一,00截断
00截断的原理
0x00 , %00 , /00 之类的截断,都是一样的,只是不同表示而已。
在url中 %00 表示ascll码中的 0,而ascii中0作为特殊字符保留,表示字符串结束,所以当url中出现%00时就会认为读取已结束。
比如:
https://xxx.com/upload/?filename=test.txt
此时输出的是test.txt
加上 %00
https://xxx.com/upload/?filename=test.php%00.txt
此时输出的是test.php
这个原理相信大家都可以看的非常明白,但是题目本身有几方面值是得思考的。
1在请求包的那一个位置进行00截断,截断的方式是什么 ?
首先是位置的问题
这是在filename处修改的。
这是在请求头和filename处同时修改的。
这是仅仅在请求头处修改的。
根据对比可以发现,只有在filename处修改才有效果,所以网上大部分的流传的都不是完全的正确,但本人推荐第二种的,因为在实际操作中我们并不知道也没有必要去纠结修改那一处的,都改了就是。
测试有效就可以蚁剑进入后台了。
得到flag.
2为什么我们构造的地址为http://challenge-a35b2746e3160702.sandbox.ctfhub.com:10080/upload/2.php(我这里是用2命名)
原地址http://challenge-a35b2746e3160702.sandbox.ctfhub.com:10080/?road=/var/www/html/upload/
可以来看一下源码
<?php
header("Content-type: text/html;charset=utf-8");
error_reporting(0);
//设置上传目录
define("UPLOAD_PATH", dirname(__FILE__) . "/upload/");
define("UPLOAD_URL_PATH", str_replace($_SERVER['DOCUMENT_ROOT'], "", UPLOAD_PATH));
if (!file_exists(UPLOAD_PATH)) {
mkdir(UPLOAD_PATH, 0755);
}
if (!empty($_POST['submit'])) {
$name = basename($_FILES['file']['name']);
$info = pathinfo($name);
$ext = $info['extension'];
$whitelist = array("jpg", "png", "gif");
if (in_array($ext, $whitelist)) {
$des = $_GET['road'] . "/" . rand(10, 99) . date("YmdHis") . "." . $ext;
if (move_uploaded_file($_FILES['file']['tmp_name'], $des)) {
echo "<script>alert('上传成功')</script>";
} else {
echo "<script>alert('上传失败')</script>";
}
} else {
echo "文件类型不匹配";
}
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CTFHub 文件上传 - 00截断</title>
</head>
<body>
<h1>CTFHub 文件上传 - 00截断</h1>
<form action=<?php echo "?road=" . UPLOAD_PATH; ?> method="post" enctype="multipart/form-data">
<label for="file">Filename:</label>
<input type="file" name="file" id="file" />
<br />
<input type="submit" name="submit" value="Submit" />
</form>
<!--
if (!empty($_POST['submit'])) {
$name = basename($_FILES['file']['name']);
$info = pathinfo($name);
$ext = $info['extension'];
$whitelist = array("jpg", "png", "gif");
if (in_array($ext, $whitelist)) {
$des = $_GET['road'] . "/" . rand(10, 99) . date("YmdHis") . "." . $ext;
if (move_uploaded_file($_FILES['file']['tmp_name'], $des)) {
echo "<script>alert('上传成功')</script>";
} else {
echo "<script>alert('上传失败')</script>";
}
} else {
echo "文件类型不匹配";
}
}
-->
</body>
</html>
in_array — 检查数组中是否存在某个值
in_array( mixed $needle, array $haystack[, bool $strict = FALSE] ) : bool
move_uploaded_file — 将上传的文件移动到新位置
move_uploaded_file( string $filename, string $destination) : bool
根据in_array($ext, $whitelist)为真即后缀为"jpg", “png”, "gif"之一的文件,进入下一个if。
根据 $des = $_GET[‘road’] . “/” . rand(10, 99) . date(“YmdHis”) . “.” . $ext;得知得到的完整路径是 GET[‘road’]+随机数+日期加前面获得的后缀名。我们将他修改为已上传的文件的路径,也就是说要上传一句话木马的php文件就要绕过后缀的限制,而使用2.php.jpg修改后的请求包无法上传,
故采用00截断。
二,双写后缀
str_ireplace — str_replace() 的忽略大小写版本
str_replace — 子字符串替换。
str_replace( mixed $search, mixed $replace, mixed $subject[, int & $count] ) : mixed
该函数返回一个字符串或者数组。该字符串或数组是将 subject 中全部的 search 都被 replace 替换之后的结果。
结合以上说明在看源码题目给的提示
显而易见,是将文件后缀替换成了空格,那么只要双写后缀即可,写成2.pphphp然后上传。
由于str_ireplace会过滤所有php后缀,所以 2.phpphp的后缀无法保留php后缀,而2.pphphp仅仅将中间的php过滤,所以留下了php后缀,因此成功拿到flag。