angstromctf 2019 WriteUp
はじめに
angstromctfというワードがtwitterで流れてきたのでその勢いで登録しました。初心者にも解ける問題があるよって言われたので、、、ctfの勉強なんてしようと思っててずっとしてこなかった感じなので、これを機に始めようかななんて思っています。なので、このWriteupは初心者がたまたま解けた問題を乗っけているだけなので詳しいことを知りたい方は別の方のページに飛んでくださいねっ!
REV
One Bite
ctfのサーバに実行ファイルがあるのでその対話に答えてフラグ取得するやつ。elfファイルをもらえるので解析します。radare2
を使いました。
・1つ目の入力はstrcmp
で比較されている文字列okrrrrrrr
。
・2つ目は足して0x88
(136)、かけて0xec7
(3783)、になる2つの数字の小さい順39
と97
。
actf{okrrrrrrr_39_97}
MISC
The Mueller Report
pdf
string target_file.pdf | grep actf
actf{no0o0o0_col1l1l1luuuusiioooon}
Blank Paper
firefoxでそのままファイルを開いたら、普通に開けました。著者の部分にフラグがかいてあります。
actf{knot_very_interesting}
Paper Bin
.dat
ファイルが入手できます。ストーリー仕立てみたいになっていて、先ほどのpdfファイルが消えたからリカバリしてくれみたいな感じです。GUIからダブルクリックでPDFは開けるのですが、著者の部分は空欄です。hexdump -C target.dat
で一度開いてみると先頭からしばらく00で埋まっていたので、データの一部分ごっそり抜いてきたみたいなファイルかと。
https://qiita.com/forestsource/items/15933888466ba9c3f048
ファイル抽出してみようと思いforemost
で抜いてみると20個PDFファイルが出てきました。しかしstrings
で"actf"をgrep
回してみたけど見つからず..(これで見つかるなら元ファイルにgrep
かけただけで見つかるはずだし..)
foremost
の出力ファイルがあるのでそれをみると、411KBの若干他より重いファイルと、コメントがついたファイルに当たりをつけて開いてみると、後者の著者欄にフラグがありました。
actf{proof_by_triviality}
Paper Trail
pcapng
ファイルが入手できるので、TCPStream
をFollow. 「ランダムに生成するよ:(」って言ってますが、辿ってみるとa
,c
,t
,f
となるのでそのまま追って行きました。
actf{fake_math_papers}
WEB
No Sequels
以下のフォームを通す。最初はJWT
かなと思っていたのですが、MongoDB
でした。
router.post('/login', verifyJwt, function (req, res) { // monk instance var db = req.db; var user = req.body.username; var pass = req.body.password; if (!user || !pass){ res.send("One or more fields were not provided."); } var query = { username: user, password: pass } db.collection('users').findOne(query, function (err, user) { if (!user){ res.send("Wrong username or password"); return } res.cookie('token', jwt.sign({name: user.username, authenticated: true}, secret)); res.redirect("/site"); }); });
Burp
をかませて、jsonを送信します。
- Content-Type: application/x-www-form-urlencoded + Content-Type: application/json - username=hoge&password=hoge + { + "username" : {"$gt": ""}, + "password" : {"$gt": ""} +}
ネットだとapplication/x-www-form-urlencoded
でのPoCが多いですが、一度パラメータの存在を確認しているので、username[$ne]=
のような事はできませんでした。
actf{no_sql_doesn't_mean_no_vuln}
CRYPTO
Classy Cipher
暗号苦手なので簡単ですが書きます。
問題文
from secret import flag, shift def encrypt(d, s): e = '' for c in d: e += chr((ord(c)+s) % 0xff) return e assert encrypt(flag, shift) == ':<M?TLH8<A:KFBG@V'
ord()
は文字を単語に、chr()
は数字を文字に変換します。なので、読み込んできているshift
の値が分かれば、比較している文字列を復号できそうです。
shift = 0 for i in range(257): e = '' e = chr((ord('a')+i) % 0xff) if (e==':'): shift = i l = ':<M?TLH8<A:KFBG@V' e = '' for c in l: e += chr((ord(c) -shift) % 0xff ) print(e)
python
のfor
文がわからなかった。。
actf{so_charming}
Really Secure Algorithm
RSA
は相変わらず苦手ですが、過去のスクリプトを引っ張ってきてそのまま利用しました。
#python2 def exgcd(m, n): if n>0: y,x,d = exgcd(n, m%n) return x, y-m/n*x, d else: return 1, 0, m def n_module(_p,_q): return _p*_q E = 65537 C = 7022848098469230958320047471938217952907600532361296142412318653611729265921488278588086423574875352145477376594391159805651080223698576708934993951618464460109422377329972737876060167903857613763294932326619266281725900497427458047861973153012506595691389361443123047595975834017549312356282859235890330349 p = 8337989838551614633430029371803892077156162494012474856684174381868510024755832450406936717727195184311114937042673575494843631977970586746618123352329889 q = 7755060911995462151580541927524289685569492828780752345560845093073545403776129013139174889414744570087561926915046519199304042166351530778365529171009493 N = n_module(p,q) d = exgcd(E, (p-1)*(q-1))[0] % ((p-1)*(q-1)) P = pow(C, d, N) print ("%x"%P).decode("hex")
actf{really_securent_algorithm}
Half and Half
解けたのですが正攻法ではないと思うので詳しくは書きません...
from secret import flag def xor(x, y): o = '' for i in range(len(x)): o += chr(ord(x[i])^ord(y[i])) return o assert len(flag) % 2 == 0 half = len(flag)//2 milk = flag[:half] cream = flag[half:] assert xor(milk, cream) == '\x15\x02\x07\x12\x1e\x100\x01\t\n\x01"'
フラグ文字列を半分に分けて1文字ずつ取り出してXOR
してます。先頭の文字列と末尾はわかっているので、actf{
と_taste
と}
がわかります。あとは総当たりかなと思ったのですが、組み合わせパターン多すぎて諦めました。問題文がMm, coffee. Best served with half and half!
だったので、coffee
かなと決め打ちでやってみたら当たりました。下は最後にフラグを出したコード。ちゃんとした答えが知りたい。
targets = '\x15\x02\x07\x12\x1e\x100\x01\t\n\x01"' # 全部で24文字 # answer = 'actf{000000}' # e = '' # for i in range(len(targets)): # e += chr(ord(targets[i])^ord(answer[i])) # print(e) => "taste 19:1_" x = 'actf{coffee_' mid11_16 = '_taste' e = '' for i in range(len(targets)): e+= chr(ord(targets[i])^ord(x[i])) print(x + e)
actf{coffee_tastes_good}
最後に
いくつか省略していますが、簡単な問題なので。結果は 359/1570位となりました。意外と上位に感じるかもですが、上の方は桁が違うので全然上位ではないです。ひとまずweb問に強くなりたいので頑張ろうと思います。以上。