代码审计-某微商城系统RCE漏洞

前言

本次审计的项目有提供部署的相关步骤和视频教程,但不知为何我自己在搭建的时候会出现莫名的错误导致环境搭建不起来,因此只能fofa上面搜一个来进行测试

fofa语句:"/Mao_Public/js/jquery-2.1.1.min.js"

前台sql注入漏洞

首先我们先审计一下主页代码index.php,发现一处sql查询的地方

1
2
3
4
5
6
7
8
9
10
11
<?php
$rs = $DB->query("SELECT * FROM mao_shop WHERE M_id='{$mao['id']}' and (tj='0' && zt='0') order by id desc limit 2");
while($rows = $DB->fetch($rs)){
if($rows['type'] == 1){
$type = "天猫优选";
}elseif ($rows['type'] == 2){
$type = "超值捡漏";
}elseif ($rows['type'] == 3){
$type = "人气销量";
}
?>

对$mao[‘id’]进行溯源,看看是否可控

1
$mao=$DB->get_row("select * from mao_data where url='{$_SERVER['HTTP_HOST']}' or url_1='{$_SERVER['HTTP_HOST']}' limit 1");

可以看出$mao的值是从一个叫做mao_data的表中获取的,因此是不可控的,遂放弃

该文件中还有一两处sql查询的地方,但其参数我们都不可控

在网页处乱点一通后,查看bp的代理模块中的http历史记录,发现了有趣的地方

image-20240824160839030

查看goods.php文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
require './Mao/common.php';
$id= isset($_GET['id']) ? $_GET['id'] : 0;
$cha_1 = $DB->get_row("select * from mao_shop where M_id='{$mao['id']}' and id='{$id}' limit 1");
if($cha_1['type'] == 1){
$bt = "天猫优选";
}elseif ($cha_1['type'] == 2){
$bt = "超值捡漏";
}elseif ($cha_1['type'] == 3){
$bt = "人气销量";
}
if(!$cha_1){
sysmsg("商品不存在!");
}
?>

已知$mao[‘id’]不可控,但是后面的$id可以通过$id= isset($_GET['id']) ? $_GET['id'] : 0;进行控制,还是单引号包括

通过查看sql文件得知表mao_shop一共有18字段

所以测试:/goods.php?id='union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18--+

image-20240824162256014

可以看到字段3,7,12,14可控

image-20240824163455309

剩下的就是普通的union注入步骤,这边就不详写了

前台任意文件上传漏洞

全局搜索文件上传的危险函数,这次是move_uploaded_file(),位于api/api.php文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
elseif($mod == "upload"){
$type = daddslashes($_REQUEST['type']);
if($type == 1){
if ((($_FILES["file"]["type"] == "image/gif") || ($_FILES["file"]["type"] == "image/jpeg") || ($_FILES["file"]["type"] == "image/png") || ($_FILES["file"]["type"] == "image/pjpeg")) && ($_FILES["file"]["size"] < 5242880)){
if ($_FILES["file"]["error"] > 0){
$result=array("code"=>-2,"msg"=>"上传出错!");
exit(json_encode($result));
}else{
$cmm = date("YmdHis").rand(111,999);
$name = explode('.',$_FILES["file"]["name"]);
$newPath = $cmm.'.'.$name[1];
if (preg_match("/[\x7f-\xff]/", $newPath)) {
$result=array("code"=>-3,"msg"=>"文件名称不能为中文!");
exit(json_encode($result));
}
if (file_exists("../upload/" . $newPath)){
$result=array("code"=>-2,"msg"=>"上传出错!");
exit(json_encode($result));
}else{
move_uploaded_file($_FILES["file"]["tmp_name"],"../upload/" . $newPath);
$lj=array("src"=>"/upload/{$newPath}","title"=>"图片");
$result=array("code"=>0,"msg"=>"上传成功!","data"=>$lj,"name"=>"/upload/{$newPath}");
exit(json_encode($result));
}
}
}else{
$result=array("code"=>-3,"msg"=>"图片大小不能超过5M!{$_FILES["file"]["size"]}");
exit(json_encode($result));
}
}
else{
$result=array("code"=>-1,"msg"=>"上传类型不存在!");
}
exit(json_encode($result));
}

其中$mod由$mod = isset($_REQUEST['mod']) ? $_REQUEST['mod'] :0;控制

上述代码对文件上传的验证是检测其上传的mime类型是否是图片的,不检查文件名后缀

因此我们便可以便可以伪造mime类型上传任意文件了

伪造请求体如下:

image-20240824202942960

访问该文件

image-20240824203033526