嗨,朋友你好,我是闪石星曜CyberSecurity创始人Power7089。
今天为大家带来PHP代码审计基础系列文章第三篇之命令执行篇。
这是【炼石计划@PHP代码审计】知识星球第二阶段的原创基础系列文章,拿出部分课程分享给零基础的朋友学习。本系列原创基础文章涵盖了PHP代码审计中常见的十余种WEB漏洞,是匹夫老师精心的创作,欢迎关注我的公众号跟着一起学习。
【炼石计划@PHP代码审计】是一个系统化从入门到提升学习PHP代码审计的成长型知识星球。这里不仅注重夯实基础,更加专注实战进阶。强烈推荐加入我们,一起来实战提升PHP代码审计。
进入正文
通过调用PHP中命令执行函数,且函数中的参数可控就会造成命令执行。以Web中一句话木马为例,常见的PHP一句话木马<?php system($_REQUEST['value']); ?>
,这里通过system()
函数将前端传入的值当做系统命令执行,其中value
参数由前端传入。
cmd.php
下面示例代码将前端传入的value
参数值带到system()
命令执行函数中去执行,值得注意的是system()
函数自带回显,不用使用echo
或者var_dump()
进行输出。
<?php
$sys = $_REQUEST['value'];
$cmd = system($sys);
?>
value
传入calc.exe
即可调用system()
函数弹出计算器。
exec()
、shell_exec()
、system()
、popen()
、passthru()
、proc_open()
、pcntl_exec()
、 反引号``实际上是使用shell_exec()函数。
该函数无回显需使用echo
进行输出,且只返回执行后的最后一行结果。
示例代码:
<?php
$sys = $_REQUEST['value'];
$cmd = exec($sys);
echo $cmd;
?>
我们执行ipconfig
只返回了结果中最后一行结果
执行whoami
结果将不受影响,因为返回结果只有一行
该函数无回显需使用echo
或者var_dump
进行输出,但返回结果所有内容。
示例代码:
<?php
$sys = $_REQUEST['value'];
$cmd = shell_exec($sys);
var_dump( $cmd);
?>
我们传入系统命令ipconfig
则会输出所有结果
反引号其实调用的是shell_exec()函数,当反引号中的变量可控时就会造成命令执行,且无回显。
示例代码:
<?php
$sys = $_REQUEST['value'];
$cmd = `$sys`;
echo $cmd;
?>
我们传入系统命令ipconfig
则会输出所有结果
该函数会将输入的参数当做命令执行,有回显且返回所有内容。在实战中也是最常见的造成命令执行漏洞的函数之一。
这里注意:如果目标是LInux则执行Bash
命令,如果是Windows则执行cmd
命令。
该函数与上述system()
函数类似,也可将输入的参数当做命令执行,且函数执行后有回显。
示例代码:
<?php
$sys = $_REQUEST['value'];
$cmd = passthru($sys);
?>
我们传入系统命令dir
则会输出所有结果
该函数通常用于打开进程文件指针,但如果传入的参数可控也可造成命令执行,且该函数无回显,通过echo
不回直接返回执行的结果,而是返回的是文件指针。
示例代码:
<?php
$sys = $_REQUEST['value'];
$cmd = popen($sys,'r');
var_dump($cmd); ;
?>
这里调用我们的popen()
函数执行calc.exe打开了计算器。
执行一个命令,并且打开用来输入/输出的文件指针。 类似 popen()
函数,但是 proc_open()
所需参数更多,且处理数据能力更强。
在很多IoT设备如路由器中会存在如下类似的代码,本来设计的功能点是测试网络通信情况,但由于传入的参数没有进行严格的过滤就传入到命令执行函数中,最终导致命令执行。
ping.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>系统命令执行demo</title>
<meta name="keywords" content="" />
<meta name="description" content="" />
</head>
<body>
<div id="main">
<div class="title">Ping功能测试</div>
<form action="ping.php" method="post" onsubmit="return enter()">
<label><input class="text" type="text" placeholder="请输入IP地址" name="ip" /></label>
<label><input class="submit" type="submit" name="submit" value="测试" /></label>
</form>
</div>
</body>
</html>
ping.php
<?php
header("content-type:text/html;charset=gbk");
if(isset($_POST['submit'])){
$target = $_REQUEST['ip'];
//php_uname()判断当前操作系统是否为Windows NT
if(stristr(php_uname('s'),'Windows NT')){
$cmd = shell_exec('ping '.$target);
echo '<pre>'.$cmd.'<pre>';
}else{
$cmd = shell_exec('ping -c 3 '.$target);
echo '<pre>'.$cmd.'<pre>';
}
}
我们使用|
来分割前面的ping
命令,将我们的ipconfig
命令单独分割出来造成命令执行。
由于|
会直接执行后面的命令,所以直接输出了ipconfig
的内容。
常见管道符
由于Linux和Windows中命令执行的方式不同,Linux中执行的是bash
命令,而Windows执行的是cmd
命令。常见的管道符如下:
Windows:
| 直接执行后面的语句
|| 如果前面执行的语句出错,那么才执行后面的语句
& 前面和后面的语句都会被执行
&& 前面语句出错后面的语句也不执行,只有前面的语句成功执行才执行后面的语句
Linux:
Linux中除了上面的管道符外还有一个;
; 前面的语句执行完成后,继续执行后面的语句。
这些管道符大家可以可以在cmd命令行或者bash命令行进行测试,一般情况下如果在命令行中可以成功执行的话,在真实的业务系统也是可以执行的。
在PHP中还有很多函数可以造成命令执行,但在代码审计中常见的命令执行危险函数已经给大家列出,大家在PHP代码审计中只要多留意这些函数且该函数的参数是可以被我们所控制,这是命令执行漏洞存在的关键。下部分会讲PHP中的代码执行函数,其实命令执行和代码执行都是一样的,命令执行可以通过调用代码执行的函数实现代码执行,代码执行也可以通过调用命令执行的函数来实现命令执行。
往期回顾
【第一篇】PHP代码审计之WEB安全系列基础文章(一)之SQL注入漏洞篇
【第二篇】PHP代码审计之WEB安全系列基础文章(二)之任意文件上传漏洞篇
注意
后台回复以下关键字即可获取对应学习资料!
【navicat15】SQL注入篇用到的Navicat 15 即破解教程
【PHP代审录屏】往期PHP代码审计直播课
【0531】往期PHP代码审计直播课
【文件上传演示代码】获取文件上传篇涉及的案例代码