このブログは、数年前にN高等学校を卒業し株式会社 Armoris にやってきたアルバイト Kaepi が書いています。
あるもりすぶろぐの内容は個人の意見です。
概要
- CTFとは?
Capture The Flagの頭文字を取ったもので、旗取りゲームのことです。
サイバーセキュリティの分野では、Flagと呼ばれる文字列をサーバーに侵入して見つけ出したり、渡されたデータを解析して特定する競技のことを指します。
Write Up
目次
- 6FA
- Look into a photo & JPG as key
6FA
htmlに埋め込まれたjavascriptのソースコードからPINを推定する問題
6桁のPINが6個あり、全部一致するとFlagが表示される
Key
var key = 2 * 72467 * 2; var keys = (key + String(1 << 23)).split(8);
keyは普通に計算して289868
になる
keysはkeyに1を23ビット左にシフトした数を足して8でsplitした配列になっている
['2', '9', '6','', '3', '', '60', '']
1. PIN1
check1 = p => p == keys.join(keys[3]);
keysの要素をjoin()でつなげただけなので、console.log(keys.join(keys[3]));
とするとPIN1がわかる。
答えは296360
となる
2. PIN2
check2 = p => p * 7 + keys[7] == keys[1].repeat(keys[2]);
keysを数字に置き換えてわかりやすくする
check2 = p => p * 7 + '' == 9.repeat(6);
こうするとp = 999999/7
にして計算することができる
なので答えは142857
3. PIN3
check3 = p => p ** 3 - p ** 2 + key * p == 3.01781152450557e+16;
keyや指数表記を整数になおしてわかりやすくする
check3 = p => p ** 3 - p ** 2 + 289868 * p == 30178115245055700;
更に数式になおして解く
p^3-p^2+289868p=30178115245055700
- 両辺から30178115245055700を引く
p^3-p^2+289868p-30178115245055700=0
- 左辺を因数分解して2個の方程式に分ける
p-311337=0, p^2+311336p+96930706100=0
- 数学的にはまだ解が出ていませんが、
p-311337=0
からp=311337
ということがわかる
なので答えは311337
4. PIN4
check4 = p => Number(p).toString(6 * 6) == "ctf" + keys[4] + keys[5];
keysを数字になおす
check4 = p => Number(p).toString(36) == "ctf" + '3' + ``;
toString()に引数を渡すと他の基数に変換してくれるので、36進数でctf3
になる10進数が答えになる
なので答えは597999
5. PIN5
p.split("").reverse().join("") == String(keys[0] ** (keys[0] + keys[0] ** keys[0])).substr(-6);
keysを数字になおす
p.split("").reverse().join("") == String(2 ** (2 + 2 ** 2)).substr(-6);
右辺を計算すると777216
になる
左辺ではpを一文字づつ分割してから配列にしてreverse().join()をしているので、右辺を右から読んだ数字になる
答えは612777
6. PIN6
check6 = function(p){ var x = []; for(var i = 2; i <= keys.slice(6).join(6); i++) if(!x[i]){ for(var j = 2 * i; j <= [6, 6].join(6) - keys[6]; j += i) x[j] = 1; p /= (i % 100 == 10 + 1) ? i : 1; } return p == 1; }
読みやすいように整形してみる
check6 = function(p){ var x = []; for(var i = 2; i <= 606; i++){ if(!x[i])){ // 1 for(var j = 2 * i; j <= 606; j+=i){ x[j] = 1; // 2 } if (i % 100 == 11) { // 3 console.log(i); p /= i; } else { p /= 1; } } } return p == 1; // 4 }
pがわからなくても手に入る情報をまとめる
- 606までの素数がif文を通る
- 配列xのj番目に1を入れる
- iを100で割った余り(剰余)が11だったら
p/=i
、違ったらp/=1
をする。(除算代入) - 入力されたpが3.の式で1になったらtrueを返す
この関数は受け取った数字が何回か割って1になるとtrueを返すので、素因数分解を使っていそうなことがわかる
なので3.のif文を通れる数をconsole.log(i);
などで確認して全部かけると答えがわかる
答えは721831
おまけ
ちなみに総当りでも答えはわかる
for (let i = 111111; i < 999999; i++) { if (check1(i.toString())) console.log("1: "+i) if (check2(i.toString())) console.log("2: "+i) if (check3(i.toString())) console.log("3: "+i) if (check4(i.toString())) console.log("4: "+i) if (check5(i.toString())) console.log("5: "+i) if (check6(i.toString())) console.log("6: "+i) }
JPG as key & Look into a photo
1枚の画像に隠されたFlagを見つける問題
- JPG as Key github.com
- Look into a photo github.com
環境
- Kali-Linux-2021.1
大まかな流れ
画像に情報を埋め込む手段はいくつかあるので、それぞれ試してみる
- exif情報
本来の用途は撮影したカメラの情報などを保存しておくための機能
exiftool xxx.png
などで確認できる - stringsコマンド
バイナリファイルなどから表示可能な文字列を表示するstrings xxx.png
などで確認できる - binwalkコマンド
埋め込まれているファイルを確認したり取り出す事ができるbinwalk xxx.png
などで確認できる
Look into a hoto
Flagはexiftoolとstrings両方で見つけることができた
Image DescriptionのほうはBase64でエンコードされていそうなのでデコードする
┌──(kali㉿kali)-[~/Desktop] └─$ exiftool q2.jpg Image Description : aGtjZXJ0MjB7ZG9jN29yX3MzaWRfbjlfbWVkaTZpbmVfbmU1ZH0= ┌──(kali㉿kali)-[~/Desktop] └─$ echo 'aGtjZXJ0MjB7ZG9jN29yX3MzaWRfbjlfbWVkaTZpbmVfbmU1ZH0=' > exif.txt ┌──(kali㉿kali)-[~/Desktop] └─$ base64 -d exif.txt hkcert20{doc7or_s3id_n9_medi6ine_ne5d}
stringsではそのままFlagが出た
┌──(kali㉿kali)-[~/Desktop] └─$ strings q2.jpg hkcert20{doc7or_s3id_n9_medi6ine_ne5d}
JPG as key
こちらはexifとstringsではFlagは見つけられなかったのでbinwalkで見てみると、画像内にパスワード付きのzipファイルが埋め込まれていることがbinwalkによってわかった。
┌──(kali㉿kali)-[~/Desktop] └─$ binwalk left_exit.jpg DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 JPEG image data, JFIF standard 1.01 30 0x1E TIFF image data, big-endian, offset of first image directory: 8 57895 0xE227 Zip archive data, encrypted at least v2.0 to extract, compressed size: 3007, uncompressed size: 3048, name: flag.png 60940 0xEE0C Zip archive data, encrypted at least v2.0 to extract, compressed size: 51376, uncompressed size: 51405, name: left_exit.jpg 112544 0x1B7A0 End of Zip archive, footer length: 22
このzipファイルにはダウンロードしてきた画像(left_exit.jpg)と同じものが入っているので、 既知平文攻撃というものが使える
既知平文攻撃とは、暗号化されたファイルの中身の一つと同じものを用意できれば、そのファイルを復号できるというもの
今回はpkcrackというツールを使って復号する
- インストール
$ wget http://www.unix-ag.uni-kl.de/~conrad/krypto/pkcrack/pkcrack-1.2.2.tar.gz $ tar xzvf pkcrack-1.2.2.tar.gz $ cd pkcrack-1.2.2/src $ make
- 必要なファイルを用意する
$ binwalk left_exit.jpg --dd='.* $ binwalk ./left_exit.jpg -o 0 -l 51405 --dd='.*''
一行目では暗号化されたzipを、二行目ではzipが埋め込まれていないleft_exit.jpg単体を取り出している。
2行目で生成されたフォルダーに移動して
$ 7z a left_exit.zip left_exit.jpg
暗号化されていないzipファイルを用意する。
- パスワード付きのzipを解凍する
pkcrack -C 暗号化されたzip -c left_exit.jpg -P left_exit.zip -p left_exit.jpg -d flag.zip
-C 暗号化されたzip
-c 暗号化されたzip内で平文のわかっているファイル
-P -cで指定したファイルをパスワードなしで圧縮したファイル
-p 平文のファイル
-d 出力先
解凍して得られたflag.pngはQRコードになっており、スマホなどで読み込むと
hkcert20{n0w_y0u_can_crack_z1p}
Flagを見つけることができた。
まとめ
今回はソースコードから機密情報などを抜き出すReverse Enginneringと、ファイルに隠された情報を見つけ出すForensicsの問題を解いてみました。 CTFには他にも暗号を解読するCryptographyや、脆弱性を突いてFlagを入手するExploitationなどさまざまな分野の問題があるので得意な分野の問題を解いてみたり、まだ知らない分野の問題に触れてみると面白いかもしれません。