基于Metasploit利用GHOST 漏洞获得远程Exim邮件服务器SHELL
? 分析阶段
1. GHOST漏洞分析及其条件限制
2. 如何利用受GHOST漏洞影响的Exim服务的原理 ? 实际操作阶段
1. 渗透环境搭建:KaliLinux与Metasploit 2. 使用Nmap对目标进行端口扫描及服务查点 3. 快速检查被渗透目标是否存在ghost漏洞
4. 使用Metasploit加载GHOST漏洞攻击模块进行远程入侵,获得远程主机shell
========= 分析开始 =========
? GHOST漏洞分析及其条件限制
GHOST漏洞是2015年1月27号公布的Linux底层漏洞,国际编号为CVE-2015-0235,存在于GNU C库(glibc)中,受影响的Linux发现版本有:Debian 7 (wheezy),Red Hat Enterprise,Linux 6 & 7,CentOS 6 & 7,Ubuntu 12.04等。 存在漏洞的函数__nss_hostname_digits_dots()由glibc的非重入版本的文件:
nss/getXXbyYY.c,以及重入版本:nss/getXXbyYY_r.c提供。然而,这个函数的调用是由#ifdef HANDLE_DIGITS_DOTS来定义的,这个宏定义只在这几个文件有: - inet/gethstbynm.c - inet/gethstbynm2.c - inet/gethstbynm_r.c - inet/gethstbynm2_r.c - nscd/gethstbynm3_r.c
以上这些文件实现gethostbyname*()函数族,因此也只有它们会调用__nss_hostname_digits_dots(),并且可能触发它的缓冲区溢出。该函数的作用是:“如果主机名是IPv4/IPv6地址,就跳过费时的DNS查找”。 glibc-2.17的代码如下:
35 int
36 __nss_hostname_digits_dots (const char *name, struct hostent *resbuf, 37 char **buffer, size_t *buffer_size, 38 size_t buflen, struct hostent **result,
39 enum nss_status *status, int af, int *h_errnop) 40 { ..
57 if (isdigit (name[0]) || isxdigit (name[0]) || name[0] == ':') 58 {
59 const char *cp; 60 char *hostname;
61 typedef unsigned char host_addr_t[16]; 62 host_addr_t *host_addr;
63 typedef char *host_addr_list_t[2]; 64 host_addr_list_t *h_addr_ptrs; 65 char **h_alias_ptr; 66 size_t size_needed; ..
85 size_needed = (sizeof (*host_addr)
86 + sizeof (*h_addr_ptrs) + strlen (name) + 1); 87
88 if (buffer_size == NULL) 89 {
90 if (buflen < size_needed) 91 { ..
95 goto done;
96 } 97 }
98 else if (buffer_size != NULL && *buffer_size < size_needed) 99 {
100 char *new_buf;
101 *buffer_size = size_needed;
102 new_buf = (char *) realloc (*buffer, *buffer_size); 103
104 if (new_buf == NULL) 105 { ...
114 goto done; 115 }
116 *buffer = new_buf; 117 } ...
121 host_addr = (host_addr_t *) *buffer; 122 h_addr_ptrs = (host_addr_list_t *)
123 ((char *) host_addr + sizeof (*host_addr));
124 h_alias_ptr = (char **) ((char *) h_addr_ptrs + sizeof (*h_addr_ptrs)); 125 hostname = (char *) h_alias_ptr + sizeof (*h_alias_ptr); 126
127 if (isdigit (name[0])) 128 {
129 for (cp = name;; ++cp) 130 {
131 if (*cp == '\\0') 132 {
133 int ok; 134
135 if (*--cp == '.') 136 break; ...
142 if (af == AF_INET)
143 ok = __inet_aton (name, (struct in_addr *) host_addr); 144 else 145 {
146 assert (af == AF_INET6);
147 ok = inet_pton (af, name, host_addr) > 0; 148 } 149 if (! ok) 150 { ...
154 goto done; 155 } 156
157 resbuf->h_name = strcpy (hostname, name); ...
194 goto done;
195 } 196
197 if (!isdigit (*cp) && *cp != '.') 198 break; 199 } 200 } ...
Ln 85-86计算所需的缓冲区大小size_needed来存储三个不同的实体: HOST_ADDR,h_addr_ptrs和name(hostname) 。Ln 88-117 确保缓冲区足够大:Ln 88-97对应于函数重入的情况,Ln 98-117为非重入的情况。 Ln
121-125
处理存储四个不同实体的指针地址,
HOST_ADDR,h_addr_ptrs,h_alias_ptr ,和hostname。 计算size_needed时,漏掉了一个sizeof( * h_alias_ptr ) - 也即一个char指针的大小。
因此, strcpy的( )所在的Ln157应该可以让我们写过缓冲区的末尾,至多(取决于函数strlen(name)和对齐) 4个字节 (32位),或8个字节(64位)...
为了在行157触发溢出,主机名参数必须符合下列要求: - 它的第一个字符必须是数字(Ln 127) 。 - 它的最后一个字符不能是点 “.”(Ln 135 ) 。
- 它必须只包含数字和点(Ln 197 ) (我们称之为“数字和点”的要求) 。
- 它必须足够长以溢出缓冲区。例如,非重入的gethostbyname *()函数最开始就会通过调用malloc (1024)来分配自己的缓冲区 (申请 “1 KB”) 。
- 它必须成功地解析为IPv4地址。也即它必须通过INET_ATON()函数的检测!
? 如何利用受GHOST漏洞影响的Exim服务的原理:
在本节中,我们将介绍如何对Exim SMTP邮件服务器实现远程执行代码,绕过NX保护和glibc的malloc强化。
相关推荐: