본문 바로가기
Computer Science/Security

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

by Bloofer 2021. 5. 28.

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

포맷스트링 공격은 프로그램에 입력된 문자열 데이터가 명령으로 해석될 때 발생합니다. 이러한 방식으로 공격자는 코드를 실행하거나 스택 메모리 일부를 읽거나 실행중인 프로그램에 Segmentation Fault를 발생시켜 시스템에 의도되지 않은 동작을 일으킬 수 있습니다.

 


포맷스트링의 3가지 개념

 

포맷 함수(Format Function)

프로그램 언어의 변수를 사람이 읽을 수 있는 문자열 형식으로 변환하는 printf, fprintf와 같은 ANSI C 함수입니다.

 

표1. 포맷 함수의 예시

Format function Description
fprint Writes the printf to a file
printf Output a formatted string
sprintf Prints into a string
snprintf Prints into a string checking the length
vfprintf Prints the a va_arg structure to a file
vprintf Prints the va_arg structure to stdout
vsprintf Prints the va_arg to a string
vsnprintf Prints the va_arg to a string checking the length

 

포맷 스트링(Format String)

포맷 함수의 인자이며 다음과 같은 텍스트 및 포맷 인자를 포함하는 ASCII 문자열입니다.

printf("The magic number is : %d\n", 1911);

 

포맷스트링 인자(Format String Parameter)

%x %s와 같은 포맷스트링 인자는 포맷 함수의 변환 형태를 정의합니다. 프로그램이 전달된 스트링 입력의 유효성을 제대로 확인하지 않으면 공격을 받을 수 있습니다. 이 경우 %x와 같은 포맷스트링 인자가 데이터에 삽입되면 해당 문자열은 포맷 함수에 의해 파싱되고 인자에 지정된 변환이 일어납니다. 그러나 포맷 함수는 더 많은 인자 입력에 대한 예외 처리를 하지 않으면 함수가 스택을 읽는 등의 위험성을 내포합니다.

 

표2. 포맷스트링 공격에 사용되는 파라미터들

Parameters Output Passed as
%% % character (literal) Reference
%p External representation of a pointer to void Reference
%d Decimal Value
%c Character  
%u Unsigned decimal Value
%x Hexadecimal Value
%s String Reference
%n Writes the number of characters into a pointer Reference

 


포맷스트링 공격 예시

 

 

안전한 코드

printf('%s', argv[1]);

예제에서 라인 5의 프로그램을 컴파일하고 실행하면 안전합니다.
./example 'Hello World %s%s%s%s%s%s'

첫 번째 줄의 printf는 입력 문자열의 "%s%s%s%s%s%s"를 파싱하지 않으며 출력은 다음과 같습니다.

"Hello World %s%s%s%s%s%s”

 

위험한 코드

printf(argv[1]);

예제에서 라인 8의 프로그램을 컴파일하고 실행하면 위험합니다.
./example 'Hello World %s%s%s%s%s%s''

두 번째 줄의 printf는 입력 문자열의 %s%s%s%s%s%s를 문자열 포인터에 대한 참조로 파싱되므로 모든 %s를 문자열에 대한 포인터로 해석합니다. 특정 시점에서 잘못된 주소에 도달하여 액세스를 시도하면 프로그램이 중단됩니다.

 

다른 포맷스트링 인자 사용

공격자는 이 정보를 사용하여 스택 메모리에 관한 정보도 얻을 수 있습니다. 예를 들어 다음을 실행할 경우,
./example 'Hello World %p%p%p%p%p%p'

다음과 같은 결과가 나타날 수 있습니다.
Hello World %p%p%p%p%p%p
Hello World 000E133E 000E133E 0057F000 CCCCCCCC CCCCCCCC CCCCCCCC
첫 번째 줄은 안전한 방식의 printf 버전에서 출력되고 두 번째 줄은 위험한 방식에서 출력됩니다. "Hello World" 텍스트 뒤에 출력된 값은 이 예제를 실행하는 순간의 스택에 있는 메모리 주소입니다.

또한 일부 조건에서는 메모리 위치에 대한 읽기 및 쓰기가 가능하며 코드 실행도 가능합니다.

 

다른 포맷함수 예시

printf 계열의 포맷 함수들은 모두 위험성을 내포합니다. 다음은 snprintf의 예제입니다.

 

이 프로그램을 다음과 같이 실행하면 앱 크래시가 발생합니다.
./example 'Hello World %s%s%s%s%s%s'

 

출처: owasp.org