手机版

PHP中对象注入的深入讲解

时间:2021-09-05 来源:互联网 编辑:宝哥软件园 浏览:

虽然这篇文章被称为PHP对象注入,但它本质上与PHP序列化的不当使用有关。如果您阅读了PHP中的SESSION反序列化机制,您将对序列化有一个大致的了解。实际上,PHP对象注入本质上是由序列化引起的。

基础知识

php类中可能有一些叫做magic functions的神奇函数,当类中发生某些事件时会自动触发。例如,创建对象时调用__construct(),销毁对象时调用_ _ destroy(),将对象视为字符串时调用__toString。常见的魔法函数有__construct()、_ _ destroy()、__toString()、__sleep()、_ _唤醒()。

例子如下:

?phpclass测试{ public $ varr1=' abcpublic $ varr2=' 123公共函数echoP(){ echo $this-varr1。br ';} public function _ _ construct(){ echo ' _ _ construct br ';} public function _ _ destrust(){ echo ' _ _ destrust br ';} public function _ _ toString(){ return ' _ _ toString br ';} public function _ _ sleep(){ echo ' _ _ sleep br ';返回数组(' varr1 ',' var R2 ');} public function _ _ wake up(){ echo ' _ _ wake up br ';} } $ obj=new test();//实例化对象,调用__construct()方法,输出_ _ construct $ obj-echoP();//调用echoP()方法并输出‘ABC’EcHo $ obj;//obj对象输出为字符串,调用__toString()方法,输出_ _ toString $ s=serialize($ obj);//obj对象被序列化,调用__sleep()方法并输出_ _ sleep echo unserialize($ s);//$s将首先被反序列化,并将调用__wake()方法。如果反序列化的对象被视为字符串,将调用_toString()方法。//脚本结束后会调用_ _ destroy()方法,输出_ _ destroy?原则

为什么要用顺序词?主要是为了方便数据传输,数据恢复后,数据的属性不会改变。例如,在反序列化一个对象之后,该对象的所有信息仍然被保存。同时,序列化的值可以保存在文件中,这样就可以直接从文件中读取数据,然后在需要时反序列化。序列化()和非序列化()在PHP中用于序列化和反序列化。

序列化的危害在于,如果序列化的内容是用户可控的,那么用户可以注入精心构造的有效载荷。序列化时,有可能在对象中启动一些神奇的方法,造成意想不到的伤害。

对象注入

本质上serialize()和serialize()在PHP内部实现上没有漏洞,漏洞主要是应用程序对对象、魔法函数的处理以及序列化相关问题造成的。

如果一个类用于将日志临时存储到程序中的一个文件中,当调用_ _ _ destruct()方法时,日志文件将被删除。

代码大致如下:

logfile.php

?phpclass LogClass { public $ Logfilename=' ';公共函数log data($ text){ echo ' log data }。$文本。br/';FILE _ put _ contents($ this-log filename,$text,FILE _ apped);} public function _ _ destrust(){ echo ' deletes }。$ this-log filename;取消链接(dirname(__FILE__)。'/'.$ this-log filename);}}?在其他类中使用日志类

logLogin.php

?phpinclude ' index.php$ obj=new LogClass();$ obj-log filename=' log in . log ';$obj-logdata('日志');上面的代码是使用LogClass类进行日志记录的正常功能。

下面是一个带有对象注入漏洞的使用示例。

news.php

?phpinclude ' logfile.php//某些代码使用LogClassClass User { public $ age=0;public $ name=公共函数print_data() { echo 'User '。$这个名字。是。$这个年龄。年old.br/'; } }//从用户接受输入序列化为用户对象$usr=未序列化($ _ GET[' User ']);上面显示的代码使用了日志类对象,并且还接受来自用户的输入,用于序列化和转换为用户对象。

当我们提交以下数据时,

news.php?用户=O:4: '用户' :2:{s:3: '年龄';i:20s:4:“名称”;s:4:约翰’;}这种语句可以正常使用,也是程序员想用的方法。

但是,如果提交的数据是:

news.php?user=o :8: ' LogClass ' :1: { s :11: ' log filename ';s 33609:’。htaccess ';}然后删除。最终将输出htaccess。

可以看到,由构造的数据导致LogClass中的_ _ _ destruct()方法被执行,然后网站中的重要配置文件被删除。

从上面的例子可以看出,如果不严格控制用户的输入,同时反序列化用户的输入,可能会实现代码执行的漏洞。

倾析点

PHP对象注入一般在程序逻辑之上。例如,一个User类定义了__toString()用于打印格式,但是还有一个file类定义了__toString()方法来读取File内容然后显示,因此攻击者有可能通过反序列化User类来构造一个File类来读取网站的配置文件。

user.php

?phpclass FileClass { public $ filename=' error . log ';公共函数_ _ tostring(){ echo ' filename changed=='。$ this-文件名;返回@ file _ get _ contents($ this-filename);} } class UserClass { public $ age=0;public $ name=公共函数__toString() {返回“User”。$这个名字。是。$这个年龄。岁。br/';}}$obj=未序列化($ _ GET[' usr ']);回声$ obj//调用obj的__toString()方法?在正常情况下,我们应该传入一个由UserClass序列化的字符串,比如user.php?usr=O:9: ' UserClass ' :2: { s :3: ' age ';i:18s:4:“名称”;s:3:《汤姆》;},页面会输出用户Tom已经18岁了。

这也是一种理想的使用方法。

但是如果我们传入的数据是user.php呢?usr=O:9: ' File Class ' :1: { s :8: ' filename ';s 336010:“config . PHP”;},页面的最终输出是文件名已经更改==config.php,并且已经执行了FileClass中的__toString()方法。

这样,你就可以在config.php阅读源代码。

漏洞挖掘

这种洞一般很难挖。虽然显示看起来简单,但要求的条件实际上相当苛刻。而且,查找对象注入的漏洞一般是通过审计源代码来发现,看unserialize()的参数是否可控,是否有反序列化其他参数对象的可能。

保护

测试程序中的各种边界条件

避免用户对unserialize()参数可控,考虑使用json_decode方法传递参数。

摘要

以上就是本文的全部内容。希望本文的内容能给你的学习或工作带来一些帮助。有问题可以留言交流。谢谢你的支持。

版权声明:PHP中对象注入的深入讲解是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。