简述 FTP 入侵与防御 [ vsftpd ]

0x01 首先,我们先来简单思考下,当你面对一台 ftp 时,到底能做些什么

1
2
3
4
5
6
7
0day,抱歉,并不在今天的讨论范畴 ^_^
允许匿名可写,直接上传webshell,一般极小的个人站才有可能,ftp目录即网站目录
允许匿名下载,造成的敏感文件信息泄露
爆破,亦可造成敏感配置泄露
嗅探,搜集各种明文账号密码,然后再拿着这些账号密码,去撞目标的其它入口,或以此进行进一步的内网渗透
提权,linux平台下基本不可能
...

0x02 相对主流的一些ftp工具

1
vsftpd proftpd filezilla ...

0x03 深入理解ftp的主动与被动工作模式

命令连接

1
2
3
在客户端向ftp服务端发起连接请求时,客户端会随机选择本地的某个tcp端口与ftp服务端的21端口进行连接
这中间会进行一系列的身份验证过程,待验证通过后,客户端与ftp服务端即会成功建立 `命令连接`
所谓的 `命令传输连接` 也就是说,仅仅只会用这个连接来传输命令本身

主动模式

1
2
3
4
在 `命令连接` 建立成功后,客户端可能还需要进行一系列的数据传输动作,如,上传,下载文件...
此时,客户端会先在本地另启一个端口监听等待连接,并利用先前与ftp客户端建立好的`命令连接`通道,告诉ftp服务端客户端所监听的端口
而后,ftp服务端会利用自身的20端口和刚才ftp客户端所告知的端口进行数据连接,随后就开始利用此连接来进行各类数据传输
注意,此时`数据连接`在建立的过程中,是ftp服务端的20端口主动连接FTP客户端的随机端口的,也就是我们所说的`主动模式`

被动模式

1
2
3
4
5
6
依然是在成功建立`命令连接`之后,客户端需要进行文件上传下载...
与主动模式不同的是,此时,ftp客户端将通过`命令连接`通道告诉ftp服务端的并不是客户端本地的那个随机端口
而是会向服务端发出一个PASV指令,该指令的作用就是告诉ftp服务端,准备采用被动模式来建立连接
当ftp服务端采用被动模式来连接时,会先读取自己配置文件中事先设置好的那个端口范围
从中随机取出一个端口在服务端本地进行监听,而后再通过命令连接通道将ftp服务端本地监听的那个随机端口告给知客户端
最后,客户端则会在本地随机起一个端口与刚刚服务端监听的那个数据端口进行连接,而后即可进行正常的数据传输

如何选择主动与被动

1
2
3
4
在常规内网环境中,主动和被动模式的意义并不是非常大,但,如果你是直接给公网提供的ftp服务这个就稍微有意义了
主动模式,也就意味着`客户端本地的数据端口是随机的`,如果被客户端本地防火墙所限制则无法进行数据传输
被动模式,此时意味着`服务端的数据传输端口是随机的`,你需要在服务端的防火墙中放开对指定端口范围的限制,否则一样无法进行数据传输
相比之下,被动模式可能更适用于公网环境,了解即可,我们言归正传,如何部署一个安全的ftp服务

0x04 此次演示环境

1
2
RHEL6.6_i386 ip: 192.168.3.57
win7cn ip: 192.168.3.70

0x05 安装vsftpd 2.2.2,我这个版本已经比较旧了直接用的是iso 包里的提供的,建议大家尽量还是用新一点的版本,毕竟只是个ftp工具而已,大可不必像web那样,对每个版本选择都小心谨慎,用新一点的版本,也能在一定程度上帮大家避免一些已知高危漏洞,ftp的溢出还是非常非常多的,废话不多说,咱们真奔主题

1
2
3
# rpm -qa vsftpd
# yum install -y vsftpd
# mv /etc/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf.bak

0x06 详细配置 vsftpd,这里暂以配置虚拟用户登陆为主,关于匿名用户本地系统用户登陆配置,只做顺带说明,不做详述,另外,请务必注意,在配置vsftpd.conf时,每个选项前后都务必不能有空格,不然,你会发现,虽然重启服务看似没什么问题,但选项会一直不生效

