SECCON CTF 福岡大会の問題

SECCON CTFの筑波大会に出場させて頂けることになりました。
他チームは各所で活躍されている方々が参加されるということもあり、勝ちを狙うのは難しそうなので、チーム全員で楽しんで出場できたら良いなと思います :)

今回のCTFをきっかけにセキュリティ&プログラミングキャンプ2010に参加した友人たちと連絡を取り合うきっかけになりました。(キャンプのCTFで同じチームだった人もいます)

@ITの記事を見ていて、福岡大会でどんな問題が出ていたのか書いてあったので、解いてみました。

問:以下のファイルダンプは宇宙からの中性子線で1bitのデータが反転したものである。

0000000 1f 8b 08 08 27 2c 39 4f 02 03 7a 2e 74 78 74 00
0000020 ed da 4d 0e 83 20 10 86 e1 7d 93 de 61 d6 de ff
0000040 80 ee 9a 54 65 f8 66 18 11 93 97 55 63 f8 1d 5e
0000060 0c 45 cc 6c fb 4f b6 64 3a 74 6c e5 7e fe c2 78
0000100 f8 1d 1d d1 e5 bc 44 e3 b0 5d 25 a7 3f ad fc 7a
0000120 13 7e bb e7 28 b5 f2 fb f1 fc 7e 0c b9 c8 45 2e
0000140 72 91 3b 4d ae 13 51 a5 65 a7 f1 6e a7 42 8b e6
0000160 50 ca 9f 1c a5 94 be 4a 5a e3 2d 94 7b ce e3 c8
0000200 ca 2d 5f 65 a1 24 5e 09 dd 15 29 66 eb ae 24 e4
0000220 22 17 b9 c8 45 ee 52 72 bb 81 69 b5 29 3e d7 1b
0000240 12 6b 53 c8 d7 4e b2 5e 5c e9 b6 98 3f 1a d5 a7
0000260 e4 8a 79 c4 fe b4 e2 83 5c e4 22 17 b9 c8 9d 29
0000300 57 df 9f 8e 88 f6 f7 89 e2 e8 9d e2 e3 f5 57 ed
0000320 73 0b 4f a7 a2 71 88 ca 6d f5 27 34 d8 cb 59 ce
0000340 bd ff 42 4d 23 17 b9 c8 45 2e 72 27 cb 8d ee a4
0000360 ba 41 15 a5 cf d9 e7 96 ef dd 72 78 a3 df ac de
0000400 bb cf 15 a7 7e f0 cf 04 72 91 8b 5c e4 22 77 a6
0000420 5c f1 34 22 7a 2a 76 9f 5c 4b dd 3a 29 9c e4 72
0000440 b9 e9 e7 8b 7f 43 0b bd 00 90 8b 5c e4 22 17 b9
0000460 2b cb b5 e1 9b 32 d1 53 b1 c4 46 d5 1f 68 49 fd
0000500 13 4e c5 42 42 ad e8 7e 6e 42 ee 53 f7 73 91 8b
0000520 5c e4 22 17 b9 2b cb bd 23 bd b1 e2 1d 86 5a 0f
0000540 50 4d 3a 00 00
0000545

1bitだけ異なる正常なデータファイルを復元し、秘密の鍵を答えよ。

1f 8bなのでどう見てもgzipです。
ファイルサイズはそれ程大きくないので、総当たりで解きました。

% cat prob.txt
1f 8b 08 08 27 2c 39 4f 02 03 7a 2e 74 78 74 00
ed da 4d 0e 83 20 10 86 e1 7d 93 de 61 d6 de ff
80 ee 9a 54 65 f8 66 18 11 93 97 55 63 f8 1d 5e
0c 45 cc 6c fb 4f b6 64 3a 74 6c e5 7e fe c2 78
f8 1d 1d d1 e5 bc 44 e3 b0 5d 25 a7 3f ad fc 7a
13 7e bb e7 28 b5 f2 fb f1 fc 7e 0c b9 c8 45 2e
72 91 3b 4d ae 13 51 a5 65 a7 f1 6e a7 42 8b e6
50 ca 9f 1c a5 94 be 4a 5a e3 2d 94 7b ce e3 c8
ca 2d 5f 65 a1 24 5e 09 dd 15 29 66 eb ae 24 e4
22 17 b9 c8 45 ee 52 72 bb 81 69 b5 29 3e d7 1b
12 6b 53 c8 d7 4e b2 5e 5c e9 b6 98 3f 1a d5 a7
e4 8a 79 c4 fe b4 e2 83 5c e4 22 17 b9 c8 9d 29
57 df 9f 8e 88 f6 f7 89 e2 e8 9d e2 e3 f5 57 ed
73 0b 4f a7 a2 71 88 ca 6d f5 27 34 d8 cb 59 ce
bd ff 42 4d 23 17 b9 c8 45 2e 72 27 cb 8d ee a4
ba 41 15 a5 cf d9 e7 96 ef dd 72 78 a3 df ac de
bb cf 15 a7 7e f0 cf 04 72 91 8b 5c e4 22 77 a6
5c f1 34 22 7a 2a 76 9f 5c 4b dd 3a 29 9c e4 72
b9 e9 e7 8b 7f 43 0b bd 00 90 8b 5c e4 22 17 b9
2b cb b5 e1 9b 32 d1 53 b1 c4 46 d5 1f 68 49 fd
13 4e c5 42 42 ad e8 7e 6e 42 ee 53 f7 73 91 8b
5c e4 22 17 b9 2b cb bd 23 bd b1 e2 1d 86 5a 0f
50 4d 3a 00 00
% xxd -r -p prob.txt prob.gz
% cat xor.py
origGz = open("prob.gz", "rb").read()

byteSize = len(origGz)
bits = []
for i in range(0, 8):
	bits.append(2**i)

for byte in range(0, byteSize):
	for bit in bits:
		change = chr( ord(origGz[byte]) ^ bit )
		newGz = origGz[0:byte] + change + origGz[byte+1:]
		
		filename = "out/" + str(byte) + "_" + str(bit) + ".gz"
		f = open(filename, "wb")
		f.write(newGz)
		f.close()

% cat dec.py
import os
gzfiles = os.listdir("./out")
for gzfile in gzfiles:
	if( os.system("gzip -d " + "./out/" + gzfile) == 0 ):
		print gzfile
		break
% mkdir out
% python xor.py
% python dec.py
gzip: .....
.....(略)
47_64.gz
% file out/47_64
out/47_64: ASCII text, with very long lines, with CRLF line terminators

SECRET KEY IS "HACK THE GZIP"