Seccon Beginners CTF 2019 writeup
まえがき
ひきこもってくろうぃずやるつもりができなくなったのでさんかしたよ
どれぐらいがんばったか
1220Pt 84位でした。まあまあえらい
ときかた
[warmup] Ramen
「'」をsearchに投げるとエラーが出るので、SQLインジェクションができると予想
「1' UNION SELECT TABLE_NAME,TABLE_SCHEMA FROM INFORMATION_SCHEMA.TABLES -- 」とか投げてデータベース内の情報を読み取ると、flagというテーブルがあることがわかる。
最後に「1' UNION SELECT flag,NULL FROM flag -- 」を投げるとフラグが出てくるよ。
katsudon
base64っぽい文字列があるのでdecodeする。おわり。
[warmup] Seccompare
objdump -D seccompare
するとmain関数にそれっぽいmovbがいっぱいあるので、そのまま文字に直していけばおわり。
Leakage
とりあえずobjdump
4005ffで文字列の長さが34文字かチェックする。フラグの長さがわかる。
とりあえず適当にaを34文字入れて、プログラムの動きをgdbでみてみる。
convert関数の戻り値と、入力文字を比較している場所がある。(0x400643)
gdbで戻り値を確認する。
0x63、つまり「c」が出てくる。
set $rax=0x63
でRAXをその都度合わせつつ、最後の実行までフラグを抜き取る。
So Tired
base64->deflate->base64->deflate...になっている。 面倒なのでNodeJSでちょちょちのちょいする。
const fs = require('fs'); const zlib = require('zlib'); var decoded = fs.readFileSync('base64data','utf8'); decoded = new Buffer(decoded,'base64'); var inflated; try{ while(true){ inflated = zlib.inflateSync(decoded); console.log('Inflate OK'); decoded = new Buffer(inflated.toString('utf8'),'base64'); console.log('Decode OK'); } }catch(e){ console.log(e); console.log(inflated.toString('utf8')); console.log(decoded.toString('utf8')); }
Party
なにがパーティーだよ
outputは[(party:val)]の配列形式で記述されている。
val配列はparty配列にx=>f(x,coeff)を適用した値である。
coeffの1つ目の値は、常にsecretである。
つまり、
output[0] = (p , v) = (p , f(p,coeff) )
である。
f関数の実装は次のようになっている。
def f(x, coeff): y = 0 for i in range(len(coeff)): y += coeff[i] * pow(x, i) return y
読み解くと
f(x,coeff) = coeff[0] * x⁰ + coeff[1] * x¹ + coeff[2] * x² + coeff[3] * x³ + ... + coeff[N] * xⁿ
である。
これは、coeffを桁の値としたx進数の数値を作り出しているとも読み取れる。
ここで、coeff[0] = secret なので、f(p,coeff)をp進数としてみた時の1桁目の値がsecretになる。
N進数の1桁目はNで割った余りを求めればいいので、v % p を計算すればよい。
from Crypto.Util.number import long_to_bytes party = # いっぱい val = # たくさん val = val % party print(long_to_bytes(val))
[warmup] Welcome
若者のIRC離れ
containers
お手元のバイナリエディタで開くと、ところどころにPNGのヘッダがある。
それぞれで抜き出してやるとフラグが書いた画像が出てくる。
const fs = require('fs'); const bsplit = require('buffer-split'); var txt = fs.readFileSync('./container'); var arr = bsplit(txt,Buffer.from('PNG')) arr.map((d,i)=>{ fs.writeFileSync('./out/'+i+'.png',Buffer.concat([Buffer.from([0x89]),Buffer.from('PNG'),d])); })
Dump
fileコマンドで調べるとtcpdumpファイルだということがわかる。
WireSharkで開き、HTTPで絞りこむと、webshellというページにシェルコマンドを投げているのがわかる。
「hexdump -e '16/1 "%02.3o " "\n"' /home/ctf4b/flag」というコマンドの応答を見ると、hexdumpした結果が返されている。
1Byteを8進数3桁で表しているので、気を付けながら複合していく。
const fs = require('fs'); var txt = fs.readFileSync('./hdump.txt','utf8'); // txt = `037 213 010 000 012 325 251 134 000 003 354 375 007 124 023 133 // 327 007 214 117 350 115 272 110 047 012 212 122 223 320 022 252` var line = txt.split('\n'); var arr = []; line.forEach(t=>{ t.split(' ').forEach(n=>{ arr.push(parseInt(n,8)); }) }) var buff = Buffer.from(arr) fs.writeFileSync('out',buff);
複合すると、gzip圧縮されたファイルができるので、解答する。
中の画像にフラグが書かれている。
Sliding puzzle
スライドパズルを解く問題、昔Wiiに画像からパズル作るゲームあったよね。
こんな便利なプログラムがあるのでありがたく使う。
const net = require('net'); const client = net.Socket(); const Grid = require('./app/js/models/grid'); const Solver = require('./app/js/models/solver'); const MessageQueue = []; var mesCallback = null; const ArrowNumber = { UP:0, RIGHT:1, DOWN:2, LEFT:3 } function mes(buff){ buff = buff.toString('utf8'); if(mesCallback){ mesCallback(buff); mesCallback = null; }else{ MessageQueue.push(buff); } } async function WaitMessage(){ if(MessageQueue.length){ return MessageQueue.pop(); }else{ return new Promise(r=>{ mesCallback = r; }) } } function parseGrid(text){ var arr = text.replace(/-|\s/g,'').replace(/\|\|/g,'|').split('|').map(Number); arr.pop(); arr.shift(); arr = arr.map(n=>n == 0 ? '' : n); return new Grid(arr, arr.findIndex(d=>d===''), ['',...[...Array(8).keys()].map(d=>d+1)]); } client.connect('24912','133.242.50.201',async ()=>{ client.on('data',mes); while(true){ var message = await WaitMessage(); console.log(message) var grid = parseGrid(message); var solver = new Solver(grid); console.log(grid) var solution = solver.solve(); var ret = solution.map(d=>ArrowNumber[d]).join(); console.log(ret) client.write(ret); } })
こういう目標がはっきりしてる問題は楽ぴぃ
あとがき
pwnはむり、むずい