下面是 vsftpd 自身配置的一些常用选项说明

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
28
29
30
31
32
33
34
# vi /etc/vsftpd/vsftpd.conf
ftpd_banner=Welcome klion's FTP server! # ftp服务端登陆欢迎信息
listen=YES # 以standalone模式运行vsftpd
listen_ipv6=NO # 禁用ipv6
listen_port=21 # 默认监听的命令连接端口,大多数情况下,我们其实都不需要改
tcp_wrappers=YES # 默认就是开启的,主要可以用它来限制ip访问,到/etc/hosts.allow中配置即可
idle_session_timeout=300 # 指定连接闲置时长,当闲置指定秒数后就自动断开连接
data_connection_timeout=150 # 指定数据连接超时时长,如果超过规定秒数数据连接还没建立就自动断开
ascii_upload_enable=NO # 禁止以文本格式传输数据,防止数据被破坏,虽然默认就是NO,但习惯性还是给上
ascii_download_enable=NO
write_enable=YES # 是否允许ftp用户写,如果想让他上传文件务必要能写才行
# 文件上传后的默认权限,为了不让其他人看,可以设为077,注意,这里只是ftp用户权限的unmsk跟系统权限的unmask没任何关系
local_umask=077
# 主要用来对ftp下的各个目录作用进行简要描述
# 使用方法很简单,只需在指定的ftp目录下创建.message文件,之后在里面写上具体的说明内容即可
# 这样每次只要用户进到该目录中就会自动读取该文件中的内容并提示给用户
dirmessage_enable=YES
# vsftpd日志设置
xferlog_enable=YES
xferlog_std_format=YES # 指定日志格式,使用默认的标准格式即可
xferlog_file=/var/log/vsftpd.log # vsftpd日志存放位置,这里默认只记录了上传下载的数据,并没有记录登陆状态
# 启用被控模式进行数据连接,vsftpd在此模式下会自动从此端口范围内随机选择一个进行监听
pasv_enable=YES
pasv_min_port=65200 # 指定数据连接端口最小为多少,端口尽量给高点
pasv_max_port=65410 # 指定数据连接端口最大为多少
max_clients=100 # 设置vsftpd最大并发连接数
max_per_ip=2 # 设置单个ip的最大连接数

0x07 允许匿名用户登陆的相关配置,此设配置极不安全,虽然配置简单,但绝不推荐,如果有实际需求,不如用http下载代替

1
2
3
4
5
6
7
8
anonymous_enable=NO # 是否启用匿名登陆
# 是否允许匿名用户上传文件,单单这样启用还是上传不了的
anon_upload_enable=NO
anon_mkdir_write_enable=NO # 是否允许匿名用户新建目录
anon_other_write_enable=NO # 是否允许匿名用户其它的写权限,比如,允许匿名用户删除目录或文件
anon_world_readable_only=YES # 允许匿名用户下载
anon_max_rate=10000 # 匿名用户最大的数据传输速度

匿名用户想上传文件的单独授权过程,默认vsftpd是以ftp的系统用户身份在运行,所以需要配合setfacl来进行单独授权才行

1
2
3
4
# ls -dl /var/ftp
# mkdir /var/ftp/upfiles
# setfacl -m u:ftp:rwx /var/ftp/upfiles
# getfacl /var/ftp/upfiles 此时就可以正常上传文件,创建目录了


0x08 允许本地系统用户登陆的相关配置,默认ftp用户登陆成功后都会进到自己的家目录下,如果配置不当,允许ftp用户随意切换到其它的系统目录下,很容易造成系统敏感信息泄露,极不安全,另外,大批量权限控制也比较繁琐,容易遗漏,不推荐用于实战

1
2
3
4
5
6
7
8
9
10
11
12
13
# vi /etc/vsftpd/vsftpd.conf
pam_service_name=vsftpd # 启用pam认证,其实默认就是启用的,否则本地是登陆不成功的
local_enable=YES # 启用本地用户登陆
# 禁止所有ftp用户访问其它的系统目录,尽可能把它严格控制在自己的家目录下,实际测试多次测试并未成功
chroot_local_user=YES
chroot_list_enable=NO
# useradd -s /sbin/nologin admin
# echo "admin" | passwd --stdin admin
# useradd -s /sbin/nologin sysadm
# echo "admin" | passwd --stdin sysadm

只让指定的ftp用户能访问到其它的系统目录

1
2
3
4
5
6
7
8
9
# vi /etc/vsftpd/vsftpd.conf
chroot_local_user=YES
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd.chroot_list
local_max_rate=10000 # 限制本地用户最大的数据传输速度
# 把所有能访问到其它系统目录的用户名都事先写到改文件中,每行对应一个用户名
# vi /etc/vsftpd.chroot_list
admin

0x09 基于虚拟用户登陆的相关配置,注意,虚拟用户不是系统账号,跟系统账号压根就没有任何关系,所有的ftp虚拟用户到最后统统都会被压缩映射为一个指定的低权限系统账户,我们在前面说nfs时也提到过权限压缩,这跟那其实是一个意思,实战中推荐以此方式来部署ftp

首先,创建虚拟用户口令文件,注意,奇数行是账号,偶数行为对应的密码,实际的密码务必要严格遵守密码复杂性要求,可千万不能像我下面这么干

1
2
3
4
5
# vi /etc/vsftpd/vsftpd_user.txt
webadmin
admin110
web
123456

