Dangling Pointer
: 유효하지 않은 메모리 영역을 가리키는 포인터
malloc()
→ 할당된 메모리 주소 반환
1. 포인터를 선언
2. 포인터에 malloc()
함수가 할당한 메모리 주소 저장
3. 포인터를 참조하여 할당한 메모리에 접근
1. free()
함수 호출
2. free()
함수가 청크를 ptmalloc
에 반환, 청크의 주소를 담고 있던 포인터 초기화 X
⇾ free()
함수 호출 이후 프로그래머가 포인터를 초기화하지 않으면, 포인터는 해제된 청크를 가리키는 Dangling Pointer
가 됩니다.
⇾ Dangling Pointer
는 경우에 따라 공격 수단으로 활용될 수 있습니다.
해제된 메모리에 접근할 수 있을 때 발생하는 취약점
Dangling Pointer
로 인해 발생하기도 하지만, 새롭게 할당한 영역을 초기화하지 않고 사용하면 발생
malloc()
과 free()
함수는 할당 또는 해제할 때 메모리 데이터들을 초기화하지 않아서 새롭게 할당된 청크를 프로그래머가 초기화하지 않으면, 메모리에 남아있던 데이터가 유출되거나 사용될 수 있습니다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct NameTag {
char team_name[16];
char name[32];
void (*func)();
};
struct Secret {
char secret_name[16];
char secret_info[32];
long code;
};
int main() {
int idx;
struct NameTag *nametag;
struct Secret *secret;
secret = malloc(sizeof(struct Secret));
strcpy(secret->secret_name, "ADMIN PASSWORD");
strcpy(secret->secret_info, "P@ssw0rd!@#");
secret->code = 0x1337;
free(secret);
secret = NULL;
nametag = malloc(sizeof(struct NameTag));
strcpy(nametag->team_name, "security team");
memcpy(nametag->name, "S", 1);
printf("Team Name: %s\n", nametag->team_name);
printf("Name: %s\n", nametag->name);
if (nametag->func) {
printf("Nametag function: %p\n", nametag->func);
nametag->func();
}
}
$ ./uaf
Team Name: security team
Name: S@ssw0rd!@#
Nametag function: 0x1337
Segmentation fault
Name
으로 secret_info
의 문자열이 출력됐고 값을 입력한 적 없는 함수 포인터가 0x1337
을 가리키고 있습니다.
ptmalloc2
→ 새로운 할당 요청이 들어오면 요청된 크기와 비슷한 청크가 bin
이나 tcache
에 있는지 확인
→ 만약 있다면 해당 청크를 꺼내 재사용
Nametag와 Secret은 같은 크기의 구조체
→ secret
를 해제하고 nametag
를 할당하면, nametag
는 secret
과 같은 메모리 영역을 사용
→ free
는 해제한 메모리의 데이터를 초기화하지 않기 때문에, nametag
에는 secret
의 값이 일부 남아있게 됨
gef➤ heap-analysis-helper
[*] This feature is under development, expect bugs and unstability...
[+] Tracking malloc() & calloc()
[+] Tracking free()
[+] Tracking realloc()
[+] Disabling hardware watchpoints (this may increase the latency)
[+] Dynamic breakpoints correctly setup, GEF will break execution if a possible vulnerabity is found.
[*] Note: The heap analysis slows down the execution noticeably.
gef➤ c
Continuing.
[+] Heap-Analysis - __libc_malloc(56)=0x602260
[+] Heap-Analysis - free(0x602260)
[+] Heap-Analysis - __libc_malloc(56)=0x602260
[+] Heap-Analysis - __libc_malloc(1024)=0x6022a0
Team Name: security team
Name: S@ssw0rd!@#
Nametag function: 0x1337
Program received signal SIGSEGV, Segmentation fault.
gef➤ x/10gx 0x602260
0x602260: 0x7974697275636573 0x0000006d61657420
0x602270: 0x6472307773734053 0x0000000000234021
0x602280: 0x0000000000000000 0x0000000000000000
0x602290: 0x0000000000001337 0x0000000000000411
0x6022a0: 0x20676174656d614e 0x6e6f6974636e7566
gef➤ x/s 0x602260
0x602260: "security team"
gef➤ x/s 0x602270
0x602270: "S@ssw0rd!@#"
gef➤ x/gx 0x602290
0x602290: 0x0000000000001337
초기화되지 않은 secret_info
값과 code
값이 그대로 남아있습니다.
동적 할당한 청크를 해제한 뒤에는 해제된 메모리 영역에 이전 객체의 데이터가 남습니다. 이러한 특징을 이용하면 초기화되지 않은 메모리의 값을 읽거나, 새로운 객체가 악의적인 값을 사용하게 유도하여 프로그램의 정상적인 실행을 방해할 수 있습니다.