前言
看 CTF 群里有大佬引流,说周末西北瓜大(NPU)有个 CTF 比赛,据说对萌新比较友好,于是就来看了看。
官方平台地址:http://ha1cyon-ctf.fun:666/
周六比赛刚开始,平台就被 DDoS 了,于是那时只下载了一道题目的附件就啥也没了……比赛过程中平台也屡受攻击,端口换了好几次,比如 666->777->778->777->98x,平台用动态端口还是第一次见呢 23333。
结果比赛时间一直拖到了周二晚上,题目还越来越多,噢,是不会的题目越来越多了!
随便写点 Writeup 好了,主要是会做的部分吧,顺便记录了一下做题的体会啦。
(后面再看心情会不会按照大佬们的 WP 复现一下
Misc
HappyCheckInVerification
压缩包中的 endLocator 被改到最前面了,挪回去。然后把伪加密去掉。修改如下面红色部分所示。
解压出来一个是黑人抬棺的视频(真的有啊。。),另一个是一个二维码。
拉到 PS 里补上三个角,得到下面这图。
扫码得到:
?flag{this_is_not_flag}三曳所諳陀怯耶南夜缽得醯怯勝數不知喝盧瑟侄盡遠故隸怯薩不娑羯涅冥伊盧耶諳提度奢道盧冥以朋罰所即栗諳蒙集皤夷夜集諳利顛呐寫無怯依奢竟#¥#%E68BBFE4BD9BE68B89E6A0BCE79A84E5A7BFE58ABFE59CA8E69C80E5908E32333333||254333254242254338254342254231254338254345254432254238254643254236254145254239254441254437254234254232254131254236254245253244253244254343254438254330254341254336254435...sadwq#asdsadasf faf$use$dasdasdafafa_$ba##se64$
第一部分
三曳所諳陀怯耶南夜缽得醯怯勝數不知喝盧瑟侄盡遠故隸怯薩不娑羯涅冥伊盧耶諳提度奢道盧冥以朋罰所即栗諳蒙集皤夷夜集諳利顛呐寫無怯依奢竟
这一段扔去佛曰,得到:
说了这不是佛拉格,你还来转?给爷爪巴
佛拉格 flag 可还行…看来不是了。
中间一段
E68BBFE4BD9BE68B89E6A0BCE79A84E5A7BFE58ABFE59CA8E69C80E5908E32333333
拿去 base16 一下得到:
拿佛拉格的姿势在最后2333
下一部分
254333254242254338254342254231254338254345254432254238254643254236254145254239254441254437254234254232254131254236254245253244253244254343254438254330254341254336254435
base16 得到:
%C3%BB%C8%CB%B1%C8%CE%D2%B8%FC
%B6%AE%B9%DA%D7%B4%B2%A1%B6%BE
%2D%2D%CC%D8%C0%CA%C6%D5
看上去是 urlencode,解码得到:
(这里气死我了,居然用的 gb2312 编码而不是 UTF-8,我以为假的半天解不出来,虽然的确没啥用…
没人比我更懂冠状病毒–特朗普
后面这部分没看明白,但感觉是提示了 use base64.
另外,发现黑人抬棺视频里又出现了熟悉的拨号声,就是之前在XCTF高校战“疫”里碰到的 DTMF 信号。
于是把视频导出了音频,然后拖到 Audacity 里,查看频谱图,提取出带有拨号声的片段,并限制频率范围,得到下面的图。
1209 Hz | 1336 Hz | 1477 Hz | 1633 Hz | |
---|---|---|---|---|
697 Hz | 1 | 2 | 3 | A |
770 Hz | 4 | 5 | 6 | B |
852 Hz | 7 | 8 | 9 | C |
941 Hz | * | 0 | # | D |
对照表格得到 418070885
。(可能有误,应该是个手机号码,可能漏了几位
(是 13418070885
base64 -> NDE4MDcwODg1
MTM0MTgwNzA4ODU=
套上flag,flag{nde4mdcwodg1}
发现不对!!!!! (然后做不下去了嘤嘤嘤
赛后找到了一个软件可以分析 DTMF 信号,就是 **
dtmf2num.exe
*,在这里可以下载。这里是它 sourceforge 的项目地址。(好古老一个软件了*不过这题要用软件的话需要截取对应的片段才行,毕竟 BGM 太杂了而且频率信号比较有规律……
By the way,抛开题目来说,这个 BGM 就属于电音嘛,就一堆有规律的频率信号的组合唉,还带有连续调频。。
后面看了大佬的 WP,发现需要把 b64encode 后的结果发到西北瓜大信安协会的公众号(NWPUSEC)(居然这样引流!),得到一个音频信号,是无线电传输的图像,解码得到的图片里就有 flag……
(真想不出来,啊是无线电大佬!Misc 真的杂。
抽象带师
NPUCTF{欢迎来到西北工业大学CTF比赛世界上最简单的比赛}
您也是抽象带师?
再也不信什么 Easy/(Real) Ez/Baby/Basic/Not Hard/… 都是假的假的。
parts
好几个parts,zde0, zde1, zfr0, …
看文件头是一堆压缩包,解出来有个 hint
Here's the hint:
33 * 33 = 1089
And everything is inside the image
还有一张图,BV1kx411F7Fn.png
看来 flag 在图片里,不过 33*33 没看明白。
foremost 提取不出来,看 Hex 文件是有点问题。
图片文件名看上去像是 B站的 BV 号,上去看了一下没找到什么线索……
吃了它
may be hint.txt
提示
emmmmm...
something important was hidden in secret, but I can't find it!
lookatme.txt
下面有一段莫名奇妙的空白字符。不清楚啥玩意了。
secret
文件头是 MPE1
(4D 50 45 31),搜了一下没找到相关的文件格式呢。
蹲 WP。
Web
查源码
终于看到有送分题了!
就是查源码完事。
F12 禁掉了,用 Ctrl + Shift + C
或者点浏览器的 Web 开发者 之类的就行。
Crypto
Classical_Cipher
key.txt
中提示:
解密后的flag请用flag{}包裹
压缩包密码:gsv_pvb_rh_zgyzhs
对应明文: ***_key_**_******
看了一下,不是凯撒。于是丢到 quipqiup 去解密,已知 pvb=key。
根据得到的答案,大概形式是 the_key_is_??????,后面这个不大对,于是改变 clues 为 pvb=key rh=is gs=th
,得到合理的解为 the_key_is_atbash
。
噢,赛后发现这是
atbash
编码(埃特巴什码),一种古典的密码。密文就是字母表反过来对应位置的字母,即密文和明文字母的对应位置之和为27.
常文:A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
密文:Z Y X W V U T S R Q P O N M L K J I H G F E D C B A
拿这个密码去解压 flag.zip
,得到一张图片。
又是抽象带师。有一部分是猪圈密码的变种,见下图。
C??SSIC??C??E
剩下的突然想到是字符形状的字体了,联想题目 Classical Cipher,应该是 classical。
找了个识别字体的网站,比如这个,然后对应一波发现真的有!
在 Egypt0 Regular 里没找到,倒是在 ROSETTA STONE Regular 里找到了。
于是就是 CLASSICALCODE
(其实对应上D就猜到是code
了)。flag{CLASSICALCODE}
交上去发现不对,要换成小写。
flag{classicalcode}
原来这是古埃及象形文字…
更多密码可以看这篇文章:http://www.tuicool.com/articles/2E3INnm
这是什么觅🐎
2020年4月
F1 W1 S22 S21 T12 S11 W1 S13
是日历密码唉!(真会玩呢
3 1 12 5 14 4 1 18
l=[3,1,12,5,14,4,1,18]
s=''
for i in l:
s+=chr(ord('A')+i-1)
print(s)
得到 CALENDAR
flag{calendar}
日历密码原则:
(1)1—26代表a—z26个英文字母;(2)M,T1,W,T2,F,S1,S2分别代表周一到周日七天(英文首字母代替,1,2为了有别,也人为增加密度);(3)密钥即密码表
以2007年11月份的日历为密码表,我们来加密这个单词:dictionary
第一步,用数字代替明文中的字母,即D I C T I O N A R Y;
4 9 3 20 9 15 14 1 18 25
第二步,写密文。
方法:例如单词首字母D用4代替,则在日历中找到4号,发现是本月第一个星期日,所以用S21表示;又如第七个字母N用数字14代表,找到14号,发现是本月第二个星期三,用W2代表。如此类推,得到密文如下:
S21 F2 S11 T13 F2 T23 W2 T21 S23 S24此类密码的解法如下:
(1)首先要知道密钥,即密码表;
(2)其次分解密码中的星期 i,即变成星期+数字的形式;
(3)去寻找对应的是第几个出现的星期 i,对应日期;
(4)对应字母,练成单词,短语或句子。
认清形势,建立信心
题目如下,看上去就是 RSA 之类的吧。
from Crypto.Util.number import *
from gmpy2 import *
from secret import flag
p = getPrime(25)
e = # Hidden
q = getPrime(25)
n = p * q
m = bytes_to_long(flag.strip(b"npuctf{").strip(b"}"))
c = pow(m, e, n)
print(c)
print(pow(2, e, n))
print(pow(4, e, n))
print(pow(8, e, n))
'''
169169912654178
128509160179202
518818742414340
358553002064450
'''
这次去看了一些 RSA 的知识,然而不大明白这些加密算法,更不了解相关的解密算法,还没有 OI 基础,于是题目看起来挺简单的然而还是不大会解 emmm((
(Crypto
模块都不大熟有哪些现成方法,gmpy2
模块装了半天还没装好。。
题目应该叫 认清形势,放弃幻想
才对吧。
Reverse
machine(不记得题目了
这题是个 Java 写的应用,拿去 Java Decompiler 反编译了一下,得到:
虽然也没学过 Java,但大概意思还是能看个大概的。
public class Gui
extends Frame
{
public void c()
{
JFrame f = new JFrame("gkd");
f.setBounds(400, 250, 600, 450);
f.setLayout(null);
final Container j = f.getContentPane();
JButton c = new JButton("奥里给");
final JTextField b = new JTextField(20);
final JLabel l = new JLabel("");
JLabel saying = new JLabel("团长说:180298505946947064650759");
b.addKeyListener(new KeyListener()
{
public void keyTyped(KeyEvent e)
{
int c = e.getKeyChar();
if ((c < 48) || (c > 57)) {
e.consume();
}
}
public void keyReleased(KeyEvent e) {}
public void keyPressed(KeyEvent e) {}
});
c.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
String s = b.getText();
boolean u = true;
for (int i = 0; i < s.length(); i++) {
if ((s.charAt(i) < '0') || (s.charAt(i) > '9')) {
u = false;
}
}
if ((u) && (new BigInteger("100").compareTo(new BigInteger(s)) == 1)) {
u = false;
}
if (!u)
{
l.setText("逗爷玩呢,给爷爪巴,再玩下去团长就要唱希望之花了");return;
}
Lib f = new Lib(s);
BigInteger b = f.e();
l.setText("n=" + b.toString() + ",e=65537");
j.validate();
}
});
b.setBounds(200, 120, 200, 50);
c.setBounds(250, 200, 100, 30);
l.setBounds(150, 260, 300, 50);
saying.setBounds(190, 60, 220, 30);
j.add(b);
j.add(c);
j.add(l);
j.add(saying);
f.setDefaultCloseOperation(3);
f.setVisible(true);
}
这上面的代码都是控制 GUI 的,给输入框绑定了函数,如果不是数字(’0’-‘9’)的话就销毁(输入不显示在框里)。
给 button 绑定了执行函数,首先判断输入字符是不是数字,再比较输入的数字是否 >100,如果都不成立就输出 逗爷玩呢,给爷爪巴,再玩下去团长就要唱希望之花了
。
Lib f = new Lib(s);
BigInteger b = f.e();
l.setText("n=" + b.toString() + ",e=65537");
都成立的话再用输入的数字去实例化 LIb,看上面这几行感觉就是算大整数n了,又是 RSA?
按照上面的规则输入几个数字试了试,发现程序卡死,疯狂占用 CPU 的一个核心(单线程呢)进行运算。
是在干嘛噢,下面看看 Lib 类吧。
package machine;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.Stack;
public class Lib
{
private BigInteger b;
private Map<BigInteger, Integer> m;
private static final int B = 150;
private void f()
{
BigInteger T = new BigInteger("3");
BigInteger t = new BigInteger("2");
BigInteger t1 = new BigInteger("0");
for (int i = 0; this.b.mod(t).equals(t1); i++) {
this.b = this.b.divide(t);
}
this.m.put(t, Integer.valueOf(i));
for (i = 0; this.b.mod(T).equals(t1); i++) {
this.b = this.b.divide(T);
}
this.m.put(T, Integer.valueOf(i));
}
private void s()
{
while (!this.b.equals(BigInteger.ONE))
{
BigInteger d = new BigInteger(150, new Random());
for (int i = 0; i < 3; i++) {
d = d.add(BigInteger.ONE);
}
if (this.b.mod(d).equals(BigInteger.ZERO))
{
this.b = this.b.divide(d);
for (BigInteger j = new BigInteger("5"); d.compareTo(j) == 1; j.add(BigInteger.ONE)) {
if (d.mod(j).equals(BigInteger.ZERO))
{
this.m.replace(j, Integer.valueOf(((Integer)this.m.get(j)).intValue() + 1));
j = j.subtract(BigInteger.ONE);
d = d.divide(j);
}
}
this.m.replace(d, Integer.valueOf(((Integer)this.m.get(d)).intValue() + 1));
}
}
}
public BigInteger e()
{
Set<BigInteger> p = this.m.keySet();
Stack<BigInteger> o = new Stack();
BigInteger d = BigInteger.ONE;
for (BigInteger q : p) {
o.push(q);
}
d = d.multiply((BigInteger)o.elementAt(o.size() - 1));
d = d.multiply((BigInteger)o.elementAt(o.size() - 2));
return d;
}
Lib(String num)
{
this.b = new BigInteger(num);
this.m = new HashMap();
f();
s();
}
}
看最下面的函数,首先 b 为输入的数字,m为一个 HashMap(不是很懂?
f()
函数先是不断让 b/2 直到 b mod 2 == 0,然后把这时的 2 和索引 i 放入 m;之后同理让 b/3,把 3 和索引 i 放入 m。
s()
函数……
(做到这里后面有事就没看下去了
蹲个大佬的 WP 看看。
其他题
这次还有挺多有意思的题目吧。
比如 Misc 有道 Minecraft 的题目,看截图还有红石电路的,不过倒是没人做出来罢了。
Reverse 里有个 R_E_5_E_T.exe
是用 VB 写的,神器 IDA 就直接用不了了,貌似还加了壳,给了一堆 hint 然而并不会做。
有道题 are-you-a-fan
用了一堆位运算,hint 是 NAND(数电里的?),哇呜难顶。
Crypto 里有个 EzRSA
,文件名是 difficultrsa.py
,噢暴露真相了2333。
到最后还出了 OI 的题(没玩过,再见)……目睹了问号?
大佬疯狂秒题,???
小结
这次比赛平台是用 docker 部署的 CTFd,上了动态 flag 和独立环境,从这个角度而言做题感受挺好的。只是独立环境直接绑定到了同一个域名 ha1cyon-ctf.fun 下的不同端口,不像之前见过的动态域名,可能比较容易被扫描,从而容易被攻击吧(猜的。
看了一下平台是直接用 Gunicorn 搭建的 web 服务就上公网了,没套 Nginx 之类的反代,也没加 WAF 来着。不过没怎么了解也不大清楚 Gunicorn 应对高并发的能力如何。
总体感觉这次 CTF 运维赛 题目好多啊,难度好大啊,基本没见过的套路呢。题目质量还不错,就是啥都不会,嘤嘤嘤。
虽说算是业余玩玩的,但也想好好学点东西呢。
看了大佬们的WP,膜一波。
顺便再膜一下用学生机灵活应对高并发的运维大佬。
周日还打了个虎符 CTF(2020数字中国创新大赛-虎符网络安全赛道),发现题目大都新鲜出炉的。果然爆零,题目做到自闭。。
Misc 题一堆密码题,哇呜不会做……
有道 python 逆向题disasm
,给了对字节码反编译后得到的代码(可以利用dis.dis
帮助分析),哇第一次看到了 python 的底层实现,真就和汇编差不多,感觉挺能帮助理解 Py 原理的。看了几篇文章了解了一下,然而手动逆向到自闭都没分析不完,最后就放弃了。
A Python Interpreter Written in Python
Web 题用 nodejs 伪造 PHP 可还行,然而真好,都是我不会的。
不写了不写了。
等后面有机会再来复现吧。
(溜了溜了