其次,将上面创建的口令文件转换成系统识别的口令文件

1
2
3
# yum install db4 db4-utils -y
# rpm -qa | grep db4-utils
# db_load -T -t hash -f /etc/vsftpd/vsftpd_user.txt /etc/vsftpd/vsftpd_passwd.db

而后,再来修改vsftpd的PAM认证文件,将文件中的原有内容先全部注释掉,添加如下两句,其实,意思就是让它到这儿来读密码

1
2
3
# vi /etc/pam.d/vsftpd
auth required /lib/security/pam_userdb.so db=/etc/vsftpd/vsftpd_passwd
account required /lib/security/pam_userdb.so db=/etc/vsftpd/vsftpd_passwd

再者,创建好要映射到的系统用户并修改该用户默认的家目录权限

1
2
# useradd -d /home/ftpdata -s /sbin/nologin nosir
# chmod go+rx /home/ftpdata/

最后,到vsftpd.conf中去启用虚拟用户功能,并为每个虚拟用户单独赋予指定的ftp权限,个人认为这个权限并不是很彻底,算了,又不是军工级别,不必太过强求 ^_^

1
2
3
4
5
6
7
8
9
10
11
12
# vi /etc/vsftpd/vsftpd.conf
anonymous_enable=YES
local_enable=YES
write_enable=YES
anon_upload_enable=NO
anon_mkdir_write_enable=NO
chroot_local_user=YES
pam_service_name=vsftpd
guest_enable=YES
guest_username=nosir
user_config_dir=/etc/vsftpd/vusers_config

为不同的虚拟用户指定不同的ftp权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# mkdir /etc/vsftpd/vusers_config/
# cd /etc/vsftpd/vusers_config/
# touch web webadmin 此处的文件名务必和ftp用户同名
# vi /etc/vsftpd/vusers_config/web 让web用户能进行正常的上传下载,创建,删除...
local_root=/var/ftp/upfiles # 也可单独指定某个虚拟用户的根目录
anon_upload_enable=YES
anon_mkdir_write_enable=YES
anon_other_write_enable=YES
anon_world_readable_only=YES
# vi /etc/vsftpd/vusers_config/webadmin 让webadmin用户只能干看着
anon_upload_enable=NO
anon_mkdir_write_enable=NO
anon_other_write_enable=NO


0x10 在针对ftp的所有入侵中,除了各类RCE之外的首要危害就是默认数据全部使用明文传输,这也就直接导致了我们的账号密码,极易被入侵者捕获并深度利用,如下

1
# tcpdump -i eth0 -nn -XX -s 0 host 192.168.3.57 and tcp dst port 21

为了更好的解决上述问题,我们需要在vsftpd的数据外面再上加一层ssl,来暂时性对抗此类嗅探

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# ldd `which vsftpd`|grep ssl 检查当前的vsftpd是否支持ssl
# openssl req -new -x509 -nodes -out vsftpd.pem -keyout vsftpd.pem
# chmod 400 vsftpd.pem
# cp vsftpd.pem /etc/ssl/certs/
# vi /etc/vsftpd/vsftpd.conf
ssl_enable=YES
allow_anon_ssl=YES
force_local_data_ssl=YES
force_local_logins_ssl=YES
force_anon_logins_ssl=YES
force_anon_data_ssl=YES
ssl_tlsv1=YES
ssl_sslv2=NO
ssl_sslv3=NO
rsa_cert_file=/etc/ssl/certs/vsftpd.pem

重启vsftpd,让所有配置生效,并让vsftpd随系统自启动

1
2
# systemctl start vsftpd
# chkconfig vsftpd on

0x11 观察vsftpd的各种日志信息

1
2
# tail -f /var/log/secure 可自行写脚本来实时提取爆破ip,比较简单,这里就不多说了
# tail -f /var/log/vsftpd.log

0x12 勤于关注官方所发布的各类高危补丁,及时进行修补,vsftpd不比其它工具,漏洞是经常的,而且一般还都是可直接被远程利用的,所以,务必多留点儿心

小结:
    关于ftp安全,其实,差不多就这些了,只要时刻记住不要让客户端直接以本地系统用户身份来登陆操作,让ftp服务始终运行在一个较低的系统权限下,禁止匿名或者禁止匿名可写,别人此时再想通过ftp来拿到服务器权限就比较困难了,而且像ftp这种极小规模的文件共享服务,适用场景绝大多数都在内网,另外,vsftpd虚拟用户身份验证除了上面在这种基于文件的方式,同样也可以基于数据库来进行认证,如,mysql,非常简单,换汤不换药,大家有兴趣可以去自己尝试,只不过,基于数据库会更加灵活,因为非常方便通过脚本进行进一步处理,如,php,python…今天就先到这里吧,祝大家好运,也欢迎多来一起交流 ^_^