기준

공격 방법

매개변수
형식
%d
정수형 10진수 상수(integer)
%f
실수형 상수(float)
%lf
실수형 상수(double)
%c
문자 값(char)
%s
문자 스트링((const)(unsigned) char *)
%u
10진수 양의 정수
%o
8진수 양의 정수
%x
16진수 양의 정수
%s
문자열
%n
int*(총 비트 수). 문자가 출력되기 시작해서 "%n" 이 나오는 시점까지의 출력해야 할 문자들의 개수를 세어 주어진 변수에 저장하는 역할을 한다. 포맷 스트링 공격에 이용된다.
%hn
%n의 반인 2바이트 단위. 포맷 스트링 공격에 이용된다.

포맷 스트링 공격의 변수 형식입니다.

  • printf
  • sprintf / snprintf
  • fprintf
  • vprintf / vfprintf
  • vsprintf / vsnprintf

표준 C 라이브러리에서 포맷 스트링을 사용하는 대표적인 함수들입니다.

위의 변수와 함수를 보더라도 이해하기 어려운 부분이 많습니다.

포맷 스트링은 위의 함수에서 개발자가 지정한 함수가 아닌 사용자로부터 스트링 해서 받을 때 일어날 수 있는 취약점입니다.

 

예 )

#include <stdio.h>

int main(void) {

char buf[100] = {0, };

read(0, buf, 100);

 

printf(buf);}

 

위와 같은 C가 있다고 하면 buf를 사용자로부터 100바이트까지 입력받을 수 있는 구조입니다.

 

하지만, 여기에서 printf함수에 사용자 입력값(asdf)이 적용될 때 printf("asdf")와 같이 입력됩니다.

이때 입력 값이 매개변수(%x %d)로 입력된다면 printf("%x %d")와 같이 입력되는 것입니다.

 

위에서 읽었다시피 %x는 16진수이며 %n은 10진수인데 printf와 만나 출력합니다.

이때 사용자의 입력값은 평범한 사용자의 입력값이 아닌 포맷 스트링으로 적용됩니다.

%x는 버퍼의 주소를 불러오게 되고 %d는 버퍼에서 얼마나 입력받을 수 있는지 알게 되는 것입니다.

 

패턴 1 - %n%n%n%n%n%n%n%n%n%n,

패턴 2 - %s%s%s%s%s%s%s%s%s%s,

패턴 3 - %1!n!%2!n!%3!n!%4!n!%5!n!%6!n!%7!n!%8!n!%9!n!%10!n!

패턴 4 - %1!s!%2!s!%3!s!%4!s!%5!s!%6!s!%7!s!%8!s!%9!s!%10!s!

 

위의 패턴은 주통가이드에서 권고하고 있는 패턴입니다.

위의 패턴과 달리 %n을 이용하여 공격자가 의도하는 악성 패턴이 있는 주소로 RET 하는 방법도 있습니다.

 

이처럼 print함수로 인해 발생되는 취약점인데 이는 개발자의 실수로 인해 발생되는 경우가 많지만 소스를 보고 분석한다면 충분히 발생 가능한 취약점입니다.

 

포맷 스트링은 print함수의 사용자 입력 값을 매개 변수로 오해하여 %d를 입력했을 때, 메모리에 있는 값을 10진수로 출력하고 %s는 문자열로, %x는 16진수로 출력하는 것이라 생각합니다.

 

(개인적으로 설명을 하기 위한 자료를 찾기 어려운 취약점이었습니다ㅠㅠ)

 

취약점 발굴 시에 보통 사용자의 입력 값을 매개변수를 정하지 않고 받는다면 취약점이 있을 확률이 매우 높다고 생각하면 될 것 같습니다.

 

제 설명이 붕 뜬부분이 많다고 생각돼서 공부할 수 있는 URL을 첨부하여 드립니다.

 

참고 : 

https://dreamhack.io/learn/12#4

 

로그인 | Dreamhack

 

dreamhack.io

https://dreamhack.io/learn/3#t194

 

로그인 | Dreamhack

 

dreamhack.io

+ Recent posts