mirror of
https://github.com/nganhkhoa/CTF-All-In-One.git
synced 2024-12-24 19:21:15 +07:00
update
This commit is contained in:
parent
74b678b39f
commit
3a60abe7bb
@ -277,19 +277,85 @@ tcache_get (size_t tc_idx)
|
||||
```
|
||||
可以看到注释部分,它假设调用者已经对参数进行了有效性检查,然而由于对 tcache 的操作在 free 和 malloc 中往往都处于很靠前的位置,导致原来的许多有效性检查都被无视了。这样做虽然有利于提升执行效率,但对安全性造成了负面影响。
|
||||
|
||||
#### tcache_dup
|
||||
```c
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
void *p1 = malloc(0x10);
|
||||
printf("1st malloc(0x10): %p\n", p1);
|
||||
printf("Freeing the first one\n");
|
||||
free(p1);
|
||||
printf("Freeing the first one again\n");
|
||||
free(p1);
|
||||
printf("2nd malloc(0x10): %p\n", malloc(0x10));
|
||||
printf("3rd malloc(0x10): %p\n", malloc(0x10));
|
||||
}
|
||||
```
|
||||
```
|
||||
$ ./tcache_dup
|
||||
1st malloc(0x10): 0x56088c39f260
|
||||
Freeing the first one
|
||||
Freeing the first one again
|
||||
2nd malloc(0x10): 0x56088c39f260
|
||||
3rd malloc(0x10): 0x56088c39f260
|
||||
```
|
||||
tcache_dup 与 fastbin_dup 类似,但其实更加简单,因为它并不局限于 fastbin,只要在 tcache chunk 范围内的都可以,而且 double-free 也不再需要考虑 top 的问题,直接 free 两次就可以了。然后我们就可以得到相同的 chunk。
|
||||
|
||||
第一次 free 后:
|
||||
```
|
||||
gdb-peda$ x/4gx 0x0000555555756260-0x10
|
||||
0x555555756250: 0x0000000000000000 0x0000000000000021
|
||||
0x555555756260: 0x0000000000000000 0x0000000000000000
|
||||
gdb-peda$ vmmap heap
|
||||
Start End Perm Name
|
||||
0x0000555555756000 0x0000555555777000 rw-p [heap]
|
||||
gdb-peda$ x/10gx 0x0000555555756000+0x10
|
||||
0x555555756010: 0x0000000000000001 0x0000000000000000 <-- counts
|
||||
0x555555756020: 0x0000000000000000 0x0000000000000000
|
||||
0x555555756030: 0x0000000000000000 0x0000000000000000
|
||||
0x555555756040: 0x0000000000000000 0x0000000000000000
|
||||
0x555555756050: 0x0000555555756260 0x0000000000000000 <-- entries
|
||||
```
|
||||
chunk 被放入相应的 tcache bin 中,可以看到该 tcache bin 的 counts 被设为 1,表示有 1 个 chunk,入口为 0x0000555555756260。
|
||||
|
||||
第二次 free 后:
|
||||
```
|
||||
gdb-peda$ x/4gx 0x0000555555756260-0x10
|
||||
0x555555756250: 0x0000000000000000 0x0000000000000021 <-- chunk 1 [double freed]
|
||||
0x555555756260: 0x0000555555756260 0x0000000000000000
|
||||
gdb-peda$ x/10gx 0x0000555555756000+0x10
|
||||
0x555555756010: 0x0000000000000002 0x0000000000000000 <-- counts
|
||||
0x555555756020: 0x0000000000000000 0x0000000000000000
|
||||
0x555555756030: 0x0000000000000000 0x0000000000000000
|
||||
0x555555756040: 0x0000000000000000 0x0000000000000000
|
||||
0x555555756050: 0x0000555555756260 0x0000000000000000 <-- entries
|
||||
```
|
||||
counts 变成 2,入口不变,表示 tcache bin 已经有两个 chunk 了,虽然是相同的。
|
||||
|
||||
两次 malloc 后:
|
||||
```
|
||||
gdb-peda$ x/10gx 0x0000555555756000+0x10
|
||||
0x555555756010: 0x0000000000000000 0x0000000000000000 <-- counts
|
||||
0x555555756020: 0x0000000000000000 0x0000000000000000
|
||||
0x555555756030: 0x0000000000000000 0x0000000000000000
|
||||
0x555555756040: 0x0000000000000000 0x0000000000000000
|
||||
0x555555756050: 0x0000555555756260 0x0000000000000000
|
||||
```
|
||||
于是我们得到了两个指向同一块内存区域的指针。
|
||||
|
||||
#### tcache_house_of_spirit
|
||||
|
||||
#### tcache_overlapping_chunks
|
||||
|
||||
#### tcache_poisoning
|
||||
|
||||
#### tcache_fastbin_dup
|
||||
|
||||
这一节的代码可以在[这里](../src/Others/4.14_glibc_tcache)找到。其他的一些情况可以参考章节 3.3.6。
|
||||
|
||||
|
||||
## CTF 实例
|
||||
在最近的 CTF 中,已经开始尝试使用 libc-2.26,比如章节 6.1.15 中的例子。
|
||||
在最近的 CTF 中,已经开始尝试使用 libc-2.26,比如章节 6.1.15、6.1.19 中的例子。
|
||||
|
||||
|
||||
## 参考资料
|
||||
|
@ -418,7 +418,7 @@ struct student {
|
||||
char *name;
|
||||
} student;
|
||||
|
||||
struct student my_class[0x1e];
|
||||
struct student *my_class[0x1e];
|
||||
```
|
||||
|
||||
漏洞就是在读入 memo 和 name 的时候都存在的 one-byte overflow,其中 memo 会覆盖掉 name 指针的低字节。考虑可以将 name 指针改成其它地址,并利用修改 name 的功能修改地址上的内容。
|
||||
@ -557,7 +557,7 @@ firmy
|
||||
|
||||
from pwn import *
|
||||
|
||||
context.log_level = 'debug'
|
||||
# context.log_level = 'debug'
|
||||
|
||||
io = process(['./jmper'], env={'LD_PRELOAD':'./libc-2.19.so'})
|
||||
elf = ELF('jmper')
|
||||
|
@ -19,9 +19,522 @@ $ strings libc.so.6 | grep "GNU C"
|
||||
GNU C Library (Ubuntu GLIBC 2.26-0ubuntu2.1) stable release version 2.26, by Roland McGrath et al.
|
||||
Compiled by GNU CC version 6.4.0 20171010.
|
||||
```
|
||||
保护全开。libc 版本 2.26,所以应该还是考察 tcache(参考章节4.14)。
|
||||
|
||||
玩一下:
|
||||
```
|
||||
$ ./gundam
|
||||
... # 创建了两个 gundam
|
||||
1 . Build a gundam
|
||||
2 . Visit gundams
|
||||
3 . Destory a gundam
|
||||
4 . Blow up the factory
|
||||
5 . Exit
|
||||
|
||||
Your choice : 2
|
||||
|
||||
Gundam[0] :AAAA
|
||||
Type[0] :Freedom
|
||||
|
||||
Gundam[1] :BBBB
|
||||
Type[1] :Strike Freedom
|
||||
|
||||
1 . Build a gundam
|
||||
2 . Visit gundams
|
||||
3 . Destory a gundam
|
||||
4 . Blow up the factory
|
||||
5 . Exit
|
||||
|
||||
Your choice : 3
|
||||
Which gundam do you want to Destory:0 # 第一次销毁 gundam 0,成功
|
||||
|
||||
1 . Build a gundam
|
||||
2 . Visit gundams
|
||||
3 . Destory a gundam
|
||||
4 . Blow up the factory
|
||||
5 . Exit
|
||||
|
||||
Your choice : 3
|
||||
Which gundam do you want to Destory:0 # 第二次销毁 gundam 0,成功
|
||||
|
||||
1 . Build a gundam
|
||||
2 . Visit gundams
|
||||
3 . Destory a gundam
|
||||
4 . Blow up the factory
|
||||
5 . Exit
|
||||
|
||||
Your choice : 2 # 此时剩下 gundam 1
|
||||
|
||||
Gundam[1] :BBBB
|
||||
Type[1] :Strike Freedom
|
||||
|
||||
1 . Build a gundam
|
||||
2 . Visit gundams
|
||||
3 . Destory a gundam
|
||||
4 . Blow up the factory
|
||||
5 . Exit
|
||||
|
||||
Your choice : 4 # 销毁 factory
|
||||
Done!
|
||||
|
||||
1 . Build a gundam
|
||||
2 . Visit gundams
|
||||
3 . Destory a gundam
|
||||
4 . Blow up the factory
|
||||
5 . Exit
|
||||
|
||||
Your choice : 2 # gundam 1 没有变化
|
||||
|
||||
Gundam[1] :BBBB
|
||||
Type[1] :Strike Freedom
|
||||
|
||||
1 . Build a gundam
|
||||
2 . Visit gundams
|
||||
3 . Destory a gundam
|
||||
4 . Blow up the factory
|
||||
5 . Exit
|
||||
|
||||
Your choice : 3 # 第三次销毁 gundam 0,失败
|
||||
Which gundam do you want to Destory:0
|
||||
Invalid choice
|
||||
```
|
||||
根据上面的结果也能猜出一些东西。比如在没有销毁 factory 的情况下,可以多次销毁 gundam。而销毁 factory 不会对没有销毁的 gundam 造成影响。
|
||||
|
||||
|
||||
## 题目解析
|
||||
#### main
|
||||
```
|
||||
[0x000009e0]> pdf @ main
|
||||
/ (fcn) main 122
|
||||
| main ();
|
||||
| ; var int local_18h @ rbp-0x18
|
||||
| ; var int local_12h @ rbp-0x12
|
||||
| ; var int local_8h @ rbp-0x8
|
||||
| ; DATA XREF from 0x000009fd (entry0)
|
||||
| 0x000010c5 push rbp
|
||||
| 0x000010c6 mov rbp, rsp
|
||||
| 0x000010c9 sub rsp, 0x20
|
||||
| 0x000010cd mov rax, qword fs:[0x28] ; [0x28:8]=0x2170 ; '('
|
||||
| 0x000010d6 mov qword [local_8h], rax
|
||||
| 0x000010da xor eax, eax
|
||||
| 0x000010dc mov eax, 0
|
||||
| 0x000010e1 call sub.setvbuf_22 ; int setvbuf(FILE*stream, char*buf, int mode, size_t size)
|
||||
| ; JMP XREF from 0x00001192 (main + 205)
|
||||
| 0x000010e6 mov eax, 0
|
||||
| 0x000010eb call sub.puts_aea ; int puts(const char *s)
|
||||
| 0x000010f0 lea rax, [local_12h]
|
||||
| 0x000010f4 mov edx, 8
|
||||
| 0x000010f9 mov rsi, rax
|
||||
| 0x000010fc mov edi, 0
|
||||
| 0x00001101 call sym.imp.read ; ssize_t read(int fildes, void *buf, size_t nbyte)
|
||||
| 0x00001106 lea rax, [local_12h]
|
||||
| 0x0000110a mov rdi, rax
|
||||
| 0x0000110d call sym.imp.atoi ; int atoi(const char *str)
|
||||
| 0x00001112 mov dword [local_18h], eax ; 读入选项
|
||||
| 0x00001115 cmp dword [local_18h], 5 ; [0x5:4]=257
|
||||
| ,=< 0x00001119 ja 0x1185
|
||||
| | 0x0000111b mov eax, dword [local_18h]
|
||||
| | 0x0000111e lea rdx, [rax*4]
|
||||
| | 0x00001126 lea rax, [0x00001368] ; 获取跳转表
|
||||
| | 0x0000112d mov eax, dword [rdx + rax] ; 获取对应表项
|
||||
| | 0x00001130 movsxd rdx, eax
|
||||
| | 0x00001133 lea rax, [0x00001368]
|
||||
| | 0x0000113a add rax, rdx ; '('
|
||||
\ | 0x0000113d jmp rax ; 跳到相应函数
|
||||
[0x000009e0]> px 20 @ 0x00001368+0x4
|
||||
- offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
|
||||
0x0000136c d7fd ffff e3fd ffff effd ffff fbfd ffff ................
|
||||
0x0000137c 07fe ffff
|
||||
[0x000009e0]> pd 20 @ 0x0000113f
|
||||
: 0x0000113f mov eax, 0
|
||||
: 0x00001144 call sub.malloc_b7d ; 选项 1
|
||||
,==< 0x00001149 jmp 0x1192
|
||||
|: 0x0000114b mov eax, 0
|
||||
|: 0x00001150 call sub.Gundam__u__:_s_ef4 ; 选项 2
|
||||
,===< 0x00001155 jm p 0x1192
|
||||
||: 0x00001157 mov eax, 0
|
||||
||: 0x0000115c call sub.Which_gundam_do_you_want_to_Destory:_d32 ; 选项 3
|
||||
,====< 0x00001161 jmp 0x1192
|
||||
|||: 0x00001163 mov eax, 0
|
||||
|||: 0x00001168 call sub.Done_e22 ; 选项 4
|
||||
,=====< 0x0000116d jmp 0x1192
|
||||
||||: 0x0000116f lea rdi, str.Exit.... ; 0x135c ; "Exit...."
|
||||
||||: 0x00001176 call sym.imp.puts ; int puts(const char *s)
|
||||
||||: 0x0000117b mov edi, 0
|
||||
||||: 0x00001180 call sym.imp.exit ; 选项 5
|
||||
||||: ; JMP XREF from 0x00001119 (main)
|
||||
||||: 0x00001185 lea rdi, str.Invalid_choice ; 0x130d ; "Invalid choice"
|
||||
||||: 0x0000118c call sym.imp.puts ; int puts(const char *s)
|
||||
||||: 0x00001191 nop
|
||||
||||| ; JMP XREF from 0x00001149 (main + 132)
|
||||
||||| ; JMP XREF from 0x00001155 (main + 144)
|
||||
||||| ; JMP XREF from 0x00001161 (main + 156)
|
||||
||||| ; JMP XREF from 0x0000116d (main + 168)
|
||||
`````=< 0x00001192 jmp 0x10e6 ; main+0x21
|
||||
```
|
||||
一个典型的 switch-case 跳转结构。
|
||||
|
||||
#### Build a gundam
|
||||
```
|
||||
[0x000009e0]> pdf @ sub.malloc_b7d
|
||||
/ (fcn) sub.malloc_b7d 437
|
||||
| sub.malloc_b7d (int arg_8h);
|
||||
| ; var int local_20h @ rbp-0x20
|
||||
| ; var int local_1ch @ rbp-0x1c
|
||||
| ; var int local_18h @ rbp-0x18
|
||||
| ; var int local_10h @ rbp-0x10
|
||||
| ; var int local_8h @ rbp-0x8
|
||||
| ; var int local_0h @ rbp-0x0
|
||||
| ; arg int arg_8h @ rbp+0x8
|
||||
| ; UNKNOWN XREF from 0x00001144 (main + 127)
|
||||
| ; CALL XREF from 0x00001144 (main + 127)
|
||||
| 0x00000b7d push rbp
|
||||
| 0x00000b7e mov rbp, rsp
|
||||
| 0x00000b81 sub rsp, 0x20
|
||||
| 0x00000b85 mov rax, qword fs:[0x28] ; [0x28:8]=0x2170 ; '('
|
||||
| 0x00000b8e mov qword [local_8h], rax
|
||||
| 0x00000b92 xor eax, eax
|
||||
| 0x00000b94 mov qword [local_18h], 0 ; 初始化 [local_18h]
|
||||
| 0x00000b9c mov qword [local_10h], 0 ; 初始化 [local_10h]
|
||||
| 0x00000ba4 mov eax, dword [0x0020208c] ; [0x20208c:4]=0 ; 取出当前 gundam 数量
|
||||
| 0x00000baa cmp eax, 8
|
||||
| ,=< 0x00000bad ja 0xd17 ; 如果大于 8,函数返回
|
||||
| | 0x00000bb3 mov edi, 0x28 ; 否则继续
|
||||
| | 0x00000bb8 call sym.imp.malloc ; [local_18h] = malloc(0x28) 分配一块内存作为 gundam
|
||||
| | 0x00000bbd mov qword [local_18h], rax
|
||||
| | 0x00000bc1 mov rax, qword [local_18h]
|
||||
| | 0x00000bc5 mov edx, 0x28 ; '('
|
||||
| | 0x00000bca mov esi, 0
|
||||
| | 0x00000bcf mov rdi, rax
|
||||
| | 0x00000bd2 call sym.imp.memset ; memset([local_18h], 0, 0x28) 进行初始化
|
||||
| | 0x00000bd7 mov edi, 0x100
|
||||
| | 0x00000bdc call sym.imp.malloc ; [local_10h] = malloc(0x100) 分配一块内存作为 name
|
||||
| | 0x00000be1 mov qword [local_10h], rax
|
||||
| | 0x00000be5 cmp qword [local_10h], 0
|
||||
| ,==< 0x00000bea jne 0xc02
|
||||
| || 0x00000bec lea rdi, str.error ; 0x1295 ; "error !"
|
||||
| || 0x00000bf3 call sym.imp.puts ; int puts(const char *s)
|
||||
| || 0x00000bf8 mov edi, 0xffffffff ; -1
|
||||
| || 0x00000bfd call sym.imp.exit ; void exit(int status)
|
||||
| || ; JMP XREF from 0x00000bea (sub.malloc_b7d)
|
||||
| `--> 0x00000c02 lea rdi, str.The_name_of_gundam_: ; 0x129d ; "The name of gundam :"
|
||||
| | 0x00000c09 mov eax, 0
|
||||
| | 0x00000c0e call sym.imp.printf ; int printf(const char *format)
|
||||
| | 0x00000c13 mov rax, qword [local_10h]
|
||||
| | 0x00000c17 mov edx, 0x100
|
||||
| | 0x00000c1c mov rsi, rax
|
||||
| | 0x00000c1f mov edi, 0
|
||||
| | 0x00000c24 call sym.imp.read ; read(0, [local_10h], 0x100) 读入字符到 name
|
||||
| | 0x00000c29 mov rax, qword [local_18h] ; 取出 gundam
|
||||
| | 0x00000c2d mov rdx, qword [local_10h]
|
||||
| | 0x00000c31 mov qword [rax + 8], rdx ; 将 name 放到 gundam->name
|
||||
| | 0x00000c35 lea rdi, str.The_type_of_the_gundam_: ; 0x12b2 ; "The type of the gundam :"
|
||||
| | 0x00000c3c mov eax, 0
|
||||
| | 0x00000c41 call sym.imp.printf ; int printf(const char *format)
|
||||
| | 0x00000c46 lea rax, [local_20h]
|
||||
| | 0x00000c4a mov rsi, rax
|
||||
| | 0x00000c4d lea rdi, [0x000012cb] ; "%d"
|
||||
| | 0x00000c54 mov eax, 0
|
||||
| | 0x00000c59 call sym.imp.__isoc99_scanf ; 读入 type 到 [local_20h]
|
||||
| | 0x00000c5e mov eax, dword [local_20h]
|
||||
| | 0x00000c61 test eax, eax
|
||||
| ,==< 0x00000c63 js 0xc6d
|
||||
| || 0x00000c65 mov eax, dword [local_20h] ; 大于等于 0 时继续
|
||||
| || 0x00000c68 cmp eax, 2
|
||||
| ,===< 0x00000c6b jle 0xc83 ; 小于等于 2 时跳转
|
||||
| ||| ; JMP XREF from 0x00000c63 (sub.malloc_b7d)
|
||||
| |`--> 0x00000c6d lea rdi, str.Invalid. ; 0x12ce ; "Invalid."
|
||||
| | | 0x00000c74 call sym.imp.puts ; int puts(const char *s)
|
||||
| | | 0x00000c79 mov edi, 0
|
||||
| | | 0x00000c7e call sym.imp.exit ; void exit(int status)
|
||||
| | | ; JMP XREF from 0x00000c6b (sub.malloc_b7d)
|
||||
| `---> 0x00000c83 mov eax, dword [local_20h]
|
||||
| | 0x00000c86 movsxd rdx, eax
|
||||
| | 0x00000c89 mov rax, rdx
|
||||
| | 0x00000c8c shl rax, 2
|
||||
| | 0x00000c90 add rax, rdx ; '('
|
||||
| | 0x00000c93 shl rax, 2 ; 最后得到 rax = rax * 20
|
||||
| | 0x00000c97 lea rdx, str.Freedom ; 0x202020 ; "Freedom" ; 取出起始地址
|
||||
| | 0x00000c9e add rdx, rax ; rdx 为字符串 type 的地址
|
||||
| | 0x00000ca1 mov rax, qword [local_18h]
|
||||
| | 0x00000ca5 add rax, 0x10 ; 取出 gundam->type
|
||||
| | 0x00000ca9 mov rsi, rdx
|
||||
| | 0x00000cac mov rdi, rax
|
||||
| | 0x00000caf call sym.imp.strcpy ; strcpy(gundam->type, type) 将字符串复制过去
|
||||
| | 0x00000cb4 mov rax, qword [local_18h] ; 取出 gundam
|
||||
| | 0x00000cb8 mov dword [rax], 1 ; 将 gundam->flag 赋值为 1
|
||||
| | 0x00000cbe mov dword [local_1ch], 0 ; 循环计数 i,初始化为 0
|
||||
| ,==< 0x00000cc5 jmp 0xd02 ; 开始循环
|
||||
| || ; JMP XREF from 0x00000d06 (sub.malloc_b7d)
|
||||
| .---> 0x00000cc7 mov eax, dword [local_1ch]
|
||||
| :|| 0x00000cca lea rdx, [rax*8]
|
||||
| :|| 0x00000cd2 lea rax, [0x002020a0] ; 取出 factory 地址
|
||||
| :|| 0x00000cd9 mov rax, qword [rdx + rax] ; 找到 factory[i]
|
||||
| :|| 0x00000cdd test rax, rax
|
||||
| ,====< 0x00000ce0 jne 0xcfe ; 不为 0 时继续下一次循环
|
||||
| |:|| 0x00000ce2 mov eax, dword [local_1ch] ; 否则继续
|
||||
| |:|| 0x00000ce5 lea rcx, [rax*8]
|
||||
| |:|| 0x00000ced lea rax, [0x002020a0]
|
||||
| |:|| 0x00000cf4 mov rdx, qword [local_18h] ; 取出 gundam
|
||||
| |:|| 0x00000cf8 mov qword [rcx + rax], rdx ; 将 gundam 放到 factory[i]
|
||||
| ,=====< 0x00000cfc jmp 0xd08 ; 结束循环
|
||||
| ||:|| ; JMP XREF from 0x00000ce0 (sub.malloc_b7d)
|
||||
| |`----> 0x00000cfe add dword [local_1ch], 1 ; i = i + 1
|
||||
| | :|| ; JMP XREF from 0x00000cc5 (sub.malloc_b7d)
|
||||
| | :`--> 0x00000d02 cmp dword [local_1ch], 8 ; 最多能有 9 个 gundam
|
||||
| | `===< 0x00000d06 jbe 0xcc7 ; 循环继续
|
||||
| | | ; JMP XREF from 0x00000cfc (sub.malloc_b7d)
|
||||
| `-----> 0x00000d08 mov eax, dword [0x0020208c] ; [0x20208c:4]=0
|
||||
| | 0x00000d0e add eax, 1 ; gundam 数量 + 1
|
||||
| | 0x00000d11 mov dword [0x0020208c], eax ; [0x20208c:4]=0 ; 放回去
|
||||
| | ; JMP XREF from 0x00000bad (sub.malloc_b7d)
|
||||
| `-> 0x00000d17 mov eax, 0
|
||||
| 0x00000d1c mov rcx, qword [local_8h]
|
||||
| 0x00000d20 xor rcx, qword fs:[0x28]
|
||||
| ,=< 0x00000d29 je 0xd30
|
||||
| | 0x00000d2b call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
|
||||
| | ; JMP XREF from 0x00000d29 (sub.malloc_b7d)
|
||||
| `-> 0x00000d30 leave
|
||||
\ 0x00000d31 ret
|
||||
[0x000009e0]> px 60 @ 0x00202020
|
||||
- offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
|
||||
0x00202020 4672 6565 646f 6d00 0000 0000 0000 0000 Freedom.........
|
||||
0x00202030 0000 0000 5374 7269 6b65 2046 7265 6564 ....Strike Freed
|
||||
0x00202040 6f6d 0000 0000 0000 4167 6965 7300 0000 om......Agies...
|
||||
0x00202050 0000 0000 0000 0000 0000 0000
|
||||
```
|
||||
通过分析这个函数,可以得到 gundam 结构体(大小为0x28)和 factory(地址`0x002020a0`) 数组:
|
||||
```c
|
||||
struct gundam {
|
||||
uint32_t flag;
|
||||
char *name;
|
||||
char type[24];
|
||||
} gundam;
|
||||
|
||||
struct gundam *factory[9];
|
||||
```
|
||||
另外 gundam->name 指向一块 0x100 大小的空间。gundam 的数量存放在 `0x0020208c`。
|
||||
|
||||
从读入 name 的操作中我们发现,程序并没有在末尾设置 '\x00',可能导致信息泄漏。
|
||||
|
||||
#### Visit gundams
|
||||
```
|
||||
[0x000009e0]> pdf @ sub.Gundam__u__:_s_ef4
|
||||
/ (fcn) sub.Gundam__u__:_s_ef4 254
|
||||
| sub.Gundam__u__:_s_ef4 (int arg_8h);
|
||||
| ; var int local_ch @ rbp-0xc
|
||||
| ; var int local_8h @ rbp-0x8
|
||||
| ; arg int arg_8h @ rbp+0x8
|
||||
| ; CALL XREF from 0x00001150 (main + 139)
|
||||
| 0x00000ef4 push rbp
|
||||
| 0x00000ef5 mov rbp, rsp
|
||||
| 0x00000ef8 sub rsp, 0x10
|
||||
| 0x00000efc mov rax, qword fs:[0x28] ; [0x28:8]=0x2170 ; '('
|
||||
| 0x00000f05 mov qword [local_8h], rax
|
||||
| 0x00000f09 xor eax, eax
|
||||
| 0x00000f0b mov eax, dword [0x0020208c] ; [0x20208c:4]=0 ; 取出 gundam_num
|
||||
| 0x00000f11 test eax, eax
|
||||
| ,=< 0x00000f13 jne 0xf26 ; 不等于 0 时跳转
|
||||
| | 0x00000f15 lea rdi, str.No_gundam_produced ; 0x1322 ; "No gundam produced!"
|
||||
| | 0x00000f1c call sym.imp.puts ; int puts(const char *s)
|
||||
| ,==< 0x00000f21 jmp 0xfd7
|
||||
| || ; JMP XREF from 0x00000f13 (sub.Gundam__u__:_s_ef4)
|
||||
| |`-> 0x00000f26 mov dword [local_ch], 0 ; 循环计数 i,初始化为 0
|
||||
| |,=< 0x00000f2d jmp 0xfcd ; 开始循环
|
||||
| || ; JMP XREF from 0x00000fd1 (sub.Gundam__u__:_s_ef4)
|
||||
| .---> 0x00000f32 mov eax, dword [local_ch]
|
||||
| :|| 0x00000f35 lea rdx, [rax*8]
|
||||
| :|| 0x00000f3d lea rax, [0x002020a0]
|
||||
| :|| 0x00000f44 mov rax, qword [rdx + rax] ; 取出 factory[i]
|
||||
| :|| 0x00000f48 test rax, rax
|
||||
| ,====< 0x00000f4b je 0xfc9 ; 为 0 时跳转,下一次循环
|
||||
| |:|| 0x00000f4d mov eax, dword [local_ch]
|
||||
| |:|| 0x00000f50 lea rdx, [rax*8]
|
||||
| |:|| 0x00000f58 lea rax, [0x002020a0]
|
||||
| |:|| 0x00000f5f mov rax, qword [rdx + rax]
|
||||
| |:|| 0x00000f63 mov eax, dword [rax] ; 取出 factory[i]->flag
|
||||
| |:|| 0x00000f65 test eax, eax
|
||||
| ,=====< 0x00000f67 je 0xfc9 ; flag 为 0 时跳转,下一次循环
|
||||
| ||:|| 0x00000f69 mov eax, dword [local_ch]
|
||||
| ||:|| 0x00000f6c lea rdx, [rax*8]
|
||||
| ||:|| 0x00000f74 lea rax, [0x002020a0]
|
||||
| ||:|| 0x00000f7b mov rax, qword [rdx + rax]
|
||||
| ||:|| 0x00000f7f mov rdx, qword [rax + 8] ; 取出 factory[i]->name
|
||||
| ||:|| 0x00000f83 mov eax, dword [local_ch]
|
||||
| ||:|| 0x00000f86 mov esi, eax
|
||||
| ||:|| 0x00000f88 lea rdi, str.Gundam__u__:_s ; 0x1336 ; "\nGundam[%u] :%s"
|
||||
| ||:|| 0x00000f8f mov eax, 0
|
||||
| ||:|| 0x00000f94 call sym.imp.printf ; 打印出 factory[i]->name
|
||||
| ||:|| 0x00000f99 mov eax, dword [local_ch]
|
||||
| ||:|| 0x00000f9c lea rdx, [rax*8]
|
||||
| ||:|| 0x00000fa4 lea rax, [0x002020a0]
|
||||
| ||:|| 0x00000fab mov rax, qword [rdx + rax]
|
||||
| ||:|| 0x00000faf lea rdx, [rax + 0x10] ; 取出 factory[i]->type
|
||||
| ||:|| 0x00000fb3 mov eax, dword [local_ch]
|
||||
| ||:|| 0x00000fb6 mov esi, eax
|
||||
| ||:|| 0x00000fb8 lea rdi, str.Type__u__:_s ; 0x1346 ; "Type[%u] :%s\n"
|
||||
| ||:|| 0x00000fbf mov eax, 0
|
||||
| ||:|| 0x00000fc4 call sym.imp.printf ; 打印出 factory[i]->type
|
||||
| ||:|| ; JMP XREF from 0x00000f4b (sub.Gundam__u__:_s_ef4)
|
||||
| ||:|| ; JMP XREF from 0x00000f67 (sub.Gundam__u__:_s_ef4)
|
||||
| ``----> 0x00000fc9 add dword [local_ch], 1 ; i = i + 1
|
||||
| :|| ; JMP XREF from 0x00000f2d (sub.Gundam__u__:_s_ef4)
|
||||
| :|`-> 0x00000fcd cmp dword [local_ch], 8 ; 最多有 9 个 gundam
|
||||
| `===< 0x00000fd1 jbe 0xf32 ; 循环继续
|
||||
| | ; JMP XREF from 0x00000f21 (sub.Gundam__u__:_s_ef4)
|
||||
| `--> 0x00000fd7 mov eax, 0
|
||||
| 0x00000fdc mov rcx, qword [local_8h]
|
||||
| 0x00000fe0 xor rcx, qword fs:[0x28]
|
||||
| ,=< 0x00000fe9 je 0xff0
|
||||
| | 0x00000feb call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
|
||||
| | ; JMP XREF from 0x00000fe9 (sub.Gundam__u__:_s_ef4)
|
||||
| `-> 0x00000ff0 leave
|
||||
\ 0x00000ff1 ret
|
||||
```
|
||||
该函数先判断 gundam_num 是否为 0,如果不是,再根据 factory[i] 和 factory[i]->flag 判断某个 gundam 是否存在,如果存在,就将它的 name 和 type 打印出来。
|
||||
|
||||
#### Destory a gundam
|
||||
```
|
||||
[0x000009e0]> pdf @ sub.Which_gundam_do_you_want_to_Destory:_d32
|
||||
/ (fcn) sub.Which_gundam_do_you_want_to_Destory:_d32 240
|
||||
| sub.Which_gundam_do_you_want_to_Destory:_d32 ();
|
||||
| ; var int local_ch @ rbp-0xc
|
||||
| ; var int local_8h @ rbp-0x8
|
||||
| ; CALL XREF from 0x0000115c (main + 151)
|
||||
| 0x00000d32 push rbp
|
||||
| 0x00000d33 mov rbp, rsp
|
||||
| 0x00000d36 sub rsp, 0x10
|
||||
| 0x00000d3a mov rax, qword fs:[0x28] ; [0x28:8]=0x2170 ; '('
|
||||
| 0x00000d43 mov qword [local_8h], rax
|
||||
| 0x00000d47 xor eax, eax
|
||||
| 0x00000d49 mov eax, dword [0x0020208c] ; [0x20208c:4]=0 ; 取出 gundam_num
|
||||
| 0x00000d4f test eax, eax
|
||||
| ,=< 0x00000d51 jne 0xd64 ; 不等于 0 时跳转
|
||||
| | 0x00000d53 lea rdi, str.No_gundam ; 0x12d7 ; "No gundam"
|
||||
| | 0x00000d5a call sym.imp.puts ; int puts(const char *s)
|
||||
| ,==< 0x00000d5f jmp 0xe07
|
||||
| || ; JMP XREF from 0x00000d51 (sub.Which_gundam_do_you_want_to_Destory:_d32)
|
||||
| |`-> 0x00000d64 lea rdi, str.Which_gundam_do_you_want_to_Destory: ; 0x12e8 ; "Which gundam do you want to Destory:"
|
||||
| | 0x00000d6b mov eax, 0
|
||||
| | 0x00000d70 call sym.imp.printf ; int printf(const char *format)
|
||||
| | 0x00000d75 lea rax, [local_ch]
|
||||
| | 0x00000d79 mov rsi, rax
|
||||
| | 0x00000d7c lea rdi, [0x000012cb] ; "%d"
|
||||
| | 0x00000d83 mov eax, 0
|
||||
| | 0x00000d88 call sym.imp.__isoc99_scanf ; 读入序号 i 到 [local_ch]
|
||||
| | 0x00000d8d mov eax, dword [local_ch]
|
||||
| | 0x00000d90 cmp eax, 8
|
||||
| |,=< 0x00000d93 ja 0xdb2 ; 如果大于 8,函数结束
|
||||
| || 0x00000d95 mov eax, dword [local_ch] ; 否则继续
|
||||
| || 0x00000d98 mov eax, eax
|
||||
| || 0x00000d9a lea rdx, [rax*8]
|
||||
| || 0x00000da2 lea rax, [0x002020a0]
|
||||
| || 0x00000da9 mov rax, qword [rdx + rax] ; 取出 factory[i]
|
||||
| || 0x00000dad test rax, rax
|
||||
| ,===< 0x00000db0 jne 0xdc5 ; 如果不为 0,跳转
|
||||
| ||| ; JMP XREF from 0x00000d93 (sub.Which_gundam_do_you_want_to_Destory:_d32)
|
||||
| ||`-> 0x00000db2 lea rdi, str.Invalid_choice ; 0x130d ; "Invalid choice"
|
||||
| || 0x00000db9 call sym.imp.puts ; int puts(const char *s)
|
||||
| || 0x00000dbe mov eax, 0
|
||||
| ||,=< 0x00000dc3 jmp 0xe0c
|
||||
| ||| ; JMP XREF from 0x00000db0 (sub.Which_gundam_do_you_want_to_Destory:_d32)
|
||||
| `---> 0x00000dc5 mov eax, dword [local_ch]
|
||||
| || 0x00000dc8 mov eax, eax
|
||||
| || 0x00000dca lea rdx, [rax*8]
|
||||
| || 0x00000dd2 lea rax, [0x002020a0]
|
||||
| || 0x00000dd9 mov rax, qword [rdx + rax] ; 取出 factory[i]
|
||||
| || 0x00000ddd mov dword [rax], 0 ; 将 factory[i]->flag 置为 0
|
||||
| || 0x00000de3 mov eax, dword [local_ch]
|
||||
| || 0x00000de6 mov eax, eax
|
||||
| || 0x00000de8 lea rdx, [rax*8]
|
||||
| || 0x00000df0 lea rax, [0x002020a0]
|
||||
| || 0x00000df7 mov rax, qword [rdx + rax]
|
||||
| || 0x00000dfb mov rax, qword [rax + 8] ; 取出 factory[i]->name
|
||||
| || 0x00000dff mov rdi, rax
|
||||
| || 0x00000e02 call sym.imp.free ; free(factory[i]->name)
|
||||
| || ; JMP XREF from 0x00000d5f (sub.Which_gundam_do_you_want_to_Destory:_d32)
|
||||
| `--> 0x00000e07 mov eax, 0
|
||||
| | ; JMP XREF from 0x00000dc3 (sub.Which_gundam_do_you_want_to_Destory:_d32)
|
||||
| `-> 0x00000e0c mov rcx, qword [local_8h]
|
||||
| 0x00000e10 xor rcx, qword fs:[0x28]
|
||||
| ,=< 0x00000e19 je 0xe20
|
||||
| | 0x00000e1b call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
|
||||
| | ; JMP XREF from 0x00000e19 (sub.Which_gundam_do_you_want_to_Destory:_d32)
|
||||
| `-> 0x00000e20 leave
|
||||
\ 0x00000e21 ret
|
||||
```
|
||||
该函数用于销毁 gundam,它先将 gundam->flag 置为 0,再释放掉 gundam->name。
|
||||
|
||||
这里有几个问题:
|
||||
- 该函数是通过 factory[i] 来判断某个 gundam 是否存在,而在销毁 gundam 后并没有将 factory[i] 置空,导致 factory[i]->name 可能被多次释放
|
||||
- name 指针没有被置空,可能导致 UAF
|
||||
- 销毁 gundam 后没有将 gundam_num 减 1
|
||||
|
||||
#### Blow up the factory
|
||||
```
|
||||
[0x000009e0]> pdf @ sub.Done_e22
|
||||
/ (fcn) sub.Done_e22 210
|
||||
| sub.Done_e22 (int arg_8h);
|
||||
| ; var int local_ch @ rbp-0xc
|
||||
| ; var int local_8h @ rbp-0x8
|
||||
| ; arg int arg_8h @ rbp+0x8
|
||||
| ; CALL XREF from 0x00001168 (main + 163)
|
||||
| 0x00000e22 push rbp
|
||||
| 0x00000e23 mov rbp, rsp
|
||||
| 0x00000e26 sub rsp, 0x10
|
||||
| 0x00000e2a mov rax, qword fs:[0x28] ; [0x28:8]=0x2170 ; '('
|
||||
| 0x00000e33 mov qword [local_8h], rax
|
||||
| 0x00000e37 xor eax, eax
|
||||
| 0x00000e39 mov dword [local_ch], 0 ; 循环计数 i,初始化为 0
|
||||
| ,=< 0x00000e40 jmp 0xec7 ; 开始循环
|
||||
| | ; JMP XREF from 0x00000ecb (sub.Done_e22)
|
||||
| .--> 0x00000e45 mov eax, dword [local_ch]
|
||||
| :| 0x00000e48 lea rdx, [rax*8]
|
||||
| :| 0x00000e50 lea rax, [0x002020a0]
|
||||
| :| 0x00000e57 mov rax, qword [rdx + rax] ; 取出 factory[i]
|
||||
| :| 0x00000e5b test rax, rax
|
||||
| ,===< 0x00000e5e je 0xec3 ; 为 0 时跳转,下一次循环
|
||||
| |:| 0x00000e60 mov eax, dword [local_ch] ; 否则继续
|
||||
| |:| 0x00000e63 lea rdx, [rax*8]
|
||||
| |:| 0x00000e6b lea rax, [0x002020a0]
|
||||
| |:| 0x00000e72 mov rax, qword [rdx + rax]
|
||||
| |:| 0x00000e76 mov eax, dword [rax] ; 取出 factory[i]->flag
|
||||
| |:| 0x00000e78 test eax, eax
|
||||
| ,====< 0x00000e7a jne 0xec3 ; 不等于 0 时跳转,下一次循环
|
||||
| ||:| 0x00000e7c mov eax, dword [local_ch] ; 否则继续
|
||||
| ||:| 0x00000e7f lea rdx, [rax*8]
|
||||
| ||:| 0x00000e87 lea rax, [0x002020a0]
|
||||
| ||:| 0x00000e8e mov rax, qword [rdx + rax] ; 取出 factory[i]
|
||||
| ||:| 0x00000e92 mov rdi, rax
|
||||
| ||:| 0x00000e95 call sym.imp.free ; free(factory[i])
|
||||
| ||:| 0x00000e9a mov eax, dword [local_ch]
|
||||
| ||:| 0x00000e9d lea rdx, [rax*8]
|
||||
| ||:| 0x00000ea5 lea rax, [0x002020a0]
|
||||
| ||:| 0x00000eac mov qword [rdx + rax], 0 ; 将 factory[i] 置为 0
|
||||
| ||:| 0x00000eb4 mov eax, dword [0x0020208c] ; [0x20208c:4]=0 ; 取出 gundam_num
|
||||
| ||:| 0x00000eba sub eax, 1 ; gundam_num -= 1
|
||||
| ||:| 0x00000ebd mov dword [0x0020208c], eax ; [0x20208c:4]=0 ; 写回去
|
||||
| ||:| ; JMP XREF from 0x00000e5e (sub.Done_e22)
|
||||
| ||:| ; JMP XREF from 0x00000e7a (sub.Done_e22)
|
||||
| ``---> 0x00000ec3 add dword [local_ch], 1 ; i = i + 1
|
||||
| :| ; JMP XREF from 0x00000e40 (sub.Done_e22)
|
||||
| :`-> 0x00000ec7 cmp dword [local_ch], 8 ; 最多有 9 个 gundam
|
||||
| `==< 0x00000ecb jbe 0xe45 ; 循环继续
|
||||
| 0x00000ed1 lea rdi, str.Done ; 0x131c ; "Done!"
|
||||
| 0x00000ed8 call sym.imp.puts ; int puts(const char *s)
|
||||
| 0x00000edd nop
|
||||
| 0x00000ede mov rax, qword [local_8h]
|
||||
| 0x00000ee2 xor rax, qword fs:[0x28]
|
||||
| ,=< 0x00000eeb je 0xef2
|
||||
| | 0x00000eed call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
|
||||
| | ; JMP XREF from 0x00000eeb (sub.Done_e22)
|
||||
| `-> 0x00000ef2 leave
|
||||
\ 0x00000ef3 ret
|
||||
```
|
||||
该函数会找出所有 factory[i] 不为 0,且 factory[i]->flag 为 0 的 gundam,然后将该 gundam 结构体释放掉,factory[i] 置为 0,最后 gundam_num 每次减 1。
|
||||
|
||||
经过这个过程,销毁 gundam 留下的问题基本解决了,除了 name 指针依然存在。
|
||||
|
||||
|
||||
## Exploit
|
||||
|
||||
|
13
src/Others/4.14_glibc_tcache/tcache_dup.c
Normal file
13
src/Others/4.14_glibc_tcache/tcache_dup.c
Normal file
@ -0,0 +1,13 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
void *p1 = malloc(0x10);
|
||||
printf("1st malloc(0x10): %p\n", p1);
|
||||
printf("Freeing the first one\n");
|
||||
free(p1);
|
||||
printf("Freeing the first one again\n");
|
||||
free(p1);
|
||||
printf("2nd malloc(0x10): %p\n", malloc(0x10));
|
||||
printf("3rd malloc(0x10): %p\n", malloc(0x10));
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
from pwn import *
|
||||
|
||||
context.log_level = 'debug'
|
||||
# context.log_level = 'debug'
|
||||
|
||||
io = process(['./jmper'], env={'LD_PRELOAD':'./libc-2.19.so'})
|
||||
elf = ELF('jmper')
|
||||
|
Loading…
Reference in New Issue
Block a user