所谓代码审计是一种以发现程序错误,安全漏洞和违反程序规范为目标的源代码分析。在安全领域,为了发现安全问题,常通过黑盒测试、白盒测试方法来尽可能的发现业务程序中的安全问题,代码审计就是白盒测试的常用方法,相较于黑盒测试,由于白盒测试能接触到源代码,可以更加详细的理解业务程序逻辑,也能更全面的发现安全风险。接下来本系列文章将以php代码审计为切入点,过程中结合常见源代码扫描工具和动态调试方法,来讲解php代码审计的常见漏洞点和分析方法。本章节将介绍PHP对象注入漏洞的原理,便于研究后续相关漏洞的审计。
其中__destruct()被称为析构函数,会在对象的所有引用或者当对象被显式销毁的时候执行。由于在实际应用程序中,一个对象在实例化完成后必然会被销毁,因此只要该对象存在__destruct()方法,则该对象在创建销毁过程中就必然会被调用。而__construct()恰恰与__destruct()相反,是指在对象被创建的时候被调用。
__toString()方法:是指当一个类对象被当成字符串操作时,自动会调用该函数。比如echo某个类或者拼接该类值。
__sleep():在一个对象被序列化的时候调用
__wakeup():在一个对象被反序列化的时候调用
在挖掘PHP对象注入漏洞的时候,一定要关注上述魔术方法,接下来我们简单测试一下魔术方法的实际作用。
首先我们先生成一个序列化后的类对象
得到序列化后的对象为:O:4:"test":2:{s:8:"username";s:5:"admin";s:8:"password";s:6:"passwd";}。
接下来我们就可以设计多个场景,如在对象被销毁时自动触发__construct()方法,在对象被反序列化时自动触发__wakeup()方法以及在对象被当成字符串进行处理时调用__toString()方法。
在对象被销毁时自动触发__construct()方法如下
我们传入的参数a就是上面生成的序列化数据
可以看到,自定义的序列化数据成功替换了默认的username和password的参数值,且在反序列化函数unserialize处理完后自动调用对象销毁方法__construct()。如果反序列函数处理的数据是用户输入的数据,且__construct()函数内容存在危险执行逻辑,就容易产生对象注入并任意命令执行。
同理当生成对象的时候,就会先后执行__construct()和__destruct()方法
当调用$b = new test();时,会调用该类的方法__construct()。对$b赋值完成后,会调用该类的方法__destruct()。
这里我们在网页请求a=admin时,执行结果如下图
当我们把类当成字符串去处理的时候,就会调用__toString方法,如下所示
执行效果如图所示,__toString()成功被调用。
因此针对PHP对象注入,要注意判断在对象创建或销毁的时候,是否引入了外部用户输入的参数。一旦引入,用户输入就能够构造部分有缺陷类,并执行相关函数。比如在thinkphp中,其中有一条比较有名的调用链就是__toString(),当调用__toString()方法时将会造成任意命令执行。如thinkphp5.1.X 反序列化漏洞利用链就是通过__toString方法触发的。
原文始发于微信公众号(第59号):php代码审计之PHP对象注入
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论