Format String Bug란
포맷스트링을 인자로 사용하는 함수인 printf, scanf, fprintf 등의 함수들은 포맷스트링에 채울 값들을 스택 또는 레지스터에서 가져온다.
그런데 이들 내부에는 필요로 하는 인자의 개수와 함수에 전달되는 인자 개수를 비교하는 루틴이 없다.
=> 악의적으로 다수의 인자를 요청하거나 원하는 위치에 스택 값을 읽거나 쓰기가 가능
해당 취약점을 Format String Bug 라고 한다.
실생활에서는 자주 볼 수 있는 취약점은 아니지만 워게임에서 매우 자주 등장하는 취약점이다.
포맷스트링
포맷스트링의 구성
-> %[parameter][flags][width][.prceison][length][spcifier]
specifier(형식 지정자)
- d(부호있는 10진수 정수)
- u(부호없는 10진수 정수)
- s(문자열)
- x(부호없는 16진수 정수)
- n(해당하는 위치의 인자에 사용된 문자열의 길이를 저장. 출력은 하지 않는다.)
- p(포인터)
width(너비 지정자)
- 정수(정수의 값 만큼 최소너비 지정)
- *(인자 두개 사용, 첫 인자만큼 너비 지정 후 두번째 인자 출력)
length : 출력하고자 하는 변수의 크기 지정
- hh(해당 인자가 char 크기임을 나타냄)
- h(해당 인자가 short int 크기임을 나타냄)
- l(해당 인자가 long int 크기임을 나타냄)
- ll(해당 인자가 long long int 크기임을 나타냄)
ex) 만약 char형을 정수 형태로 나타내고 싶다면 %hhd를 사용
parameter : 참조할 인자의 인덱스 값 지정 ex) %[parameter]$d
** 파라미터 값이 전달된 인자의 갯수의 범위 내인지 확인하지 않는다 **
스택 안에서 parameter 사용시 rsp기준 offset 으로 값을 지정함
ex) format -> %7$saaaa(rsp) + p64(addr)(rsp+8)
포맷스트링을 사용한 FSB 예시(aar만)
다음과 같은 FSB 취약점을 가진 코드가 있다고 하자.
#include <stdio.h>
#include <unistd.h>
int main()
{
char buf[0x30];
read(0, buf, 0x30);
printf("result is : ");
printf(buf);
return 0;
}
사용자가 입력한 데이터를 printf()함수의 포맷스트링 인자로 그대로 사용하고 있다.
위에서 설명한 포맷스트링을 이용하여 FSB가 어떤식으로 일어나는지 보자.

%p를 여러개 포맷스트링 인자로 줬다.
무슨 주소인지는 모르지만 어딘가의 주소를 참조해서 그대로 출력해주고 있다.
이처럼 개발자의 의도와는 다르게 공격자 입장에서 특정 주소를 유출 시킬 수가 있다.
위 출력값에서 차례대로 rdi, rsi, rdx, rcx, r8, r9, rsp, rsp+8... 값을 가진다.

위 예시는 특정 주소나 값을 유출할 수 있는 즉, aar 취약점이다.
앞서 설명한 파라미터와 %n 서식지정자를 이용하여 FSB 취약점을 통해 임의 주소에 값을 쓰는 aaw도 가능하다.
'PWN > 개념' 카테고리의 다른 글
| ROP에서 dup2를 이용한 리버스쉘 (0) | 2025.08.20 |
|---|---|
| Pwntools를 이용한 ROP 페이로드 작성 방법 (2) | 2025.07.30 |
| Double Free Bug(DFB) 취약점 (2) | 2025.07.26 |
| Use After Free(UAF) 취약점 (2) | 2025.07.25 |
| ptmalloc2 - Memory Allocator in Linux (1) | 2025.07.24 |