본문 바로가기

study/취약점

[취약점/공격] Format String Attack (FSB)

Format string bug(FSB) : 포맷 스트링을 이용한 공격 기법으로 print()함수의 취약점을 이용한다.

Format String Bug는 개발자의 실수로 print(buf) 이렇게 사용했을 때 입력값을 포맷 스트링으로 넣으면 입력값을 문자로 취급하는게 아닌, 서식 문자로 취급하여 취약점일 일어날 수 있다.

EX

fgets(bug, sizeof(buf), stdin)
printf(buf)

buf가 문자열일 때는 정상적으로 문자열로 인식하지만 서식문자를 넣었을 경우 문자열로 안보고 서식문자로 인식한다.

buf = "string"
buf = "%x %s"

buf 배열에 서식문자가 있을 경우, buf 배열을 가리키는 주소의 다음 4바이트 위치를 참조하여 그 서식 문자의 기능대로 출력한다.

 Format String : printf나 scanf에 쓰이는 서식문자

parameter 변수 형식
%d 정수형 10진수 상수(Integer)
%f 실수형 상수(Float)
%lf 실수형 상수(Double)
%c 문자 값(char)
%s 문자열
%u 양의 정수(10진수)
%o 양의 정수(8진수)
%x 양의 정수(16진수)
%n *int(쓰인 총 바이트 수) : 지금까지 출력한 바이트 수를 포인터가 가리키는 주소에 넣어줌
%hn %n의 반인 2바이트 단위
%p 포인터: 포인터가 가리키는 주소

 

서식문자의 기능대로 출력한다는 뜻 ->  %d를 입력했을 대 메모리에 있는 값을 10진수로 출력하고 %s는 문자열로, %s는 16진수로 출력한다.

EX2

#include <stdio.h>

int main() {
	char str[100];
    scanf("%s", str);
    
    print("올바른 출력 방법 : %s \n", str);
    
    print("잘못된 출력 방법 : ");
    print(str);
    
    return 0;
   }

출력1

Hello
올바른 출력 방법 : Hello
잘못된 출력 방법 : Hellof

printf(str)로 사용해도 문제가 없다 -> 이유: stdoi.h 헤더에서 printf함수는 printf(cnst char *a, ...); 로 정의되어 즉, 상수 포인터를 넣으면 출력이 된다.

printf("aaa")가 출력이 되는 이유는 "aaa"가 data영여에 저장된 aaa라는 문자열 리터럴의 주소이기에 출력이 가능한 것

=> 결국 printf(str)은 str이라는 포인터에 있는 문자열 주소이기에 출력이 가능하다.

 

출력2

Hello!%x
올바른 출력 방법 : Hello!%x
잘못된 출력 방법 : Hello!f1a12025

printf(str) = printf("Hello!%x")

따라서, printf(str)로 출력을 시켜버리면 버그가 발생하여 사용자의 입력값에 따라 메모라 상태가 유출될 수 있다.

 

포맷 스트링 버그를 이용한 메모리 출력

포맷 스트링 버그를 이용해서 메모리 값을 변조하는 것이 가능하다.

함수를 선언하게 되면 다음과 같은 순서대로 스택에 쌓이게 된다.

1. 인자

2. 다시 돌아갈 주소

3. 다시 돌아갈 ebp 주소

4. 그 함수 안에 있는 버퍼들

printf를 옳게 선언할 경우 메모리

printf를 틀리게 선언할 경우 메모리

 

순차적으로 아래있는 값을 가리키게 되어 출력이 된다.

만약, 인자 없이 print("%d")만 넣게 되면 인자로 정해두지 않은 곳을 가리키게 되어 메모리를 출력하게 된다.

 

EX3

#include <stdio.h>

int main() {
	int a;
    
    printf("aaabbbccc%n", &a);
    printf("\n a : %d", a);
    
    return 0;
}

출력

aaabbbccc
 a : 9

aaabbbccc -> 총 9바이트

숫자 9를 %n이 a라는 변수에 넣어주게 된다.

 

출처