原文 https://www.yuque.com/ni4n/blogs/zpw349

漏洞原理

代码执行漏洞是指应用程序在调用“把字符串作为PHP代码执行”的函数时未对用户的传参严格过滤,致使用户可以将代码注入应用程序执行。

代码执行漏洞形成原因大概有以下几种:

  • eval()和assert()函数
  • preg_replace()函数
  • 调用函数过滤不严
  • 动态函数执行

eval()和assert()函数

函数解释

  1. eval ( string $code )
  2. 把字符串 code 作为PHP代码执行。
  3. assert( mixed $assertion )
  4. 参数需是函数或者表达式,才会执行

示例:

eval()

  1. <?php
  2. if (isset($_GET['cmd'])){
  3. eval($_GET['cmd']); //未对参数进行过滤
  4. }
  5. ?>
  6. //payload:?cmd=phpinfo();

assert()

  1. <?php
  2. assert('phpinfo()');
  3. ?>

preg_replace()函数

函数解释

  1. preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
  2. //搜索$subject的$pattern部分,以$replacement替换掉$pattern;但当$pattern处,即第一个参数存在e修饰符时,$replacement的值会被当成php代码执行;但前提是匹配到$pattern
  3. //但是在高版本中已经不行了

示例1:

  1. <?php
  2. $subject="hello hack";
  3. $pattern='/hack/e';
  4. $replacement=$_GET["name"];
  5. echo preg_replace($pattern,$replacement,$subject)
  6. ?>
  7. //payload:?name=phpinfo()

这是个简单的构造,然后在看个稍微复杂的

示例2:

  1. <?php
  2. preg_replace("/\[(.*)\]/e", '\\1', $_GET['str']);
  3. ?>
  4. "\1"表示重复正则第一个圆括号内匹配到的内容
  5. 当我们传入[phpinfo()]时,$replacement="phpinfo()" 然后执行phpinfo()
  6. //payload:?str=[phpinfo()]

然后说一下修饰符

PHP代码审计之代码执行(转载) - 图1

调用函数过滤不严

在php中,有很多可以调用其他函数的函数;如call_user_func()和array_map()等,以一个参数为要调用的函数,其他的为要调用函数的参数;当其传入的函数名可控,就可以调用任意函数,执行任意代码。

call_user_func()

  1. <?php
  2. $cmd=$_GET['cmd'];
  3. $var=$_GET['var'];
  4. call_user_func($cmd,$var);
  5. ?>
  6. //payload:?cmd=assert&var=phpinfo()

函数解释

  1. call_user_func ( callable $callback [, mixed $parameter [, mixed $... ]] )
  2. 第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数。

动态函数执行

直接看示例吧

  1. <?php
  2. $_GET['a']($_GET['b']);
  3. ?>
  4. //payload:?a=assert&b=phpinfo()

其意思就是接受GET请求的a参数,作为函数,b参数作为函数的参数。和call_user_func()有点相似。

漏洞修复

使用白名单过滤机制,严格控制用户传入的参数。