[9] Memory Corruption - C (2) :: Format String Bug(FSB)

본 글은 DreamHack의 강의 내용을 요약한 글이므로 자세한 내용은 dreamhack.io 에서 학습하시길 바랍니다. 

 

해커들의 놀이터, Dreamhack

해킹과 보안에 대한 공부를 하고 싶은 학생, 안전한 코드를 작성하고 싶은 개발자, 보안 지식과 실력을 업그레이드 시키고 싶은 보안 전문가까지 함께 공부하고 연습하며 지식을 나누고 실력 향

dreamhack.io

 

학습목표

C언어에서 발생할 수 있는 Memory Corruption 취약점 중 Format String Bug을 알아본다.

 

1. Format String Bug

printf 또는 sprintf와 같이 format string을 사용하는 함수에서 발생하는 취약점

%x 나 %s 와 같이 프로그래머가 지정한 문자열이 아닌 사용자의 입력이 format string으로 전달될 때 발생한다.

 

발생 원리

출처 : dreamhack.io

왼쪽 코드에서 printf의 인자인 buf를 사용자의 입력을 통해 전달 받는다 했을 때,

사용자가 입력한 문자열이 오른쪽 1번째 코드 "asdf"와 같이 일반 문자열이라면 큰 문제가 없지만,

2,3번째의 %x, %s 같은 format string이 들어간다면 인자 전달이 아닌 format string을 전달한 것으로 취급되어

프로그래머가 의도하지 않은 동작을 수행할 수 있게 된다.

 

 

2. Format String Bug 실습

실습 1. %x, %s를 문자열로 입력했을 때

[기본 코드]

출처 : dreamhack.io

- fsb-1.c

char형 배열 buf에 read함수로 100바이트를 입력 받아 printf 함수로 입력받은 버퍼를 출력하는 코드

 

이 때, "asdf" 또는 "10"과 같은 일반 문자열을 입력하면 printf문은 각각

printf("asdf"); 와 printf("10"); 가 되어 정상적으로 문자열 출력이 수행된다.

 

그러나 "%x %s"와 같은 format string을 문자열로 입력할 시 printf(buf)는 printf("%x %s")가 되는데

보통 2번째, 3번째 인자에 값을 같이 주게 되면, %x와 %s는 형식 지정자로써 2,3번째에 전달된 인자를 

각각의 형식에 맞추어 정상 출력하지만, 2번째, 3번째 인자를 전달하지 않은 상태에서 1번째 인자로 format string이 입력된다면 쓰레기 값을 인자로 취급해 화면에 출력한다.

출처 : dreamhack.io

 

실습 2. fprintf 함수에서 발생하는 FSB

[기본코드]

dreamhack.io

- fsb-2.c

fprintf 함수의 2번째 인자는 format string이어야 한다.

그러나 line12에서 보면 fprintf의 2번째 인자가 format string이 아닌 사용자의 버퍼이다.

이 부분에서 format string bug가 발생하게 된다.

실습1과 마찬가지로 %x나 %d 와 같은 format string 입력 시 의도치 않은 값이 파일에 저장된다.

 

드림핵에 있는 코드를 바탕으로 ubuntu에서 실습을 진행해 보았는데

log.txt 파일에 실제로 의도치 않은 값이 저장된 것을 확인할 수 있었다.

 

실습 3. FSB로 flag 출력해보기

[기본코드]

출처 : dreamhack.io

- fsb-easy.c

flag 변수의 값을 %x 표시자를 통해 16진수로 출력해보는 실습이다.

위의 코드를 보면 buf로 32byte만큼 값을 읽어들이고 이를 printf로 출력한다.

 

(1) 일반 문자열은 stack 이동 없이 문자열 그대로 출력한다.

 

(2) %x 같은 format string을 만난다면 esp+0x4 만큼 움직여서 4byte씩 출력한다. - %x는 16진수로 출력

 

풀이

stack을 보면 다음과 같다.

input으로 %x를 1번 입력하면 4바이트 만큼 읽어올 것이다. 

flag에 있는 값을 빼오기 위해서는 %x를 10번 반복해야 한다.

그렇게 되면, 총 40 byte의 값을 16진수로 가지고 오게 된다. (print_stackframe 4 + buf 32 + flag 4)

 

dreamhack.io

Q. 함수 호출 규약에 따라 printf 에서 %x format string은 esp + 4부터 4바이트씩 가져온다는 설명이 있었는데 왜 esp + 0이 아닌 esp + 4부터인지 모르겠다. 뭔가 메모리 구조와 관련 있을 듯 한데 한번 찾아봐야겠다.

 

 

3. FSB 정리

FSB는 format string을 사용하는 함수의 인자만 잘 검토하면 되므로 다른 취약점에 비해 막기 쉽다.

최신 컴파일러에서는 format string으로 전달되는 인자가 문자열 리터럴이 아닐 경우 경고 메시지를 출력하므로 요즘에는 잘 발생하지 않는 취약점이다. 

그러나 발생하면 프로그램에 큰 영향을 줄 수 있기 때문에 항상 염두에 두어야 한다

 

※ 리터럴 vs 상수 : https://mommoo.tistory.com/14

 

표준 C 라이브러리에서 format string을 사용하는 대표적인 함수

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

위의 함수들을 사용할 때는 검증되지 않은 입력이 format string으로 전달되지 않는지 주의해야 한다.

 

 

출처 : Memory Corruption - C (II) (DreamHack, https://dreamhack.io/learn/12#1)