CTF Writeup SECCON 2017 » 履歴 » バージョン 1
kanata, 2025/04/13 15:19
1 | 1 | kanata | # CTF Writeup SECCON 2017 |
---|---|---|---|
2 | |||
3 | {{toc}} |
||
4 | |||
5 | # 結果&感想 |
||
6 | |||
7 | 某チームでSECCON2017に参加しました。 |
||
8 | 4問解きました。全部100点だけどな! |
||
9 | |||
10 | チームの成績なんですが、もしかしたら国内決勝行けるかもという順位! |
||
11 | 決勝行けたらめでたいね!!! |
||
12 | |||
13 | 基本的に今回は |
||
14 | |||
15 | ## こまけぇこたぁいいんだよ |
||
16 | |||
17 |  |
||
18 | |||
19 | 解けりゃぁいいんだよ!ちゃんと実装しよ?[めんどくせぇ買ってこいよゴロリ](https://goo.gl/Utc5vb) |
||
20 | というスタンスで解いていたため、はたして公開していいのかというクソコードっぷりを披露する事になります。 |
||
21 | |||
22 | # Log search (Web 100) |
||
23 | |||
24 | 問題文はアクセス先のURLだけだったかな。。 |
||
25 | |||
26 | これはなんで解けたのか、どういう趣旨だったか理解する前に解けてしまいました。 |
||
27 | |||
28 | 検索窓があるので、おもむろに flag と入力して検索 |
||
29 | |||
30 |  |
||
31 | |||
32 | 出てきたそれっぽいヤツにアクセスする。 |
||
33 | |||
34 | |||
35 | フラグ取れた。 |
||
36 | |||
37 | ``` |
||
38 | SECCON{N0SQL_1njection_for_Elasticsearch!} |
||
39 | ``` |
||
40 | |||
41 | # Simon and Speck Block Ciphers (Crypto 100) |
||
42 | |||
43 | 平文と暗号文、キーの一部が提供されています。 |
||
44 | |||
45 | ``` |
||
46 | Simon_96_64, ECB, key="SECCON{xxxx}", plain=0x6d564d37426e6e71, cipher=0xbb5d12ba422834b5 |
||
47 | ``` |
||
48 | |||
49 | Simon and Speck Block Ciphers という暗号方式を実装して、暗号キーを求めてねという問題。 |
||
50 | |||
51 | さっそく問題文中で公開されている[404.pdf](https://eprint.iacr.org/2013/404.pdf)を見てみると暗号方式を解説している論文のようでございました。 |
||
52 | いかんせん英語でございましたので、3分ぐらいで見るのを止めた訳です。英語は無理だと。 |
||
53 | |||
54 | きっと、実装してくださっている方がいるだろうとGithubなんかを検索したら出てきました。 |
||
55 | |||
56 | {{rawhtml(<blockquote class="embedly-card"><h4><a href="https://github.com/bozhu/NSA-ciphers">bozhu/NSA-ciphers</a></h4><p>NSA-ciphers - SIMON and SPECK the two lightweight block ciphers designed by the researchers from NSA</p></blockquote><script async src="//cdn.embedly.com/widgets/platform.js" charset="UTF-8"></script></script>)}} |
||
57 | |||
58 | simon.py はテストコードがついてるので、それをコメントアウトして目的のソースコードを書き加えます。 |
||
59 | |||
60 | simon.py |
||
61 | |||
62 | ```python |
||
63 | #!/usr/bin/env python |
||
64 | |||
65 | # ~中略~ |
||
66 | |||
67 | #for bsize, ksize, key, plain, cipher in test_vectors: |
||
68 | # my_simon = SIMON(bsize, ksize, key) |
||
69 | # encrypted = my_simon.encrypt(plain) |
||
70 | # assert encrypted == cipher |
||
71 | # for i in range(1000): |
||
72 | # encrypted = my_simon.encrypt(encrypted) |
||
73 | # for i in range(1000): |
||
74 | # encrypted = my_simon.decrypt(encrypted) |
||
75 | # decrypted = my_simon.decrypt(encrypted) |
||
76 | # assert decrypted == plain |
||
77 | |||
78 | chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_' |
||
79 | itr = permutations(chars,4) |
||
80 | plain = 0x6d564d37426e6e71 |
||
81 | encrypted = 0xbb5d12ba422834b5 |
||
82 | key = 0x00 |
||
83 | key_source = "" |
||
84 | |||
85 | for i in itr: |
||
86 | key_source="SECCON{"+"".join(map(str,i))+"}" |
||
87 | answer=key_source |
||
88 | key_source = "0x" + hex(ord(key_source[0]))[2:4]+hex(ord(key_source[1]))[2:4]+hex(ord(key_source[2]))[2:4]+hex(ord(key_source[3]))[2:4]+hex(ord(key_source[4]))[2:4]+hex(ord(key_source[5]))[2:4]+hex(ord(key_source[6]))[2:4]+hex(ord(key_source[7]))[2:4]+hex(ord(key_source[8]))[2:4]+hex(ord(key_source[9]))[2:4]+hex(ord(key_source[10]))[2:4]+hex(ord(key_source[11]))[2:4] |
||
89 | key = long(key_source,16) |
||
90 | c = SIMON(64, 96, key) |
||
91 | if encrypted == c.encrypt(plain): |
||
92 | print answer |
||
93 | |||
94 | print 'All tests passed' |
||
95 | ``` |
||
96 | |||
97 | >int(key.encode('hex'), 16) # 文字列→intは、こんな感じでもっとスマートに書けたか |
||
98 | |||
99 | 後はぶん回すだけなのですが、えらい時間がかかって、これはきっと競技時間中に終らないんじゃないかとも思いましたが、運良くフラグが出てくれました。 |
||
100 | |||
101 | ``` |
||
102 | SECCON{6Pz0} |
||
103 | ``` |
||
104 | |||
105 | # SHA-1 is dead (Crypto 100) |
||
106 | |||
107 | この条件のファイルを作る問題 |
||
108 | |||
109 | 1. file1 != file2 |
||
110 | 2. SHA1(file1) == SHA1(file2) |
||
111 | 3. SHA256(file1) <> SHA256(file2) |
||
112 | 4. 2017KiB < sizeof(file1) < 2018KiB |
||
113 | 5. 2017KiB < sizeof(file2) < 2018KiB |
||
114 | |||
115 | ※1KiB = 1024 bytes |
||
116 | |||
117 | SHA1のハッシュ衝突が起こせるようになったのは有名な話題なので知ってはおりました。 |
||
118 | 知ってはおりましたが実装まではしたことがございません。 |
||
119 | きっと誰かがPoCを公開してくださっているだろうと、調べるとすぐ出てきました。 |
||
120 | |||
121 | {{rawhtml(<blockquote class="embedly-card"><h4><a href="https://github.com/73spica/sha1-collision">73spica/sha1-collision</a></h4><p>sha1-collision - Googleが発表したSHA-1衝突の原理で衝突PDFを生成するスクリプト</p></blockquote><script async src="//cdn.embedly.com/widgets/platform.js" charset="UTF-8"></script>)}} |
||
122 | |||
123 | このツールは、こんな仕様 |
||
124 | |||
125 | * jpegを指定して、sha1ハッシュ値が同じpdfを作ってくれるツール |
||
126 | * jpegのファイルフォーマットを壊さずにハッシュ衝突してくれる |
||
127 | * それ故チェック処理が入っててフォーマットが壊れる場合は処理を中断する |
||
128 | |||
129 | いい感じのサイズのjpegを作るのが面倒だったため、ファイルの後ろに0x00を何byteかくっつけてサイズ調整しようと思った訳です。 |
||
130 | するとチェックに引っかかるんですよね。困った。 |
||
131 | |||
132 | なので、こうしました。 |
||
133 | |||
134 | * sha1ハッシュ衝突ツール(collision.py)のチェック処理をコメントアウト |
||
135 | * jpegファイルのお尻に0x00を何Byteか加えてサイズを調節する |
||
136 | * pdfのサイズが 2065408~2066432 Byte になるよう以下のシェルスクリプトを作って何度か試す |
||
137 | |||
138 | ```bash |
||
139 | #!/bin/bash |
||
140 | |||
141 | dd if=/dev/zero of=zero_a bs=1024 count=$1 |
||
142 | sleep 2 |
||
143 | cat sample1.jpg zero_a >a.jpg |
||
144 | cat sample2.jpg zero_a >b.jpg |
||
145 | |||
146 | python collision.py a.jpg b.jpg |
||
147 | |||
148 | ls -lrt collision* |
||
149 | ``` |
||
150 | |||
151 | ファイルアップロードしてフラグ取得 |
||
152 | |||
153 | ``` |
||
154 | SECCON{SHA-1_1995-2017?} |
||
155 | ``` |
||
156 | |||
157 | >ちなみに、公開されているsha1ハッシュが同じpdfの後ろに0x00をくっつけてサイズ調整すればいいと気付いたのは競技終了後にwriteupを見た時 |
||
158 | |||
159 | # JPEG file (Binary 100) |
||
160 | |||
161 | あぁ、これ進研ゼミでやってたやつだ!…じゃなくて、昔のSECCONで出た問題に似てる! |
||
162 | と、すぐ思い出した訳です。そしてそのwriteupを ~~パク~~参考にしようと思ったわけで、調べたら出てきました。 |
||
163 | |||
164 | {{rawhtml(<blockquote class="embedly-card"><h4><a href="http://d.hatena.ne.jp/yasulib/20120512/1336826146">SECCON CTF 福岡大会の問題 - yasulib memo</a></h4><p>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</p></blockquote><script async src="//cdn.embedly.com/widgets/platform.js" charset="UTF-8"></script>)}} |
||
165 | |||
166 | ```python |
||
167 | origGz = open("tktk.jpeg", "rb").read() |
||
168 | |||
169 | byteSize = len(origGz) |
||
170 | bits = [] |
||
171 | for i in range(0, 8): |
||
172 | bits.append(2**i) |
||
173 | |||
174 | for byte in range(0, byteSize): |
||
175 | for bit in bits: |
||
176 | change = chr( ord(origGz[byte]) ^ bit ) |
||
177 | newGz = origGz[0:byte] + change + origGz[byte+1:] |
||
178 | |||
179 | filename = "out/" + str(byte) + "_" + str(bit) + ".jpeg" |
||
180 | f = open(filename, "wb") |
||
181 | f.write(newGz) |
||
182 | f.close() |
||
183 | ``` |
||
184 | |||
185 | 1bitずつ反転させたファイルを作って、それを全て目で確認するという手段を取りました。 |
||
186 | |||
187 | >gzipなら、全ファイル展開を試してみるとか出来るんですが、jpegだとそうはいかない |
||
188 | |||
189 | よくよく考えなくても、全画像の枚数は **93024**枚になる訳で、それを目視で確認しようとしてたあの時の私は少しおかしかったのかもしれません。 |
||
190 | |||
191 |  |
||
192 | |||
193 | Windowsのフォルダの表示を「特大」にして、こんなのを延々と確認しました。 |
||
194 | 途中で力尽きて他の方法を考える流れでしたが、割と早い段階で出てきました。 |
||
195 | |||
196 |  |
||
197 | |||
198 | >いま思うと、ファイルヘッダが壊れている可能性が高い訳で、必然的にファイルの前半が被疑箇所になりますね |
||
199 | |||
200 | # Powerful_Shell (Binary 300) |
||
201 | |||
202 | 難読化問題!?まかせろバリバリってやってたけど |
||
203 | 私が解くよりも早くチームメイトのcatさんが光の速さで解いてくれました。 |
||
204 | ほんまcatさんは神やでぇ |
||
205 | |||
206 | ちなみに私の第六感が囁くのだけれど、作問者は[@Sh1n0g1](https://twitter.com/sh1n0g1)さんだと思う。 |
||
207 | |||
208 | 以下、途中までやった結果 |
||
209 | |||
210 | ## 難読化の解除 |
||
211 | |||
212 | 最下行でデコード結果を実行しているように見えるため、その直前に以下の行を挿入してファイルへ出力 |
||
213 | |||
214 | ``` |
||
215 | Write-Output $ECCON | Out-File -FilePath C:\Users\kanata\Desktop\20171209_SECCON\Binary_300_Powerful_Shell\dec.ps1 |
||
216 | ``` |
||
217 | |||
218 | ## adminチェック処理がある |
||
219 | |||
220 | 管理者権限じゃないとチェックアウトされる。Exitをコメントアウトっと |
||
221 | |||
222 | ``` |
||
223 | <# Host Check #> |
||
224 | Write-Host -b 00 -f 15 Checking Host... Please wait... -n |
||
225 | Try{ |
||
226 | If ((Get-EventLog -LogName Security | Where EventID -Eq 4624).Length -Lt 1000) { |
||
227 | Write-Host "This host is too fresh!" |
||
228 | Exit |
||
229 | } |
||
230 | }Catch{ |
||
231 | Write-Host "Failed: No admin rights!" |
||
232 | #Exit |
||
233 | } |
||
234 | Write-Host "Check passed" |
||
235 | ``` |
||
236 | |||
237 | ## 音が出る |
||
238 | |||
239 |  |
||
240 | |||
241 | スゴイ…音が出るよ。ソースを見ると以下がある。 |
||
242 | |||
243 | ``` |
||
244 | $secret=@(440,440,493,440,440,493,440,493,523,493,440,493,440,349) |
||
245 | ``` |
||
246 | |||
247 | 440ってあれですわ。周波数ですわ。440Hzで音叉の音(A:ラ)ですわ。 |
||
248 | 他の周波数も当てはめると以下になります。 |
||
249 | |||
250 | ``` |
||
251 | $secret=@(440,440,493,440,440,493,440,493,523,493,440,493,440,349) |
||
252 | #音階 ラ ラ シ ラ ラ シ ラ シ ド シ ラ シ ラ ファ |
||
253 | #押すキー h h j h h j h j k j h j h f |
||
254 | ``` |
||
255 | |||
256 | >「さくらさくら」ですね |
||
257 | |||
258 | この通り押すと処理が進み、また最下行でデコード結果を実行しているように見えるため、その直前に以下の行を挿入してファイルへ出力 |
||
259 | |||
260 | ``` |
||
261 | Write-Output $ECCON | Out-File -FilePath C:\Users\kanata\Desktop\20171209_SECCON\Binary_300_Powerful_Shell\dec.ps1 |
||
262 | ``` |
||
263 | |||
264 | ## 数字の羅列を得る |
||
265 | |||
266 | デコード結果は数字の羅列だった。 |
||
267 | ASCIIコードやろ?おっちゃんわかるで、これ |
||
268 | |||
269 | ``` |
||
270 | 10 |
||
271 | 36 |
||
272 | 123 |
||
273 | 59 |
||
274 | 125 |
||
275 | 61 |
||
276 | 43 |
||
277 | 36 |
||
278 | |||
279 | 以下、延々と続く |
||
280 | ``` |
||
281 | |||
282 | 以下のシェルスクリプトでデコードする |
||
283 | |||
284 | ```bash |
||
285 | #!/bin/bash |
||
286 | |||
287 | for WORD in `cat dec.ps1` |
||
288 | do |
||
289 | WORD=`echo $WORD|col -bx` |
||
290 | echo "obase=16; ibase=10; $WORD" | bc|xxd -ps -r |
||
291 | done |
||
292 | ``` |
||
293 | |||
294 | 結果 |
||
295 | |||
296 | |||
297 | ``` |
||
298 | ${;}=+$();${=}=${;};${+}=++${;};${@}=++${;};${.}=++${;};${[}=++${;};${]}=++${;};${(}=++${;};${)}=++${;};${&}=++${;};${|}=++${;};${"}="["+"$(@{})"[${)}]+"$(@{})"["${+}${|}"]+"$(@{})"["${@}${=}"]+"$?"[${+}]+"]";${;}="".("$(@{})"["${+}${[}"]+"$(@{})"["${+}${(}"]+"$(@{})"[${=}]+"$(@{})"[${[}]+"$?"[${+}]+"$(@{})"[${.}]);${;}="$(@{})"["${+}${[}"]+"$(@{})"[${[}]+"${;}"["${@}${)}"];"${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${(}${+}+${"}${&}${@}+${"}${+}${=}${+}+${"}${|}${)}+${"}${+}${=}${=}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${[}${]}+${"}${&}${=}+${"}${+}${+}${[}+${"}${+}${+}${+}+${"}${+}${=}${|}+${"}${+}${+}${@}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${|}+${"}${(}${|}+${"}${+}${+}${=}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${+}${+}${[}+${"}${.}${@}+${"}${+}${+}${(}+${"}${+}${=}${[}+${"}${+}${=}${+}+${"}${.}${@}+${"}${+}${+}${@}+${"}${|}${)}+${"}${+}${+}${]}+${"}${+}${+}${]}+${"}${+}${+}${|}+${"}${+}${+}${+}+${"}${+}${+}${[}+${"}${+}${=}${=}+${"}${.}${|}+${"}${+}${.}+${"}${+}${=}+${"}${)}${.}+${"}${+}${=}${@}+${"}${[}${=}+${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${.}${@}+${"}${[}${]}+${"}${+}${=}${+}+${"}${+}${+}${.}+${"}${.}${@}+${"}${.}${|}+${"}${&}${=}+${"}${[}${&}+${"}${+}${+}${|}+${"}${(}${|}+${"}${+}${+}${[}+${"}${.}${(}+${"}${)}${@}+${"}${]}${+}+${"}${[}${|}+${"}${[}${|}+${"}${.}${|}+${"}${[}${+}+${"}${+}${@}${.}+${"}${+}${.}+${"}${+}${=}+${"}${|}+${"}${&}${)}+${"}${+}${+}${[}+${"}${+}${=}${]}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${|}+${"}${)}${+}+${"}${+}${+}${+}+${"}${+}${+}${+}+${"}${+}${=}${=}+${"}${.}${@}+${"}${)}${[}+${"}${+}${+}${+}+${"}${|}${&}+${"}${.}${.}+${"}${.}${|}+${"}${]}${|}+${"}${+}${.}+${"}${+}${=}+${"}${|}+${"}${&}${)}+${"}${+}${+}${[}+${"}${+}${=}${]}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${[}+${"}${&}${.}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${+}${@}${.}+${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${+}${@}${]}+${"}${.}${[}+${"}${+}${.}+${"}${+}${=}+${"}${+}${@}${]}|${;}"|&${;} |
||
299 | ``` |
||
300 | |||
301 | おぉ・・・もぅこれ完全にJavaScriptの難読化と同じだわ。。。スゴイわ。。。 |
||
302 | catさん「解けました」 |
||
303 | ワイ「アッハイ」 |