Tokyo Westerns/MMA CTF 2nd 2016 write-up

ちょくちょくできないなりにCTF参加してるけど、記録を残さないと自分でも忘れてしまうので。
Web系が一つもできないのはつらい。アセンブリ読むの好きといいつつPwnも全然ダメ。このあたりができればもっと楽しいのだろうなぁ。

[Misc] [Warmup] Welcome!! (10pt)

問題文に書いてあるのを入れるだけ。

[Pwn] [Warmup] judgement (50pt)

printfの第一引数に入力が渡っている。スタック上に残っているflagのポインタを読むように"%28$s"を渡してやればよい。

[PPC] [Warmup] Make a Palindrome! (20pt / 30pt)

10! = 3628800通り全部試しても3分の時間制限に間に合う。

[Crypto] [Warmup] Twin Primes (50pt)

p*qと(p+2)*(q+2)が与えられるので、p+qが求まって、解と係数の関係でpとqがわかってしまう。あとはencrypt.pyの逆の手順をたどればよい。

[Reverse] [Warmup] Reverse Box (50pt)

とりあえず動かしてみると、実行ごとに同じ入力でも出力が変わるが、一回の実行中に同じ文字には同じ出力しか出ない雰囲気。rand(3)を使っているところが初期化の一箇所だけで、しかも下位8bitしか使われない。rand(3)をLD_PRELOADでフックして256通りの値を試すと、TWCTFが問題文に書かれた出力になるのはrand(3)が214を返すとき。あとは換字表を作って変換すればよい。

[Crypto] Super Express (100pt)

ごちゃごちゃやっているけど結局入力の線形変換になるので、先頭をTWCTFとしたときの変換式を求めてデコードする。

[Crypto] Backpacker's cipher - easy mode (200pt)

pとqがわかったときにどうdecryptするか考える。mod p上でpubkeyの各要素をqで割ると、pubkeyのi番目の値は下から見てiビット目で初めて1が立つ値になる。messageをqで割ったものについて、下から順に1が立っているかどうかをチェックし、1が立っているときにpubkeyをqで割ったものを引くようにすると、DESで暗号化したビット列が得られる。
generate_keyのaの作り方から、pubkeyの最後の要素は2^1023*q%p、その一個前の要素は2^1022*q%pまたは3*2^1022*q%p。前者の場合にpが312桁の素数になってそれっぽい。2^1023の逆数を掛ければqも求まる。

[Crypto] Vigenere Cipher (200pt)

ASCIIのplain textをBase64エンコードしているので、必ず0が来るビットがある。全文についてこの性質が成り立つことを利用すると、keyの要素は繰り返し使われるので、keyの長さや範囲を絞ることができる。
この時点でkeyの長さが12、そのうち8要素はほぼ中身が確定するので、一度元の文字列らしきものを出してみると、最後のほうにflag is TWCTF{という文字列が来そうなので、残りのkeyも確定できる。

[Reverse] [PPC] Whiteout Mathmatics (200pt)

Whitespaceのプログラムを読むと、与えられた数値の間の各数について約数の和を求め、それの最大値を出力することがわかる。要は10^12までの数で約数の和が最大になる数の、その約数の和を答えればよい。
どうせそのような概念は既にあるだろうと約数のWikipediaを眺めたら、高度過剰数という概念がありOEIS経由でテーブルにたどりつけた。あとは995886571680をfactorして約数の和を求めればよい。

[PPC] Lights Out! (100pt / 300pt)

各マスを縦に、押したときに変化するマスを横にとった行列を作って、GF(2)上でAx=bを解けばよい。normalはガウス消去で十分速い。
lunaticはできていない。O(N^3)だと死んでしまうので、疎行列であることを利用して反復法で解くのかなとか考えていた。素因数分解でblock Lanczos法を使うように。

[Misc] glance (50pt)

情弱なのでWindows上でフリーソフトでGIFを分解してBMPにしたのち、BMPのフォーマットを参考にしつつ各行を順に結合して新しいBMPを吐くプログラムを書いた。もう少し楽なやり方があったかもしれない。

[Misc] ninth (100pt)

zlibでIDATの中身をinflateすると、画像データのあとにflagが書いてあった。