2023 AIS3 Pre-exam Write Up
今年是我打AIS3 Pre-Exam的第三年,今年的目標原本只是比去年的名次好就可以了,沒想到居然打進了前10,覺得十分神奇.w.(當然比較大的可能性是大佬都跑去出題ㄌ:P)今年解出的題目分數也都比較高,去年解的題目大部分都是降到100分XD總之很驚訝自己今年可以拿到第9名,也希望自己可以持續進步!
Misc
Welcome [100]
Are you not a robot ?
FLAG Format: ^AIS3{[A-Z0-9+-*/!?-]+}$
Author: nella17
file: https://drive.google.com/file/d/1OU5R736aRgj9KLce9S4CQj0qsDA6tm2g/view?usp=sharing
這題題目給了一個pdf,每張不同大小和形狀的紙裡面各包含了1個flag的字元,只要把他們通通拼在一起即可拿到flag。要注意題目中的Regex並沒有_
,所以flag是以-
來進行連接。
FLAG: AIS3{WELCOME-TO-2023-PRE-EXAM&MY-FIRST-CTF}
Robot [100]
Are you a robot?
Note: This is NOT a reversing or pwn challenge. Don’t reverse the binary. It is for local testing only. You will actually get the flag after answering all the questions. You can practice locally by running ./robot AIS3{fake_flag} 127.0.0.1 1234
and it will run the service on localhost:1234
.
Author: toxicpie
nc chals1.ais3.org 12348
file: https://drive.google.com/file/d/1cczdP1CntYpbMrU5kD_mf3_Gv3DNYTQe/view?usp=sharing
這題用nc連進去之後會發現要在90秒內做出30道數學題,由於數字很小很容易心算,而且中間又有空格,code需要一點特判,所以我決定直接用心算解完30道數學題之後就能拿到flag。
1 | $ nc chals1.ais3.org 12348 |
FLAG: AIS3{don't_eval_unknown_code_or_pipe_curl_to_sh}
Web
Login Panel [100]
Login Panel 網站採用了隱形 reCAPTCHA 作為防護機制,以確保只有人類的使用者能夠登入 admin 的帳號。你的任務是找到一個方法來繞過 reCAPTCHA,成功登入 admin 的帳號。
你可以使用各種技術和手段來達成目標,可能需要進行一些網站分析、程式碼解讀或其他形式的攻擊。請注意,你需要遵守道德規範,不得進行任何非法或有害的行為。
當你成功登入 admin 的帳號後,你將能夠獲得 FLAG。請將 FLAG 提交至挑戰平台,以證明你的成功。
Author: Ching367436
file: https://drive.google.com/file/d/1G-VtgJFEKcfN0Xj_wRZLLfXuoxPvR3tM/view?usp=sharing
這題先看source code,可以發現在/login
的地方,變數直接被塞到SQL expression裡面,是一個典型的SQL Injection。
1 | app.post('/login', recaptcha.middleware.verify, (req, res) => { |
而目標是登入admin
,但code中說明如果我們輸入的東西與username不符,就會跳出rickroll,所以我們可以注入的地方在password
,只要使用payloadadmin' OR 1=1--
就可以直接登入。
登入之後會進入/2FA
,但從source code中可以看出,這其實沒有對/dashboard
做任何防護,所以直接跳到/dashboard
就可以得到flag了。
1 | app.post('/2fa', (req, res) => { |
FLAG: AIS3{' UNION SELECT 1, 1, 1, 1 WHERE ({condition})--}
Crypto
Fernet [100]
你所在的公司最近發生了一起駭客入侵事件,管理員發現駭客使用 Fernet 密碼學來加密了他們的敏感數據。你需要解開被加密的檔案,否則事情就大條了!
flag format : FLAG{xxx}
Auther : Richard ( dogxxx)
file: https://drive.google.com/file/d/15q0Ty6A7tWm6cPBP2UMWYz1yJcfN0tEM/view?usp=sharing
這題一樣直接看source code,可以發現他是利用Fernet來進行加密。
1 | import os |
從code裡面可以知道,他的key是利用password與salt使用PBKDF2生成,但password和salt都是已知,可以分別從source code和output中得到,因此我們可以直接造出一模一樣的key來對加密的東西進行解密。將這段code稍作修改後就能作為exploit拿來decrypt,得到flag。
1 | import base64 |
FLAG: FLAG{W3lc0m3_t0_th3_CTF_W0rld_!!_!!!_!}
2DES [484]
「2DES 」是一個刺激的「Capture the Flag」(CTF)挑戰,考驗你在解密使用 Double DES(2DES)加密的數據方面的技能。準備好進入密碼學的世界,解開這個加密訊息中隱藏的秘密。
在這個挑戰中,你將面對一個使用 2DES 加密算法保護的加密訊息。你的任務是解密這個訊息並恢復原始明文。為了做到這一點,你需要深入了解密碼學原理,並能夠運用各種技術來破解加密。
你準備好踏上這個激動人心的解密之旅,揭示這個訊息中隱藏的秘密了嗎?加入我們的「2DES 加密 CTF 挑戰」,在迷人的密碼學世界中展示你的技巧吧!
Author: Ching367436
file: https://drive.google.com/file/d/1IFZz-1Q0En15uO6MehLM35cxDMZA6Sip/view?usp=sharing
這題的題目已經很明顯地暗示這題是Double DES了,而其最常見的攻擊手法就是Meet In The Middle(MITM)中間相遇攻擊,因此可以直接利用這個弱點來進行攻擊,分別拿到key1與key2。
1 | const crypto = require('crypto') |
首先我們需要先造出一個所有key的list,在這裡我使用C++來進行IO加速。其中在解密的時候可以發現,前面4 bit因為特殊for迴圈的關係,固定會是1111,而且最後1 bit的數值1/0並不會影響到解密出來的東西,所以可以枚舉奇數就好,因此一位會產生$2^3=8$種可能,並一共會產生$8^8=16777216$種key,在可電腦窮舉的範圍內。
1 |
|
生成key.txt
之後,我針對題目所給的hint_pt
與hint
分別進行加密與解密,並且儲存到en.txt
與de.txt
兩個檔案中。
1 | const crypto = require('crypto') |
1 | const crypto = require('crypto') |
兩個分別生成到一半時因為我的電腦效能太差,且nodejs的輸出效率太慢了,所以我就把它們截斷,幸運的是在裡面找到了相同的中間密文0015f807fa38ef42050da63c7100bc0f19c299aaa0323928
,而對應到的key1是f5f1fbfff1fdf5f5
,key2則是f7f9f9fff7fbf5f5
。拿著這兩把key去對原本的flag密文做解密即可拿到flag。
1 | const crypto = require('crypto') |
FLAG: AIS3{折半枚舉}
MSB Oracle Attack [499]
We all know RSA LSB oracle, but do you know MSB oracle?
Author: toxicpie
nc chals1.ais3.org 12347
file: https://drive.google.com/file/d/15KSYACFO3m1NWoL_Yb33G-fBtzd17jvx/view?usp=sharing
先來看看source code。
1 | import os |
這題題目提到LSB oracle,可以發現與本題的想法很像,題敘從原本LSB的奇偶轉換成$\dfrac{n}{2}$,不過很快就可以發現利用大於$\dfrac{n}{2}$與小於$\dfrac{n}{2}$的條件,搭配密文輸入
$hint\times(2^{power})^e=(secret\times 2^{power})^e$
,這時解密後會出現
$secret\times 2^{power}>\dfrac{n}{2}\implies secret>\dfrac{n}{2^{power+1}}$或
$secret\times 2^{power}<\dfrac{n}{2}\implies secret<\dfrac{n}{2^{power+1}}$
兩種情況,就可以作為二分搜的條件,來限縮secret的值,最後在1500次內找到趨近真實的secret,可以直接寫二分搜的exploit拿到flag。
不過在二分搜時,因為我所使用的是整除的二分搜,因此在最後的secret上會有小於10000的誤差,這時我利用for loop窮舉來判斷加密後的結果是否與給定的hint一致,就可以確定secret的值。輸入0跳出並輸入secret後就可以拿到flag。
1 | from pwn import * |
FLAG: AIS3{O0o0oO0o0oOooooO0o0oOOO0oO0o0o_Y0u_a43_4_tru1ly_Or4c13!!@#!@#!@#!@$!@$!@}
Reverse
Simply Reverse [139]
Just reverse it!
file: https://drive.google.com/file/d/140muCIzd7q5vMZNwhL5DDLXAx6tguyHc/view?usp=sharing
這題其實算是非常常見的Reverse基本題,用IDA看一下會發現裡面有一個verify function
,encrypted
是一個已知所有值的陣列,所以只要逆向之後利用他的if判斷式直接在printable ascii之中字典爆破就可以拿到flag了,從psuedo code可以看出flag長度為34。其中*((signed int *)&v2 - 1)
是index,*(&v2 - 3)
是flag陣列,而需要要注意的是unsigned __int8
限制範圍在256,需要取mod 256才不會出錯。
直接上exploit:
1 |
|
FLAG: AIS3{0ld_Ch@1_R3V1_fr@m_AIS32016!}
Flag Sleeper [379]
Taking a nap before entering the world of AIS3 is important! A good hacker requires good sleep, and so does this flag checker.
Author: TwinkleStar03 ✨
file: https://drive.google.com/file/d/1-AkPHIHF0G9Y-3BMes2QHb1slRGeHuUo/view?usp=sharing
這題執行之後會發現他只會噴一個表情符號給你,但用IDA看不出甚麼東西,所以改用Ghidra,裡面可以發現main
函數上面的一堆數字應該是三個陣列,而下面的code雖然有rand()
,但他很明顯將iVar2
限制在0x34
之內,用這個來去取iVar1
的值,而下方又利用iVar2
作為index去將其餘兩個陣列的元素做xor,所以合理懷疑iVar1
,也就是local_358
是儲存index的陣列,而flag長度就是0x34
。
接下來,他將其他兩個陣列的數字利用iVar2
作為index來xor,所以另外兩個陣列xor應該就是flag的字元,而根據index重新排列就能得到flag。直接寫出exploit拿到flag。
1 |
|
FLAG: AIS3{c143f9818a01_Ju5t_a_s1mple_fl4g_ch3ck3r_r1gh7?}
Vivid Emotion [493]
If you failed on this, I’ll give you some lovely emojis to cheer you up! Keep going until you see the Success!
To get the flag, store your answers into a file and run flag-decryptor.py
.
There are some requirements for decryptor:
- Install python package pycryptodome
pip install pycryptodome
- To let decryptor works properly, answer_file’s content must follow the format. Please arrange your answers correctly.
- If you don’t like my decryptor, you can reverse it and rewrite it!
If you step into some problem while checking answers using the checker, Use pwntools process to send answers to program may help.
Author: TwinkleStar03 🌟
file: https://drive.google.com/file/d/10_qEMNX18pZE7o269Fy-seph-eHgnzxL/view?usp=sharing
先把這題的elf跑起來,會發現他要輸入一個secret number
,稍微逆一下就知道這個數字是333
。而在輸入333
之後,接下來需要輸入333個數字做為secret
,而很明顯可以發現這些數字的條件判斷函數存在於所有chk
開頭的區塊裡面,而這個就可以用z3 solver解決,因此寫個exploit來把數字解出來。
1 | from z3 import * |
解出來之後把它們依照index重新排列並且放到ans.txt裡面,送回flag-decryptor.py
就能夠拿到flag了。
1 | // rearrange |
1 | $ python3 flag-decryptor.py |
FLAG: AIS3{OuO_Hope_th1s_ch4l1eng3_gIve_y0u_viv1d_em0Tions!_(ฅ^・ω・^ ฅ)}
Pwn
Simply Pwn [356]
The simplest pwn
nc chals1.ais3.org 11111
file: https://drive.google.com/file/d/1XQctYAM-Ul1LKooX8ofRM51pX6P1vIQI/view?usp=sharing
這題很明顯是buffer overflow,因為read
的bytes數量(256 bytes)超過了儲存量,且有一個shellcode function
可以執行/bin/sh
,所以要讓rsp
指向他讓他跳上去。把elf跑起來之後發現過了67個bytes之後會出現一個亂碼,表示最多的儲存陣列就到67 bytes,所以接下來再蓋12 bytes把old rbp
蓋掉就可以跳到shellcode
上面了,所以一共要蓋$67+12=79$ bytes。直接寫exploit就可以拿到shell。
1 | $ ./pwn |
1 | from pwn import * |
FLAG: AIS3{5imP1e_Pwn_4_beGinn3rs!}
ManagementSystem [443]
這個系統,看起來好像有點問題…。請利用你的技能和知識,找到漏洞並利用它們吧!
flag format : FLAG{xxx}
Author : Richard ( dogxxx)
nc chals1.ais3.org 10003
file: https://drive.google.com/file/d/1mnng4xunujuw5jCK1udhEmD5fTFkdbdi/view?usp=sharing
這題其實跟第一題很像,可以發現在delete
的function裡面出現了一個gets()
誤用的buffer overflow,也有secret_function
可以開shell,不過這個delete
function要在database裡存在user
時才能使用,因此前面要先註冊一個user
,接下來才繼續執行delete
function。
1 | User *delete_user(User *head) { |
而sscanf
會將buffer裡面的數字部分存到user_index
,為了要執行到ret
,因此我們要先給定一個假數字後接上空白,之後再接上payload,這樣可以讓user_index
的檢查正常執行,最終跳到secret_function
上面。
至於要蓋掉多少,可以用gdb來看看。用gef pattern create
之後,根據前面的指示,最後在delete user的地方塞入b'123 '
+pattern,可以發現rsp
指向了aaaanaaaaaaaoaaaaaaa
,gef顯示pattern search
的offset是100,所以要塞入的pattern量就是100 bytes,直接寫個exploit就可以拿到shell了。
1 | gef➤ |
1 | from pwn import * |
FLAG: FLAG{C0n6r47ul4710n5_0n_cr4ck1n6_7h15_pr09r4m_!!_!!_!}