lctf babyphp's revenge
php中session反序列化机制
简介
session中有关序列化配置:
session.serialize_handler=php 表明session的默认序列话引擎使用的是php序列话引擎 |
session.serialize_handler
是用来设置session的序列话引擎的,除了默认的PHP引擎之外,还存在其他引擎,不同的引擎所对应的session的存储方式不相同。
php_binary:存储方式是,键名的长度对应的ASCII字符+键名+经过serialize()函数序列化处理的值
例:
names:6:"spoock";
name|s:6:"spoock";
其中name是键值,s:6:”spoock”是反序列化的结果php:存储方式是,键名+竖线+经过serialize()函数序列处理的值
例:a:1:{s:4:"name";s:6:"spoock"}
对一整个name=spoock进行序列化存储php_serialize(php>5.5.4):存储方式是,经过serialize()函数序列化处理的值
例:
name|s:6:"spoock";
其中name是键值,s:6:”spoock”是反序列化的结果
在PHP中默认使用的是PHP引擎,如果要修改为其他的引擎,只需要添加代码ini_set('session.serialize_handler', '需要设置的引擎');
。示例代码如下:
<?php |
存储机制
php中的session内容并不是放在内存中的,而是以文件的方式来存储的,存储方式就是由配置项session.save_handler
来进行确定的,默认是以文件的方式存储。
session反序列化利用
session序列化的危害主要来自于不同存储引擎的解析存储方法不同,如果对同一组输入值进行不同的解析方式,那么就会产生风险。
例:
$_SESSION['ryat'] = '|O:11:"PeopleClass":0:{}'; |
上述session使用的是php_serialize,所以最后的存储内容是
a:1:{s:6:"spoock";s:24:"|O:11:"PeopleClass":0:{}";} |
但是如果我们在读取的过程中选择PHP,那么就会变成
array (size=1) |
也就是PeopClass这个类也会在反序列化读取中被执行
这是因为当使用php引擎的时候,php引擎会以**|**作为作为key和value的分隔符,那么就会将a:1:{s:6:"spoock";s:24:"
作为SESSION的key,将O:11:"PeopleClass":0:{}
作为value,然后进行反序列化,最后就会得到PeopleClas这个类。
这种由于序列化和反序列化所使用的不一样的引擎就是造成PHP Session序列话漏洞的原因。
lctf-bestphp’s revenge
SOAP简介
SOAP(Simple Object Access Protocol)是一种在 web service 通信时所用的基于 xml 的协议。
可以用来修改报文,以及修改访问的目标的ip
https://wooyun.js.org/drops/Trying%20to%20hack%20Redis%20via%20HTTP%20requests.html
看题目:
flag.php
only localhost can get flag!session_start(); |
他需要loalhost访问,那基本是SSRF的题目了,接下来就寻找一下如何突破:
|
我们可以看到这里输出的唯一内容是session,所以我们需要从session进行入手。
session通过修改存储机制可以进行反序列化:
而session正好有可以修改配置文件的函数
session_start()
eg:
|
通过调用soapclient类就可以实现修改访问的ip了
soapclient内置类的开启需要在php.ini中进行配置
接下来就是构造payload,先通过一个简单的实例,通过构造这样的一个类,可以实现发送到服务端地址的改变:
这是php手册中关于soapclient类的construct构造的定义
https://www.php.net/manual/zh/soapclient.construct.php
如果在 WSDL 模式下工作,则此参数是可选的。如果在非 WSDL 模式下工作,则必须设置location和 uri选项,其中location 是将请求发送到的 SOAP 服务器的 URL,是 SOAP 服务uri 的目标名称空间。 |
|
好的基本信息大概都清楚了,接下来就是如何利用题目中的函数实现,首先我们先用php_serialize存储机制存入SoapClient,首先构造一下我们需要反序列化的soap类,
|
call_user_func()把第一个参数作为回调函数调用,其他参数是回调函数的参数 |
成功写入
接下里进行改内容的反序列化调用,由于soap的ssrf是需要调用_call方法的,所以这里我们要想想如何调用什么不存在的类和方法=-=,可想而知 就是这里的welcome_to…..,具体的运作逻辑如下
几个函数补充了解一下:
题目中接下来的代码运作是:首先reset将数组的内部指针指向第一个单元也就是SoapClient,然后将welcome_..也合并在这个数组当中
最后再使用implode将这个数组转化为字符串,但其中都没有触发过这个soap的__call方法
这里我们可以将变量b覆盖为call_user_func,令其在最后调用执行SoapClient,但是传入的b会被写入为数组形式,所以我们还需要一个函数将其释放出来,就是extract()
它的主要作用是将数组展开,键名作为变量名,元素值为变量值
所以payload如下:
访问session=1(刚刚设置的)
小结:
1.session反序列化机制主要是利用session存储机制不同所造成的的漏洞
2.判别标准是:session是否开启,session_start函数是否可以被调用,是否存在多余参数可以用来控制session_handler。
3.可以利用soap内置类实现ssrf
1'ununionion selselectect '<?php eval($_POST[a]);?>' INintoTO OUToutfileFILE '/var/www/html/1.php'# |
lctf babyphp's revenge