본문 바로가기
System Hacking

포맷 스트링 공격 (Format String Attack)

by zz! 2024. 10. 15.
728x90

예전에 작성한 포스팅이 있지만, 다시 한번 정리를 해보겠습니다. printf 출력 함수 사용 방법 포스팅에서 "3. printf 함수 형식 지정자" 부분을 읽고 오시는 것이 도움이 됩니다.

 

C언어에서의 포맷 스트링 (Format String) 취약점

"printf"와 같은 함수를 사용할 때 주의해야 할 보안 취약점 중 하나가 포맷 문자열 취약점이다.이 취약점은 프로그램이 사용자 입력을 적절히 검증하지 않고 포맷 문자열 함수(printf, fprintf 등)에

wsul.tistory.com

 

 

#1 C언어 printf 출력 함수 사용 방법

C언어 프로그래밍에서 출력은 매우 중요한 역할을 하고 있습니다. 이를 담당하는 함수 중 가장 널리 사용되는 것이 "printf" 함수입니다. 이번 포스팅에서는 C언어의 'printf' 함수에 대해 자세하게

wsul.tistory.com

포맷 스트링 공격은 소프트웨어 취약점 중 하나입니다. 사용자가 입력한 데이터를 잘못된 방식으로 처리할 때 발생할 수 있습니다. C언어에서 많이 나타내며, 포맷 스트링 공격을 이용해서 취약한 프로세스를 공격하거나 메모리 내용을 읽거나 쓸 수 있습니다. 그 결과로, 공격자는 취약한 프로세스의 권한을 획득하여 임의의 코드를 실행할 수 있습니다.

 

1. 포맷 스트링이란?

C언어에서 printf() 등의 함수에서 사용되는 문자열의 입 출력 형태를 정의하는 문자열로 서식 문자열이라고 표현합니다.

printf("내 이름은 %s 이고, 나이는 %d 이야\n", "Alice", 30);

출력 :

위의 예시에서 포맷 스트링 %s 와 %d를 사용해서 문자열과 정수를 출력하는 코드입니다. 이 기능을 적절히 사용하지 않으면 보안 취약점이 될 수 있습니다.

 

2. 포맷 스트링 공격의 원리

앞서 말한것처럼, 포맷 스트링 공격은 프로그램이 사용자 입력을 포맷 스트링으로 잘못 처리할 경우, 공격자가 프로그램의 메모리를 탐색하거나 조작할 수 있습니다.

#include <stdio.h>

int main(int argc, char *argv[])
{
	if (argc < 2)
	{
		printf("Usage: %s <input>\n", argv[0]);
		return 1;
	}
	
	// 입력된 인자값을 그대로 printf에 전달 (취약점이 발생) 
	printf(argv[1]);	// 취약점 
	printf("\n");
	
	return 0;
}

위의 소스코드는 포맷 스트링의 취약한 코드입니다.

위와 같은 결과로 프로그램의 메모리 내용을 출력하게 만듭니다. 공격자는 이것을 통해 스택의 메모리 정보를 읽어 올 수가 있습니다. 

(%n 을 이용해서 메모리 조작 공격을 하여 return address 값을 조작해서 하는 공격법도 있는데 드림핵 진도를 끝내고 정리를 하겠습니다.)

 

3. 포맷 스트링 대응 방안

printf() 함수에 포맷 지정자를 명시적으로 사용해서 포맷 스트링을 안전하게 처리해야 합니다.

#include <stdio.h>

int main(int argc, char *argv[])
{
	if (argc < 2)
	{
		printf("Usage: %s <input>\n", argv[0]);
		return 1;
	}
	
	// %s 를 추가합니다.
	printf("%s", argv[1]);	
	printf("\n");
	
	return 0;
}

다시 한번 실행을 해보면,

이렇게 입력된 문자열이 단순히 출력되도록 해서 대응을 할 수 있습니다.

728x90