◾ 실습 환경: Ubuntu 16.04 (glibc 2.23)
Double Free와 U-A-F 취약점은 C 언어에서 동적 메모리를 관리를 올바르지 않은 방식으로 했을 때 발생하는 취약점들이다.
Double Free
해제된 메모리를 다시 한 번 해제하는 취약점이다.
📌 힙을 할당했다가 해제하면서 할당되었던 힙 청크의 주소가 크기에 맞는 bin
(fastbin/unsorted bin/samllbin/largebin)에 들어가고, 같은 bin에 해당되는 크기로 재할당 요청이 오면 순차적으로 할당이 된다. 이 때, double free가 발생해 중복된 주소가 bin에 들어가게 되었을 때, 같은 크기로 할당 요청이 여러 번 들어오게 되면 동일한 메모리에 두 개의 객체가 할당될 수 있다. 이 점을 이용해 이미 해제된 힙 청크의 메타데이터를 조작하는 등 실행 흐름을 바꿀 수 있게 된다.
예제 -(1) df1: Double Free 확인하기
#include <stdio.h>
#include <malloc.h>
int main(void) {
char* a = (char *)malloc(100);
char *b = (char *)malloc(100);
memset(a, 0, 100);
strcpy(a, "Hello World!");
memset(b, 0, 100);
strcpy(b, "Hello Pwnable!");
printf("%s\n", a);
printf("%s\n", b);
free(a);
free(b);
free(a);
}
△ df1.c
: 각 100byte씩 메모리를 할당하고 할당된 메모리에 각각 "Hello World!"와 "Hello Pwnable!"이라는 문자열을 복사하고 출력하는 코드이다.
→ 가장 마지막 코드에서 이미 해제된 메모리 a를 한 번 더 free()를 호출해 해제한다.
실제로 컴파일해서 실행했을 때 어떠한 문제없이 정상적으로 종료된다. 즉, 해제된 메모리를 다시 해제하는 것이 가능하다는 점을 확인할 수 있다!
char* a = (char *)malloc(100);
에서 메모리를 할당하면서 포인터 변수인 a에 할당했을 특정 힙 메모리의 주소가 저장된다. free(a);
를 해주면서 시스템의 힙 메모리 할당자의 구현에 따라 메모리가 해제되는데, 이 때 같은 포인터를 두 번 해제하는 비정상적인 일이 발생하면서 공격자가 프로그램을 예상치 못한 실행 흐름으로 만들 수 있다.
예제 - (2) dfb1 : Double Free 방지하기 (ptmalloc2에서)
#include <stdlib.h>
int main()
{
char* ptr = malloc(32);
char* ptr2 = malloc(32);
free(ptr);
free(ptr);
return 0;
}
△ dfb1.c (dreamhack에서는 포인터마크인 *이 빠져있다!)
(Ubuntu 18.04(glibc 2.27)에서는 위와 같은 에러가 발생하지 않았다! __ 혹시 잘못된 거라면 알려주세요..!!!)
📌 (Double Free 발생원인)double free or corruption (fasttop)
의 에러가 발생하는 원인은
if (__builtin_expect (old == p, 0)
{
errstr = "double free or corruption (fasttop)";
goto errout;
}
ptmalloc2 할당자에 double free를 방지하기 위해 동일한 힙 청크를 연속으로 여러 번 해제할 수 없도록 한 코드가 있기 때문이다.
⇒ old
(이전에 해제한 힙 청크의 포인터)와 p
(현재 해제할 힙 청크의 포인터)가 같다면 errstr을 출력하고 errout 비정상 종료한다.
예제 - (3) : Double Free 검증 우회하기
#include <stdlib.h>
int main()
{
char *ptr = malloc(32); // 0x602010
char *ptr2 = malloc(32); // 0x602030
free(ptr);
free(ptr2);
free(ptr);
return 0;
}
△ dfb2.c (double free를 검증하는 파트를 우회하는 코드)
두 번째로 ptr을 free하는 부분에 breakpoint를 걸고 실행했을 때 heap의 구조를 살펴보면 아래와 같다.
이 때는 아직 double free가 발생하기 전이다.
fastbin[0] | fastbin[1] |
---|---|
0x0 | 0x602000 -> 0x602030 -> 0x0 |
이제 두 번째 free(ptr)
을 실행시켜 double free가 발생하도록 하고 heap 구조를 다시 살펴보면 아래와 같다.
fastbin[0] | fastbin[1] |
---|---|
0x0 | 0x602030 -> 0x602000 -> 0x602030 |
ptr을 한 번 더 해제한 fastbin freelist에 중복된 주소가 들어가는 것을 알 수 있다.
⇒ fastbin에서 double free가 발생하고 같은 bin의 크기로 할당 요청이 들어온다면 0x602030
, 0x602000
, 0x602030
에 순차적으로 힙을 할당해 두 개의 객체가 하나의 메모리(0x602030)를 사용할 수 있게 된다.
Double Free 버그에 대한 이해를 했으니 이제 Double Free를 이용한 기본적인(?) 공격방법에 대해 공부해보자!
▶ Fastbin Dup
▶ Fastbin Dup Consolidate
(추가 예정....)
'System > System Hacking' 카테고리의 다른 글
[Heap] The House of Spirit (0) | 2020.09.30 |
---|---|
[Heap] UAF(Use-After-Free) (0) | 2020.09.19 |
[Heap] Security Check (0) | 2020.09.13 |
[Heap] ptmalloc2 (0) | 2020.09.12 |
Return to csu (ft. Return-to-vuln, Just-In-Time Code Reuse) (0) | 2020.08.15 |