• 文件上传及CSRF+Selfxss


    文件上传

    • 文件上传,顾名思义就是上传文件的功能行为,网站中可以上传文件是非常正常的功能,如上传头像、图片和文件等。之所以会被发展为危害严重的漏洞,是程序没有对访客提交的文件数据进行检验或者过滤不严,使得hacker将webshell上传到服务器中,之后就可以在服务器上执行恶意代码,进行数据库执行、服务器文件管理,服务器命令执行等恶意操作。

    漏洞成因

    • 服务端没有对访客或用户提交的文件数据进行检验或者过滤不严

    绕过方式

    • upload-labs靶场中,我们可以查看服务端是如何对文件数据进行检验的
    $is_upload = false;
    $msg = null;
    if (isset($_POST['submit'])) {
        if (file_exists($UPLOAD_ADDR)) {   // $UPLOAD_ADDR 为存储上传文件的文件夹,需提前创建
            $deny_ext = array('.asp','.aspx','.php','.jsp');  // 采用黑名单,上传文件的后缀名不能名单中的后缀
            $file_name = trim($_FILES['upload_file']['name']);  // 获取上传文件名,并删除两端的空白符
            $file_name = deldot($file_name);  // 删除文件名末尾的点 deldot为upload-labs的自定义函数
            $file_ext = strrchr($file_name, '.');  // 截取文件名中.及.以后的字符
            $file_ext = strtolower($file_ext);  //转换为小写
            $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
            $file_ext = trim($file_ext); //收尾去空,最终文件后缀
    
            if(!in_array($file_ext, $deny_ext)) {  // 判断文件后缀是否在白名单中
                if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR. '/' . $_FILES['upload_file']['name'])) { // 将上传的文件从临时位置移动到目的文件夹中
                     $img_path = $UPLOAD_ADDR .'/'. $_FILES['upload_file']['name'];
                     $is_upload = true;
                }
            } else {
                $msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';
            }
        } else {
            $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    trim( string $str ):去除字符串首尾处的空白字符(或者其他字符)
    strrchr( string $haystack, mixed $needle) :返回 字符串中以 needle 的最后的出现位置开始,直到字符串末尾。
    strtolower( string $string):将字符串转化为小写,类似的还有strtoupper() ,将字符串转化为大写、ucfirst():将字符串的首字母转换为大写
    str_ireplace(mixed $search, mixed $replace, mixed $subject ),函数返回一个字符串或者数组。该字符串或数组是将 subject 中全部的 search 都被 replace 替换(忽略大小写)之后的结果。

    • 上传图片时,浏览器发送的包格式如下:
      在这里插入图片描述
    • 服务端收到数据后,首先获取文件名,也就是2.jpg,然后就是对改文件名进行一系列的校验
    • 删除两端的空白符:因为在windows下,如果文件名末尾为空白符,会忽略;如果我们上传一个名为shell.php 的木马,在php程序判断时文件后缀为:.php ,如果服务端又采取的是黑名单限制,.php 很有可能就让绕过了黑名单,进入操作系统。
    • 删除文件末尾的点:同样在windows下,如果文件名末尾为.,会忽略;如果我们上传一个名为shell.php.的木马,php截取后缀是按照点最后的位置进行截取的,所以得到的结果为.,如果服务端又采取的是黑名单限制,同样很有可能绕过限制
    • 转换为小写:如果校验后缀采取的不是正则且忽略大小写 ,且还是黑名单限制,可能绕过限制,由于windows大小写不敏感,.Php=.php
    • 去除字符串::$DATA:在window的时候如果文件名+::$DATA会把::$DATA之后的数据当成文件流处理,不会检测后缀名,且保持::$DATA之前的文件名
    • 最后再次删除两端的空白符,是为了防止上传的文件名是shell.php . 的形式
    • 上述代码中采用黑名单限制,仅仅限制了'.asp','.aspx','.php','.jsp'后缀,如果在apache下开启了如下配置,服务端会将php3、phtml等文件名当php文件执行
      在这里插入图片描述
    • 对于黑名单限制,还有一种绕过方式,就是上传一个.htaccess文件,该文件提供了针对目录改变配置的方法,在.htaccess文件中添加如下内容并上传,该配置的意思是将文件名字含有png的文件都当作php文件处理
    <FilesMatch "png">  
    SetHandler application/x-httpd-php
    </FilesMatch>
    
    • 1
    • 2
    • 3
    • 由于黑名单很容易被绕过,所以推荐白名单限制上传文件的后缀,如只允许上传.png、.jpg、.gif后缀的文件,不仅要检查文件名,文件内容(文件类型感觉没什么用)
    • 如果只使用白名单限制文件名,可以上传图片马,就是在图片中插入木马语句,不过上传的图片马还需要一个文件包含漏洞才可以发挥作用
    • 在cmd下输入如下命令,就可将图片和木马文件拼接在一起
    copy 图片.jpg/b + 木马.php/a 木马.jpg 
    
    • 1
    • 服务端可以使用imagecreatefromjpeg(图片)对上传的图片进行处理,该函数会创建一个新图像,虽然该图像表面看起来没变化,但内部的结构已经被打乱,即使图片中有木马语句,也很有可能因为重新排列而消失

    案例

    • 前端上传文件页面主要代码:
    <body>
        <form method="post" action="upload.php" enctype="multipart/form-data">
            <input type="file" name="file" value=""/>
            <input type="submit" name="submit" value="upload"/>
        form>
    body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • upload_1.php代码,本案例中允许上传的文件后缀为.png、.jpg、.gif、.zip
    extract(PCLZIP_OPT_PATH, $temp_dir, PCLZIP_OPT_REPLACE_NEWER) == 0) {  
        	 // 将zip文件解压到用户目录下,如果文件重名则覆盖
                exit("解压失败");
            }
            check_dir($temp_dir);  // 检查用户目录下的文件
            exit('上传成功!');
        } else {
            move_uploaded_file($file['tmp_name'], $temp_dir . '/' . $file['name']);
            check_dir($temp_dir);
            exit('上传成功!');
        }
    }else {
        exit('仅允许上传zip、jpg、gif、png文件!');
    }
    
    
    • 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
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 代码中可以看到限制了文件后缀,但允许上传压缩文件,先上传一个包含web.php的压缩包测试
      在这里插入图片描述

    • 查看本地目录,发现只剩下了图片,php文件被删除
      在这里插入图片描述

    • 审计代码,发现函数check_file只检查了目录下的文件,那上传一个目录会怎么样
      在这里插入图片描述

    • 警告如下,应该是因为我们上传的目录2没有后缀,所以报错,可以将目录命名为2.png,这样就不会报错了
      在这里插入图片描述在这里插入图片描述

    • 查看结果,果然上传成功

    • check_dir函数进行完善,先判断是否是目录,如果是,递归删除

    function check_dir($dir){
        $handle = opendir($dir);
        while(($f = readdir($handle)) !== false){
            if(!in_array($f, array('.', '..'))){
                if(is_dir($dir.$f)){
                    check_dir($dir.$f.'/');
                 }else{
                    $ext = strtolower(substr(strrchr($f, '.'), 1));
                    if(!in_array($ext, array('jpg', 'gif', 'png'))){
                        unlink($dir.$f);
                    }
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 这下我们该如何绕过呢?,从代码中可以发现,服务端是首先将压缩文件解压到用户目录下,然后进行判断删除,那我们可以通过时间竞争,在解压完但删除前执行文件,构造木马文件web.php如下:
     file_put_contents("../shell.php","");?>
    
    • 1
    • 执行该文件,在上级目录下生成一个木马文件(这就使用phpinfo()进行测试),由于check_dir会检查当前目录下所有的文件,所以将木马文件放到上级目录,防止被删
      在这里插入图片描述
    • 这里我是用burpsiteintruter模块持续的进行上传文件和访问上传的web.php文件,但我在测试用发现,我使用burpsite上传压缩包时,会改变压缩包的内容,导致服务端解压失败,于是,我只使用burp爆破web.php文件,我通过重发器手动上传压缩文件
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
    • 一次没有成功,就多试几次
      在这里插入图片描述
      在这里插入图片描述
    • 由于多次上传的文件名相同导致时间竞争漏洞,于是修复源码:每次生成一个随机目录存放数据
    $temp_dir = $dir.md5(time(). rand(1000,9999)).'/';
    
    • 1
    • 这次又该如何绕过呢?依然是审计源码,发现压缩文件解压失败就会退出程序,那有没有一种方法使得解压失败,但里面的文件依然被解压出来
    • 这个问题其实需要看具体情况,看解压的那个程序的容忍程度。先看一下我使用的360压缩,测试发现360压缩的容忍度很低,只要压缩包中某一个文件的CRC校验码出错,就会报错退出。使用010editor打开压缩包并修改
      在这里插入图片描述
    • 由于18.png的Crc错误,导致解压失败,但web.php依然解压成功
      在这里插入图片描述
    • 我们再用PHP自带的ZipArchive库测试这个zip,修改源代码的解压部分,使用ZipArchive进行解压
        if ($ext == 'zip') {
        	$zip = new ZipArchive;
            if(!$zip->open($file['tmp_name'])) {
                echo "fail";
                return false;
            }
            if(!$zip->extractTo($temp_dir)) {
                exit("fail to extract");
            }
            check_dir($temp_dir);
            exit('上传成功!');
        } else {
            move_uploaded_file($file['tmp_name'], $temp_dir . '/' . $file['name']);
            check_dir($temp_dir);
            exit('上传成功!');
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 发现解压并没有出错,这也说明ZipArchive的容忍度比较高。

    • 又如何让ZipArchive出错呢?最简单的方法,我们可以在文件名上下功夫。比如,Windows下不允许文件名中包含冒号(:)我们就可以在010editor中将18.png的deFileName属性的值改成“18.pn:”。
      在这里插入图片描述

    • 上传测试,页面报错,查看存储目录,成功
      在这里插入图片描述
      在这里插入图片描述

    总结

    • 在本案例中,三次修改源码,但依然都被绕过,这是因为没有搞清楚漏洞的原理,本案例就是因为压缩文件直接解压到了用户可以访问到的目录下,使用户可能访问到解压后的文件,应该先将解压后的文件存储到临时目录下,经过判断后,在移放到用户目录下,或者不给予用户目录执行权限

    CSRF

    • 跨站请求伪造:(Cross-site request forgery),缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。
      在这里插入图片描述

    例子

    • 假如一家银行用以运行转账操作的URL地址如下:http://www.examplebank.com/withdrawaccount=AccoutName&amount=1000&for=PayeeName
    • 那么,一个恶意攻击者可以在另一个网站上放置如下代码:
    • 如果有账户名为Alice的用户访问了恶意站点,而她之前刚访问过银行不久,登录信息尚未过期,那么她就会损失1000资金。

    CSRF+SelfXSS

    • 在DVWA中,有一个反射性XSS漏洞,将难度调为low后,输入执行我们写入的js代码
      在这里插入图片描述
    • 使用开发工具查看该表单,在结合提交数据后页面的URL
      在这里插入图片描述
    • 可以想到这里可以有CSRF漏洞,我们可以构造一个表单放在我们的服务器上,提交地址为DVWA靶场的反射型xss页面,内容为注入的XSS代码,以获取访问用户的cookie
    • 靶场环境

    DVWA(Win),DVWA靶场服务器,也是用户所在,IP地址为:192.168.204.1
    Beef(Kali):,获取cookie的xss平台,同时存放构造的而已表单,IP地址为:192.168.204.12

    • 首先构造一个恶意表单,可以通过CSRFTester 工具自动生成,受害者打开该 POC 后,浏览器会自动执行代码随后跳转到正常页面,中途不需要用户交互。

    • 设置浏览器的代理服务器为127.0.0.1:8008,我所使用的浏览器为Firefox
      在这里插入图片描述

    • 开启 CSRFTester 的流量记录功能。之后 CSRFTester 就会抓取到输入name的数据包,一般 CSRFTester 还会记录其他流量,所以直接右击将不相关的流量进行删除即可,只保留我们需要的流量
      在这里插入图片描述

    • 开启beef-XSS,在DVWA中输入name, 让CSRFTester 就会抓取到输入name的数据包,并生成表单
      在这里插入图片描述
      在这里插入图片描述

    • 查看生成的表单,我修改了form的action,input的value修改为
      在这里插入图片描述

    • 将表单放在kali服务器上,并生成一个访问表单的短链接,生成短链接的网址https://www.s-3.cn/

    • 在这里插入图片描述

    • 在这里插入图片描述

    • 由于我在生成表单的时候提交了一次,先清除kali的beef-xss记录
      在这里插入图片描述

    • 然后在win下访问生成的短链接
      在这里插入图片描述
      在这里插入图片描述

    • beef 中就能看到上线的主机了
      在这里插入图片描述

    修复

    • CSRF 攻击之所以能够成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于 cookie 中,因此黑客可以在不知道这些验证信息的情况下直接利用用户自己的 cookie 来通过安全验证。要抵御 CSRF,关键在于在请求中放入黑客所不能伪造的信息,并且该信息不存在于 cookie 之中。可以在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。
  • 相关阅读:
    [计算机提升] Windows系统软件:娱乐类
    人工智能监考 VS 传统方式监考,你更喜欢哪一种?
    数据库系统课设——基于python+pyqt5+mysql的酒店管理系统(可直接运行)--GUI编程(2)
    前端必须知道的调试工具
    【PAT甲级 - C++题解】1054 The Dominant Color
    MCE | HIV 衣壳蛋白有望成为 HIV 治疗新靶标
    【Java面试指北】Exception Error Throwable 你分得清么?
    【Azure 应用服务】本地创建Azure Function Kafka Trigger 函数和Kafka output的HTTP Trigger函数实验
    百度飞桨公布最新成果:凝聚535万开发者,服务20万家企事业单位
    Hive 和 HDFS、MySQL 之间的关系
  • 原文地址:https://blog.csdn.net/qq_57686163/article/details/126342546