CTF Writeup SECCON 2017¶
- CTF Writeup SECCON 2017
- 結果&感想
- Log search (Web 100)
- Simon and Speck Block Ciphers (Crypto 100)
- SHA-1 is dead (Crypto 100)
- JPEG file (Binary 100)
- Powerful_Shell (Binary 300)
結果&感想¶
某チームでSECCON2017に参加しました。
4問解きました。全部100点だけどな!
チームの成績なんですが、もしかしたら国内決勝行けるかもという順位!
決勝行けたらめでたいね!!!
基本的に今回は
こまけぇこたぁいいんだよ¶
解けりゃぁいいんだよ!ちゃんと実装しよ?めんどくせぇ買ってこいよゴロリ
というスタンスで解いていたため、はたして公開していいのかというクソコードっぷりを披露する事になります。
Log search (Web 100)¶
問題文はアクセス先のURLだけだったかな。。
これはなんで解けたのか、どういう趣旨だったか理解する前に解けてしまいました。
検索窓があるので、おもむろに flag と入力して検索
出てきたそれっぽいヤツにアクセスする。
フラグ取れた。
SECCON{N0SQL_1njection_for_Elasticsearch!}
Simon and Speck Block Ciphers (Crypto 100)¶
平文と暗号文、キーの一部が提供されています。
Simon_96_64, ECB, key="SECCON{xxxx}", plain=0x6d564d37426e6e71, cipher=0xbb5d12ba422834b5
Simon and Speck Block Ciphers という暗号方式を実装して、暗号キーを求めてねという問題。
さっそく問題文中で公開されている404.pdfを見てみると暗号方式を解説している論文のようでございました。
いかんせん英語でございましたので、3分ぐらいで見るのを止めた訳です。英語は無理だと。
きっと、実装してくださっている方がいるだろうとGithubなんかを検索したら出てきました。
bozhu/NSA-ciphers¶
NSA-ciphers - SIMON and SPECK the two lightweight block ciphers designed by the researchers from NSA
simon.py はテストコードがついてるので、それをコメントアウトして目的のソースコードを書き加えます。
simon.py
#!/usr/bin/env python
# ~中略~
#for bsize, ksize, key, plain, cipher in test_vectors:
# my_simon = SIMON(bsize, ksize, key)
# encrypted = my_simon.encrypt(plain)
# assert encrypted == cipher
# for i in range(1000):
# encrypted = my_simon.encrypt(encrypted)
# for i in range(1000):
# encrypted = my_simon.decrypt(encrypted)
# decrypted = my_simon.decrypt(encrypted)
# assert decrypted == plain
chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_'
itr = permutations(chars,4)
plain = 0x6d564d37426e6e71
encrypted = 0xbb5d12ba422834b5
key = 0x00
key_source = ""
for i in itr:
key_source="SECCON{"+"".join(map(str,i))+"}"
answer=key_source
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]
key = long(key_source,16)
c = SIMON(64, 96, key)
if encrypted == c.encrypt(plain):
print answer
print 'All tests passed'
int(key.encode('hex'), 16) # 文字列→intは、こんな感じでもっとスマートに書けたか
後はぶん回すだけなのですが、えらい時間がかかって、これはきっと競技時間中に終らないんじゃないかとも思いましたが、運良くフラグが出てくれました。
SECCON{6Pz0}
SHA-1 is dead (Crypto 100)¶
この条件のファイルを作る問題
- file1 != file2
- SHA1(file1) == SHA1(file2)
- SHA256(file1) <> SHA256(file2)
- 2017KiB < sizeof(file1) < 2018KiB
- 2017KiB < sizeof(file2) < 2018KiB
※1KiB = 1024 bytes
SHA1のハッシュ衝突が起こせるようになったのは有名な話題なので知ってはおりました。
知ってはおりましたが実装まではしたことがございません。
きっと誰かがPoCを公開してくださっているだろうと、調べるとすぐ出てきました。
73spica/sha1-collision¶
sha1-collision - Googleが発表したSHA-1衝突の原理で衝突PDFを生成するスクリプト
このツールは、こんな仕様
- jpegを指定して、sha1ハッシュ値が同じpdfを作ってくれるツール
- jpegのファイルフォーマットを壊さずにハッシュ衝突してくれる
- それ故チェック処理が入っててフォーマットが壊れる場合は処理を中断する
いい感じのサイズのjpegを作るのが面倒だったため、ファイルの後ろに0x00を何byteかくっつけてサイズ調整しようと思った訳です。
するとチェックに引っかかるんですよね。困った。
なので、こうしました。
- sha1ハッシュ衝突ツール(collision.py)のチェック処理をコメントアウト
- jpegファイルのお尻に0x00を何Byteか加えてサイズを調節する
- pdfのサイズが 2065408~2066432 Byte になるよう以下のシェルスクリプトを作って何度か試す
#!/bin/bash
dd if=/dev/zero of=zero_a bs=1024 count=$1
sleep 2
cat sample1.jpg zero_a >a.jpg
cat sample2.jpg zero_a >b.jpg
python collision.py a.jpg b.jpg
ls -lrt collision*
ファイルアップロードしてフラグ取得
SECCON{SHA-1_1995-2017?}
ちなみに、公開されているsha1ハッシュが同じpdfの後ろに0x00をくっつけてサイズ調整すればいいと気付いたのは競技終了後にwriteupを見た時
JPEG file (Binary 100)¶
あぁ、これ進研ゼミでやってたやつだ!…じゃなくて、昔のSECCONで出た問題に似てる!
と、すぐ思い出した訳です。そしてそのwriteupを パク参考にしようと思ったわけで、調べたら出てきました。
SECCON CTF 福岡大会の問題 - yasulib memo¶
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
origGz = open("tktk.jpeg", "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) + ".jpeg"
f = open(filename, "wb")
f.write(newGz)
f.close()
1bitずつ反転させたファイルを作って、それを全て目で確認するという手段を取りました。
gzipなら、全ファイル展開を試してみるとか出来るんですが、jpegだとそうはいかない
よくよく考えなくても、全画像の枚数は 93024枚になる訳で、それを目視で確認しようとしてたあの時の私は少しおかしかったのかもしれません。
Windowsのフォルダの表示を「特大」にして、こんなのを延々と確認しました。
途中で力尽きて他の方法を考える流れでしたが、割と早い段階で出てきました。
いま思うと、ファイルヘッダが壊れている可能性が高い訳で、必然的にファイルの前半が被疑箇所になりますね
Powerful_Shell (Binary 300)¶
難読化問題!?まかせろバリバリってやってたけど
私が解くよりも早くチームメイトのcatさんが光の速さで解いてくれました。
ほんまcatさんは神やでぇ
ちなみに私の第六感が囁くのだけれど、作問者は@Sh1n0g1さんだと思う。
以下、途中までやった結果
難読化の解除¶
最下行でデコード結果を実行しているように見えるため、その直前に以下の行を挿入してファイルへ出力
Write-Output $ECCON | Out-File -FilePath C:\Users\kanata\Desktop\20171209_SECCON\Binary_300_Powerful_Shell\dec.ps1
adminチェック処理がある¶
管理者権限じゃないとチェックアウトされる。Exitをコメントアウトっと
<# Host Check #> Write-Host -b 00 -f 15 Checking Host... Please wait... -n Try{ If ((Get-EventLog -LogName Security | Where EventID -Eq 4624).Length -Lt 1000) { Write-Host "This host is too fresh!" Exit } }Catch{ Write-Host "Failed: No admin rights!" #Exit } Write-Host "Check passed"
音が出る¶
スゴイ…音が出るよ。ソースを見ると以下がある。
$secret=@(440,440,493,440,440,493,440,493,523,493,440,493,440,349)
440ってあれですわ。周波数ですわ。440Hzで音叉の音(A:ラ)ですわ。
他の周波数も当てはめると以下になります。
$secret=@(440,440,493,440,440,493,440,493,523,493,440,493,440,349) #音階 ラ ラ シ ラ ラ シ ラ シ ド シ ラ シ ラ ファ #押すキー h h j h h j h j k j h j h f
「さくらさくら」ですね
この通り押すと処理が進み、また最下行でデコード結果を実行しているように見えるため、その直前に以下の行を挿入してファイルへ出力
Write-Output $ECCON | Out-File -FilePath C:\Users\kanata\Desktop\20171209_SECCON\Binary_300_Powerful_Shell\dec.ps1
数字の羅列を得る¶
デコード結果は数字の羅列だった。
ASCIIコードやろ?おっちゃんわかるで、これ
10 36 123 59 125 61 43 36 以下、延々と続く
以下のシェルスクリプトでデコードする
#!/bin/bash
for WORD in `cat dec.ps1`
do
WORD=`echo $WORD|col -bx`
echo "obase=16; ibase=10; $WORD" | bc|xxd -ps -r
done
結果
${;}=+$();${=}=${;};${+}=++${;};${@}=++${;};${.}=++${;};${[}=++${;};${]}=++${;};${(}=++${;};${)}=++${;};${&}=++${;};${|}=++${;};${"}="["+"$(@{})"[${)}]+"$(@{})"["${+}${|}"]+"$(@{})"["${@}${=}"]+"$?"[${+}]+"]";${;}="".("$(@{})"["${+}${[}"]+"$(@{})"["${+}${(}"]+"$(@{})"[${=}]+"$(@{})"[${[}]+"$?"[${+}]+"$(@{})"[${.}]);${;}="$(@{})"["${+}${[}"]+"$(@{})"[${[}]+"${;}"["${@}${)}"];"${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${(}${+}+${"}${&}${@}+${"}${+}${=}${+}+${"}${|}${)}+${"}${+}${=}${=}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${[}${]}+${"}${&}${=}+${"}${+}${+}${[}+${"}${+}${+}${+}+${"}${+}${=}${|}+${"}${+}${+}${@}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${|}+${"}${(}${|}+${"}${+}${+}${=}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${+}${+}${[}+${"}${.}${@}+${"}${+}${+}${(}+${"}${+}${=}${[}+${"}${+}${=}${+}+${"}${.}${@}+${"}${+}${+}${@}+${"}${|}${)}+${"}${+}${+}${]}+${"}${+}${+}${]}+${"}${+}${+}${|}+${"}${+}${+}${+}+${"}${+}${+}${[}+${"}${+}${=}${=}+${"}${.}${|}+${"}${+}${.}+${"}${+}${=}+${"}${)}${.}+${"}${+}${=}${@}+${"}${[}${=}+${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${.}${@}+${"}${[}${]}+${"}${+}${=}${+}+${"}${+}${+}${.}+${"}${.}${@}+${"}${.}${|}+${"}${&}${=}+${"}${[}${&}+${"}${+}${+}${|}+${"}${(}${|}+${"}${+}${+}${[}+${"}${.}${(}+${"}${)}${@}+${"}${]}${+}+${"}${[}${|}+${"}${[}${|}+${"}${.}${|}+${"}${[}${+}+${"}${+}${@}${.}+${"}${+}${.}+${"}${+}${=}+${"}${|}+${"}${&}${)}+${"}${+}${+}${[}+${"}${+}${=}${]}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${|}+${"}${)}${+}+${"}${+}${+}${+}+${"}${+}${+}${+}+${"}${+}${=}${=}+${"}${.}${@}+${"}${)}${[}+${"}${+}${+}${+}+${"}${|}${&}+${"}${.}${.}+${"}${.}${|}+${"}${]}${|}+${"}${+}${.}+${"}${+}${=}+${"}${|}+${"}${&}${)}+${"}${+}${+}${[}+${"}${+}${=}${]}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${[}+${"}${&}${.}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${+}${@}${.}+${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${+}${@}${]}+${"}${.}${[}+${"}${+}${.}+${"}${+}${=}+${"}${+}${@}${]}|${;}"|&${;}
おぉ・・・もぅこれ完全にJavaScriptの難読化と同じだわ。。。スゴイわ。。。
catさん「解けました」
ワイ「アッハイ」