2021 MyFirstCTF Write Up

Albert Huang MED student | CS enthusiast

這次也參加了 AIS3 的 MyFirstCTF 競賽,裡面是一些 AIS3 的題目跟額外的 baby 友善題(結果賽中都解 baby 題 QAQ),好像蠻少人在打 MyFirstCTF 的 Write Up 的,就來整理一下吧~不過好像比較多梗題的部分(O

這次的成績:17 名 + 兩題首殺~

MISC

Cat Slayer ᶠᵃᵏᵉ | Nekogoroshi

這題跟 AIS3 Pre-exam 是一樣的題目,直接複製 XD

題目給了一行 command

1
TERM=xterm-256color ssh -p 5566 h173@quiz.ais3.org

把它拿到 Terminal 執行後可以發現他跳出了一個 Python 的執行畫面,用鍵盤可以輸入數字,輸入錯誤會鎖起來,因此可以用手動的輸入猜密碼,得到正確的密碼就可以解鎖 flag。

1
Password: 202583045529

FLAG:

1
AIS3{H1n4m1z4w4_Sh0k0gun}

[祝賀] 新垣結衣新婚快樂 發錢囉 [baby]

Bonus : First Blood

這題給了一張圖片,看起來像是 forensics,所以先用一些例如 zsteg 或 online tool 之類的工具試了一下,後來用 binwalk 試了一下發現裡面包了一個 zip 檔。

P.S. 是新垣結衣欸~

1
2
3
4
5
6
7
$ binwalk baby.png

DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 PNG image, 1200 x 675, 8-bit/color RGB, non-interlaced
179 0xB3 Zlib compressed data, best compression
1511327 0x170F9F End of Zip archive

所以用 foremost 把裡面的東西拉出來。

1
2
3
4
5
$ foremost baby.png -o baby
Processing: baby.png
|foundat=awertyjas‮qrmnk‮.pngt�w4����?�ik�
m��T�ԦZ{�ڵ�J���F�U�k�=�P����&VlAD��z�>�?��|Ϲ�x:�p?������}ߏ�k�+RS0S
*|

接下來到/baby可以發現一個00001726.zip,裡面有一張圖片,推測應該是 flag,但是 local 需要密碼解鎖,猜了幾個常用密碼跟照片名還是錯誤,所以開始找 online tool。

非常幸運的是我第一個使用的網站就讓我解開了,而且不需要密碼~

P.S. 這題應該是偽加密,但是我其實到現在還是沒搞懂它的原理是什麼 XXD

P.S. 是星野源欸~

FLAG:

1
AIS3{看好了世界,我只示範一次如何一天搶走幾億人的老婆}

結果新垣結衣跟星野源還是結婚了~

Web

Copy & Paste [baby]

這題給了一個奇怪的黑色網站,有一個 flag 按鈕,按下去之後會顯示個幾秒 flag 之後消失。但是,他的 flag 大到我只看到中間部分,沒辦法送啊?

按了 F12 之後看一下發現他好像用算的把螢幕高度 anchor 住了,所以我的螢幕不夠長就看不到完整的 flag。那有什麼方法可以讓完整的 flag 顯示出來?

後來腦洞大開把瀏覽器壓扁之後,他的 height 變小,我就可以看到完整的 flag 了!

P.S. 通靈用在這裡是正確的(O

FLAG:

1
AIS3{Re33Ee3E33e3eEEe3eE3El11I1l1i11y_lo0O0oo00o00oOC0OOoo00o0Oo0O0o0Ooo0Oo0oo0Oo0OOOO000OO0ng_f1aG}

P.S. 所以我還是不知道怎麼複製貼上 w 而且這個 flag 我打好久 QQ
不過還好手打,賽後用 OCR 跑出來的是錯的啦= =

Crypto

Judgement [baby]

這題的題目很簡潔,只有一個Judgement.py跟一個output.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
from hashlib import sha256
import string
flag = 'AIS3{THIS_IS_A_FAKE_FLAG}'

cand = string.ascii_letters + string.digits + '_{}'
charset = string.printable[:93]

enc = ''
for c in flag:
assert(c in cand)
enc += charset[int(sha256(c.encode()).hexdigest(), 16) % len(charset)]

print(enc)
1
)g;Fk@>2g;2V2J?d5G3_8V2<dR2i5GZ@<?2)g\j_2V&?2;@[F@ek2_3"=k&;2)\F2J9LL4g[W2"[2<)RZ23@<?2elFZ?2=@jZ23@=F2Yi52;lL5Vj2J?2J8\e@eW23e2lF330

第一個想法是逆推,但是它裡面用了 sha256 加密,所以也沒辦法直接逆推,只好用順向搜尋的方式解題。

但因為他取 sha256 加密後的某個位置數字的對應字元,逆推後並不只一種可能性,所以我們用不同的 ascii 碼範圍搜尋可能字元後,因為題目提及 flag 符合文法與 leet 語法,再用手動來把 flag 拼出來。

先把爆搜的程式寫出來。

1
2
3
4
5
6
7
8
9
10
11
12
from hashlib import sha256
import string

g=")g;Fk@>2g;2V2J?d5G3_8V2<dR2i5GZ@<?2)g\j_2V&?2;@[F@ek2_3\"=k&;2)\F2J9LL4g[W2\"[2<)RZ23@<?2elFZ?2=@jZ23@=F2Yi52;lL5Vj2J?2J8\e@eW23e2lF330"
s="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&'()*+,-./:;<=>?@[\]^_`{|}"
# s=cand

for i in range(133):
for j in range(127,64,-1): # range(65,128), range(48,128)
if s[int(sha256(chr(j).encode()).hexdigest(),16)%93]==g[i]:
print(chr(j),end='')
break

跑出了三種結果:

1
2
3
AISv{iX_IS_M_BeautqM_day_~utside_AIr|q_MRe_SiNvin{_qow{RS_Arv_BlOOmIN_oN_dAys_ide_nhvse_wi|s_iwv_Y~u_ShOuM|_Be_Brnin_n_hv}
AISGEiT_IS_L_BeaZtFUL_Kay_~ZtsiKe_AIrDF_LRe_SiNGinE_FoQERS_ArG_BlOOmIN_oN_KAys_iKe_nhGse_QiDs_iQG_Y~Z_ShOZLD_Be_BUrnin_n_hG}
8IS39iT_IS_4_BeaZ215=4_Kay_0Z2siKe_8IrD5_4Re_SiN3i79_51oQ9RS_8r3_BlOO@IN6_oN_K8ys_1iKe_7h3se_QiDs_1iQ3_Y0Z_ShOZ4D_Be_B=r7i76_17_h311}

剩下就是手動拼組了,不過可以確定 range(48,128)的字串長度必定為 flag 長度,因其包含了所有 flag 可能字元。

FLAG:

1
AIS3{iT_IS_4_Beaut1FUL_day_0utside_8IrD5_4Re_SiNGin9_F1owERS_Ar3_BlOOmIN6_oN_dAys_1iKe_7h3se_kiDs_1ik3_Y0u_ShOuLD_Be_BUrnin6_1n_h311}

P.S.我拼了 1.5hr 錯了 10 次才對,1t’s 4 re41 h31l…

Reverse

ⒸⓄⓋⒾⒹ-①⑨ [baby]

Bonus : First Blood

這題直接給了一個 x64 的 task.elf 檔,既然是 reverse 就直接用 IDA Pro 打開吧~

Decompile 之後先看看 main,沒有找到什麼可以用的東西,function 多到暈頭轉向,看到的東西只有YOU WIN!

不過在裡面發現了一個可疑的 functioncheck_flag_is_correct(char *),進去看看 decompile 的內容。

看起來是個判斷傳入字串是否符合條件的函數,點進 target 發現有一串數字。

看來是把這些數字拿來比對運算結果,所以我們就把條件判斷爆搜字串之後就可以拿到 flag 了。

寫個程式來把 flag 爆搜出來。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<bits/stdc++.h>
using namespace std;

int p[32]={65, 72, 81, 48, 127, 48, 49, 51, 113, 86,
98, 59, 97, 62, 114, 120, 35, 37, 96, 76,
121, 33, 35, 124, 101};

int main(){
for(int i=0;i<32;i++){
for(int j=0;;j++){
if(char(char(j)^i)==char(p[i])){
cout<<char(j);
break;
}
}
}
return 0;
}

FLAG:

1
AIS3{574y_h0m3|w34r_m45k}

P.S. 賽後發現 xor 算法可以直接算出 flag,不需要爆搜,比賽的時候沒想好繞了一圈…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<bits/stdc++.h>
using namespace std;

int p[32]={65, 72, 81, 48, 127, 48, 49, 51, 113, 86,
98, 59, 97, 62, 114, 120, 35, 37, 96, 76,
121, 33, 35, 124, 101};

int main(){
for(int i=0;i<32;i++){
cout<<char(i^p[i]);
}
cout<<endl;
return 0;
}
  • Title: 2021 MyFirstCTF Write Up
  • Author: Albert Huang
  • Created at : 2021-06-06 14:08:29
  • Updated at : 2026-06-26 14:08:16
  • Link: https://blog.albert-web.tw/2021/06/06/myfirstctf-2021/
  • License: This work is licensed under CC BY-NC-SA 4.0.