[CISCN2021 Quals]upload题解
考点
- 文件上传
- mb_strtolower绕过特定字符检测
难度
- 简单题
解题思路
首页提供了源码,分析代码发现该站支持文件上传功能,上传限制了文件大小和文件名。主要是需要对文件名的限制进行绕过,来达到getshell的目的。
<?php
if (!isset($_GET["ctf"])) {
highlight_file(__FILE__);
die();
}
if(isset($_GET["ctf"]))
$ctf = $_GET["ctf"];
if($ctf=="upload") {
if ($_FILES['postedFile']['size'] > 1024*512) {
die("这么大个的东西你是想d我吗?");
}
$imageinfo = getimagesize($_FILES['postedFile']['tmp_name']);
if ($imageinfo === FALSE) {
die("如果不能好好传图片的话就还是不要来打扰我了");
}
if ($imageinfo[0] !== 1 && $imageinfo[1] !== 1) {
die("东西不能方方正正的话就很讨厌");
}
$fileName=urldecode($_FILES['postedFile']['name']);
if(stristr($fileName,"c") || stristr($fileName,"i") || stristr($fileName,"h") || stristr($fileName,"ph")) {
die("有些东西让你传上去的话那可不得了");
}
$imagePath = "image/" . mb_strtolower($fileName);
if(move_uploaded_file($_FILES["postedFile"]["tmp_name"], $imagePath)) {
echo "upload success, image at $imagePath";
} else {
die("传都没有传上去");
}
}
从代码中可以看出,文件名不能出现c、i、h和ph。
if(stristr($fileName,"c") || stristr($fileName,"i") || stristr($fileName,"h") || stristr($fileName,"ph")) {
die("有些东西让你传上去的话那可不得了");
}
$imagePath = "image/" . mb_strtolower($fileName);
绕过上述限制可以借助下面的mb_strtolower函数,有关该函数的文档在https://www.php.net/manual/zh/function.mb-strtolower.php。可以看到,该函数可以处理一些比较奇怪的unicode字符,比如各个国家的一些比较特殊的字母。
在文档下方还提到了土耳其的字符İ。İ经过该函数处理可以变成i。
注意,该函数在不同的环境下有不同的表现,目前经过测试,PHP5.6是可以成功变成i的,7.x的版本,会变成另一个类似i的长度为3的字符。具体实现有兴趣可以查阅PHP各个版本的mb_strtolower函数代码。
到这里,i的限制就可以绕过了。c,h,ph并没有找到类似的字符。有兴趣可以查阅https://www.compart.com/en/unicode/。
因为ph、h和c的限制,直接上传php文件或者.htaccess文件应该是不太现实了。
后来经过扫描发现该站还有一个example.php,会解压zip文件,因此可以上传一个zip。
下面只展示一些关键代码:
if($ctf=="poc") {
$zip = new \ZipArchive();
$name_for_zip = "example/" . $_POST["file"];
if(explode(".",$name_for_zip)[count(explode(".",$name_for_zip))-1]!=="zip") {
die("要不咱们再看看?");
}
if ($zip->open($name_for_zip) !== TRUE) {
die ("都不能解压呢");
}
echo "可以解压,我想想存哪里";
$pos_for_zip = "/tmp/example/" . md5($_SERVER["REMOTE_ADDR"]);
$zip->extractTo($pos_for_zip);
$zip->close();
unlink($name_for_zip);
$files = glob("$pos_for_zip/*");
foreach($files as $file){
if (is_dir($file)) {
continue;
}
$first = imagecreatefrompng($file);
$size = min(imagesx($first), imagesy($first));
$second = imagecrop($first, ['x' => 0, 'y' => 0, 'width' => $size, 'height' => $size]);
if ($second !== FALSE) {
$final_name = pathinfo($file)["basename"];
imagepng($second, 'example/'.$final_name);
imagedestroy($second);
}
imagedestroy($first);
unlink($file);
}
}
阅读代码可以看到,该部分会解压上传的zip文件,并读取zip中的图片文件(没有限制文件名,也就是可以用PHP),重设大小后在保存。这部分会对把木马写在图片末尾的图片马造成影响,木马不会被写入新的文件。因此需要把木马写入正常的数据块中。
具体操作
首先自己写一个文件上传的表单,这个没啥难度,注意file的name字段设为postedFile即可。
随后上传一个zip文件,并设置文件的width和height,以及文件名。
上传的文件可以用https://github.com/huntergregal/PNG-IDAT-Payload-Generator/项目来在数据块中写入payload。
上传成功后,访问example.php,设置好相关参数触发解压操作,之后蚁剑连接/example/a.php,即可找到flag。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理