suanの備忘録

SUANが色々行ったこと等を書いていきます。

SECCONに初めて参加した参加記録 【SECCON 2019】

SECCONに参加しました!

SECCON2019に、チームMIS.Wとしてmusaprg、soeki、shiroと一緒に参加しました。結果は456点で148位でした。

SECCON結果
SECCON
ほぼ初めてな人ばかりが集まるチームで「目標は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 passwordbash と入れると 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、メモリリークできないです勉強してきます…。