SECCONに初めて参加した参加記録 【SECCON 2019】
SECCONに参加しました!
SECCON2019に、チームMIS.Wとしてmusaprg、soeki、shiroと一緒に参加しました。結果は456点で148位でした。 ほぼ初めてな人ばかりが集まるチームで「目標は500点くらい取れればいいよね」と言っていたので、良い方ではないかと思っています。
SECCON Challenges
Beeeeeeeeeer
まずはBeeeeeeeeeerです。 Let's decode!
と問題分に書かれています。
echo -e "\033#8" sleep 1 C=$(tput cols) L=$(tput lines) for ID in $(seq $(($L * $C * 6))); do x=$(($RANDOM % $C)) y=$(($RANDOM % $L)) printf "\033[${y};${x}f " done for ID in $(seq $(($L * $C * 6))); do x=$(($RANDOM % $C)) y=$(($RANDOM % $L)) printf "\033[${y};${x}fF" done clear echo TGV0J3MgZGVjb3JkaW5nISjiiafiiIDiiaYqKQo= | base64 -d read $'\164\162\141\160' '' $'\61' $'\62' $'\63' $'\x31\x35' $'\x31\x38' $'\u0031\u0039' $(echo MjAK | base64 -d) echo $- | grep x && exit $(echo =btB | rev | tr A-Za-z N-ZA-Mn-za-m | base64 -d) | $(echo =bNpyW3M | rev | tr A-Za-z N-ZA-Mn-za-m | base64 -d) $(echo XRKY | rev | tr A-Za-z N-ZA-Mn-za-m | base64 -d) $(echo =ogO | rev | base64 -d) && exit if [ -z "$1" ]; then ID=$'\x6e\x61\x6e\x64\x6f\x6b\x75'; else ID="$1"; fi if whoami | grep -e root -e user -e adm -e nobody -e test -e "$ID" >/dev/null; then :; else exit; fi for i in $($'\x73\x65\x71' $((RANDOM % 10))); do $($'\x65\x63\x68\x6f' c2xlZXAK | $'\x62\x61\x73\x65\x36\x34' -d) $((RANDOM % 300)); done $'\145\143\150\157' $- | $(echo =oAclJ3Z | rev | base64 -d) $(echo =oAe | rev | base64 -d) && $($'\x65\x63\x68\x6f' ZXhpdAo= | $'\x62\x61\x73\x65\x36\x34' $'\x2d\x64') $(echo =btB | rev | tr A-Za-z N-ZA-Mn-za-m | base64 -d) | $(echo M3WypNb= | tr A-Za-z N-ZA-Mn-za-m | base64 -d) $(echo YKRX | tr A-Za-z N-ZA-Mn-za-m | base64 -d) $(echo Btb= | tr A-Za-z N-ZA-Mn-za-m | base64 -d) && exit $'\145\170\160\157\162\164' $'\u0053\u0031'=$(echo aG9nZWZ1Z2EK | base64 -d)
Beeeeeeeeeerを見る限り、Shell Scriptであることがわかるので、実行権限を与えて実行してみると、
Let's decording!(≧∀≦*)
というメッセージが。
また、 read
以降の文が全てエンコードされていることがわかります。なのでとりあえずdecodeします。
read trap '' 1 2 3 15 18 19 20 echo $- | grep x && exit : | grep -q : && exit if [ -z "$1" ]; then ID=nandoku; else ID="$1"; fi if whoami | grep -e root -e user -e adm -e nobody -e test -e "$ID" >/dev/null; then :; else exit; fi for i in $(seq $((RANDOM % 10))); do sleep $((RANDOM % 300)); done echo $- | grep x && exit : | grep -q : && exit export S1=hogefuga
いらないコードばっかりですね。必要なのは export S1=hogefuga
だけです。 なんで執拗にexitさせてくるんだ
更にその後のコードもデコードしてみると、
: killall sh : shutdown $(: pkill sh) : shutdown : shutdown : poweroff : poweroff : exit : poweroff : shutdown : shutdown : shutdown : pkill sh : shutdown
こうなっていました。これ以上にこの並びが続いていて、どんだけ電源落としたいんだってなります…
重要なのは export S1=hogefuga
とその後のechoの1行だけです。
その場所だけ隔離してbashで実行してみたところ、ビープ音のなった回数をランダムで聞いてくるとても面倒くさいプログラムにぶち当たります。(間違えるとexitされるのでたちが悪い)
| base64 -d | gunzip | bash
を
| base64 -d | gunzip > Beeeeeeeeeer2.sh
として出力してみると
for k in $(seq $((RANDOM % 10 + 1))); do l=$((RANDOM % 10 + 1)) for m in $($(echo ==gCxV2c | rev | base64 -d) $l); do echo -ne '\a' sleep 1 done echo "How many beeps?" read n </dev/tty export n if [ "$n" -ne "$l" ]; then exit; fi done echo -ne '\a' sleep 1 echo -ne '\a' sleep 1 echo -ne '\a' sleep 1 echo "How many beeps?" read n </dev/tty export n
何だこれは!!!私の邪魔をしてくるコードがたくさん
export n
だけが必要であり、n=3であることがわかるので、 export 3
だけを残して削除します。
更にその後にもechoがあり、そこがまた重要なのでそこだけを隔離して実行してみます。
Enter the password
と出てきますが、パスワードなんて知りません。ので、やっぱり
| base64 -d | openssl aes-256-cbc -d -pass pass:$(echo -n $n | md5sum | cut -c2,3,5,12) -md md5 2>/dev/null | bash
を
| base64 -d | openssl aes-256-cbc -d -pass pass:cccc -md md5 2>/dev/null > Beeeeeeeeeer3.sh
として見てみます。
__=$(. 2>&1);__=${__##*.};__=$(. 2>&1);__=${__##*.};${__:$(($[($[$$/$$]<<$[$$/$$]<<$[$$/$$]<<$[$$/$$])+$[$$/$$]]+$[($[$$/$$]<<$[$$/$$]<<$[$$/$$]<<$[$$/$$])+$[$$/$$]]+$[$$/$$])):$((___=___^___||++___))}${__:$[$[$$/$$]<<$[$$/$$]<<$[$$/$$]]:$((___=___^___||++___))}${__:$(($[($[$$/$$]<<$[$$/$$]<<$[$$/$$]<<$[$$/$$])+$[$$/$$]]+$[($[$$/$$]<<$[$$/$$]<<$[$$/$$]<<$[$$/$$])+$[$$/$$]])):$((___=___^___||++___))} -- {z..A};${@:$((____=(____^____||++____)+
のような感じで、何もわかりません。が、一番最後に echo SECCON{$S1$n$_____}
という文字列を発見。
S1 = hogefuga
n = 3
であるので、最後の____だけわかればいいことになります。
またこれをデコードすると
__=$(. 2>&1) __=${__##*.} __=$(. 2>&1) __=${__##*.} set -- {z..A} echo Enter the password read _____ : password is bash read _____ echo -e '\033[?7h'
となりました。ちょこっと内容が消え去っていて私はここで戸惑いました。(←ちゃんとデコードしろ)
: password is bash
、神かこれ。ということで Enter the password
で bash
と入れると Good Job!
と帰ってくるので正解だとわかります。
これらからflagは
SECCON{hogefuga3bash}
となります。
coffee_break
何がコーヒーだ!コーヒー要素なんてないじゃないか!と思われた方、正解です。
とりあえず配布されたpythonコードを見てみる。
import sys from Crypto.Cipher import AES import base64 def encrypt(key, text): s = '' for i in range(len(text)): s += chr((((ord(text[i]) - 0x20) + (ord(key[i % len(key)]) - 0x20)) % (0x7e - 0x20 + 1)) + 0x20) return s key1 = "SECCON" key2 = "seccon2019" text = sys.argv[1] enc1 = encrypt(key1, text) cipher = AES.new(key2 + chr(0x00) * (16 - (len(key2) % 16)), AES.MODE_ECB) p = 16 - (len(enc1) % 16) enc2 = cipher.encrypt(enc1 + chr(p) * p) print(base64.b64encode(enc2).decode('ascii'))
cipherとbase 64を使用したところはすぐにデコードできそうですね。なので、
key1 = "SECCON" key2 = "seccon2019" text = sys.argv[1] cipher = AES.new(key2 + chr(0x00) * (16 - (len(key2) % 16)), AES.MODE_ECB) dec1 = cipher.decrypt(base64.b64decode(text))
これだけでデコードできます。問題は def encrypt(key, text):
でエンコードされた文字列。
でもこれ、ただの数値計算なので逆算してあげる。すると
def decrypt(key, text): s = '' for i in range(len(text)): s += chr(ord(text[i]) + 0x20 - (ord(key[i % len(key)]) - 0x20) + 0x3F) return s
はい。これでOK。 def encrypt
が95で割ったあまりを出力しているので正確にはデコードできないが、推測ができれば問題ないのでOK。
またこれはアルファベットしかないとして仮定した場合である。すると
FyRyZNBO2MG6ncd3hEkC/yeYKUseI/CxYoZiIeV2fe/Jmtwx+WbWmU1gtMX9m905
が
S�����{�uccess_�ecryption_�eah_�eah_S�����}
になった。これから推測するとflagは
SECCON{Success_Decryption_Yeah_Yeah_SECCON}
となる。
pngbomb
画像データがgzで圧縮されているので解凍して表示しようとすると、IHDRが壊れていることがわかる。これしかわからなかったのでダメです。12時間を溶かした問題。
SECCONを終えて
初めて出場したCTFの大会でしたが、とても楽しく、寝る時間を惜しんでいました。
miscしか解いていないけれど、それが一番楽しかった気がする。
Pwn、メモリリークできないです勉強してきます…。