Tokyo Westerns CTF 3rd 2017 WriteUp
久しぶりにCTFに参加した。(これは若干嘘で、katagaitai勉強会でXSS千本ノックをしたり、SANS NETWARS トーナメント 2017に参加したりしていた)
Harekazeで出て、940ptsで33位だった。 僕はrevのwarmup問題のrev_rev_revだけ解いた。
rev_rev_rev
読むと
、fgets()
で入力をとったあとに、入力文字列を4つの関数で処理して、あるバイト列と比較していることがわかる。4つの関数は順に、
- 改行文字を
'\0'
に(chomp的なやつ) - 文字列を逆順に(reverse的なやつ)
- 各文字cに対して下の3行を実行する。実は、最初の
<< 1
はadd eax, eax
で(c & 0x55)
の結果を自身に足していたんだけれど、これは多分最適化された結果で、下2行の雰囲気を見ると元は<< 1
だと思う。
c = ((c & 0x55) << 1) | ((c >> 1) & 0x55); c = ((c & 0x33) << 2) | ((c >> 2) & 0x33); c = (c << 4) | (c >> 4);
- 各文字のビットを反転する。
となっている。手動デコンパイルしたのをチームに共有したあと、お腹が減ったのでシャワーを浴びてご飯を買いに行ってたら、うさぎさんが「256通り試せば行けそう」と言っていたので脳死でソルバを書いた。(一文字ずつ処理してるのでそれはそう)
以下のコードでフラグが出た。
#include <stdio.h> #include <stdlib.h> #include <string.h> const unsigned char ans[] = { 0x41,0x29,0xd9,0x65,0xa1,0xf1,0xe1,0xc9, 0x19,0x09,0x93,0x13,0xa1,0x09,0xb9,0x49, 0xb9,0x89,0xdd,0x61,0x31,0x69,0xa1,0xf1, 0x71,0x21,0x9d,0xd5,0x3d,0x15,0xd5,0x00 }; void reverse(char *str) { int len = strlen(str); char *end = str + len - 1; while (str < end) { char c = *str; *str = *end; *end = c; str++; end--; } } int main() { char buf[0x21]; int len = strlen((char *)ans); for (int i = 0; i < len; i++) { for (unsigned char chr = 0x21; chr <= 0x7e; chr++) { unsigned char c = chr; c = ((c & 0x55) << 1) | ((c >> 1) & 0x55); c = ((c & 0x33) << 2) | ((c >> 2) & 0x33); c = (c << 4) | (c >> 4); if ((~c & 0xff) == ans[i]) { buf[i] = chr; break; } } } reverse(buf); printf("%s\n", buf); return 0; }
TWCTF{qpzisyDnbmboz76oglxpzYdk}
let’s go とかも解きたかったんですが、goのバイナリは気合が足りなくて読めず…