DongDD's IT

Format String Bug - format string, FSB, Example 본문

IT 보안/System

Format String Bug - format string, FSB, Example

DongDD 2018. 1. 17. 17:19

Format String Bug


Format String


- 변수의 출력 형식을 정해주는 인자를 의미한다.

- %d(정수), %f(실수), %s(string), %p(pointer), %x(16진수) 등이 있다.

- Format string bug에 주로 사용되는 인자

-> %n : *int(쓰인 총 바이트 수)를 저장하는 인자

-> %x : 16진수로 값을 알아오는데 사용되는 인자

-> %p : 0x를 붙인 16진수 값으로 출력하는데 사용되는 인자


Process(printf)

- 함수를 시작하기 전 함수에 인자로 사용된 값을 stack에 넣는다.

- printf 함수를 시작하면 함수 인자로 받은 argv[1]부터 먼저 읽는다.

- 인자를 읽다가 Format string을 만나게 되면 POP한 뒤 ESP가 가리키는 값을 Format string에 맞게 출력해준다.


포맷 스트링을 만나면 POP을 하고 ESP가 dec1을 가리키게 된다. esp에 해당하는 dec1값을 포맷 스트링에 맞게 출려해준다.



Format String Bug(FSB)


Definition : 포맷 스트링(%d, %s ...)을 사용하는 함수를 올바르게 사용하지 않았을 때 포맷 스트링에서 발생하는 취약점

-> printf, fprintf, syslog 등등..


Format String Attack : Format String Bug를 이용하여 공격하는 방법(Format String Bug와 같은 의미로 사용된다.)


Process


- buf라는 char형 배열을 사용자에게 입력받는다고 가정했을 때, printf(buf)와 같이 printf함수를 사용하게되면 사용자가 입력에 format string을 넣어 printf함수가 동작하도록 할 수 있다.

- 즉, printf에는 buf라는 인자가 하나지만 사용자가 format string을 입력할 경우 Format string을 만나게 되면 POP을 하고 ESP의 값을 출력하기 때문에 인접한 메모리의 값을 출력하게 할 수 있다.

- %n을 이용하여 원하는 값으로 바꿀 수도 있게 된다.

-> 현재까지 출력된 바이트 수를 %n을 이용하여 저장(이를 이용하여 원하는 만큼의 바이트를 출력한 후 그 값을 해당 주소에 넣을 수 있다.)

- %n을 임의로 이용하기 위해 %x나 %c를 이용해 원하는 값을 만들어 준 후 이후에 나오는 주소에 %n으로 저장한다.


Example


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main() {
    char ans[] = "A";
    char buf[1024];
    fgets(buf, sizeof(buf), stdin);
    printf(buf);
    printf("%x\n",ans);
    if(!strcmp(ans,"B")) {
        printf("FSB success!\n");
    }
    return 0;
}
cs


ans라는 buffer에 "A"가 들어가있고 fgets를 통해 buf를 입력받는다. 그 후 printf(buf)로 buf를 출력해주는데 여기서 FSB 취약점이 생긴다. 입력하는 값에 서식 문자가 들어간다면 printf(buf)에서 임의의 주소 값을 수정할 수 있게 된다.

printf("%x\n",ans)는 예제를 좀 더 쉽게 하기 위해 "A"가 들어가있는 ans의 주소를 출력해주게 만들었다.

FSB를 통해 ans의 값을 "B"로 바꿀 수 있다면 if문안으로 들어가게 된다.



먼저 위 프로그램을 실행해 서식 문자를 넣어 보았다. 그리고 예제를 쉽게하기 위해 answer주소를 출력해준다.

answer의 주소 : 0xbffff636


최신 OS 환경이나 gcc버전에 따라 출력되는 값이 바뀌어질 수 있다. 원래대로라면 fgets(buffer,sizeof(buffer),stdin)

에서 첫 번째 %x는 sizeof(buffer)의 값을 출력하고 그다음 %x는 stdin의 값을 출력해주고 그 후에 buffer에 들어간 값이 나오게 된다.

이 예제에서는 다르게 나오기 때문에 %x를 넣어보고 입력한 값이 어디에서 출력되는지 확인해봐야한다.


"A"를 8개 입력하고 %x를 통해 뒤에 있는 인접한 값들을 차례대로 읽어본다. 입력한 "A"들이 16진수로 바뀌어있는 것을 볼 수 있다. 첫 번째 %x의 중간 부분부터 입력한 값이 읽히기 시작한다. 즉, 6 bytes만큼의 입력을 해준다면 첫 번째 %x(0x4141e550), 두 번째 %x(0x41414141)이 된다.


두 번재 %x에서 출력되는 값을 answer의 주소로 하기 위해 dummy값 2개와 answer의 주소를 입력한다.

그렇게 되면 2번째 %x는 입력한 answer의 주소를 나타내게 될 것이다.



첫 번째 %x는 입력한 "A" 두개의 값과 다른 값이 들어가있고, 두 번째 %x는 "AA"다음에 입력한 값이 그대로 출력되게 된다.

이제 %x와 %n을 이용해 0xbffff636에 있는 값을 수정해 줄 수 있다.


먼저 buffer의 값을 "B"(66)으로 바꿔야 if문을 통해 들어갈 수 있게 된다.

"AA"+buffer의 주소는 총 6bytes이고 이 후에 %x에 (66-6)만큼의 dummy값을 넣어주고 0xbffff636을 가리킬 때 %n을 통해 이 값을 넣어주면 앞에서 출력되었던 총 66bytes의 값이 0xbffff636에 들어가게 된다.

즉, buffer에 들어가있는 값이 66("B")으로 수정된다.

 

Payload = dummy(2 bytes) + buffer의 주소(4 bytes) + %넣을 값(66-60) + %n(buffer <- 66)



위와 같이 FSB success!라는 message를 볼 수 있다. 


dummy를 사용하는 이유는 바로 서식 문자를 사용해야 하기 때문이다. 바로 서식 문자가 들어가는 경우 이 서식 문자가 가리키는 곳은 비정상적인 값을 가리키게 된다.

그리고 %(value)x를 사용할 때는 10진수의 값을 넣어주어야 하고 앞에서 쓰인 문자 수 +공백 만큼을 계산해서 넣어줘야 한다.




'IT 보안 > System' 카테고리의 다른 글

Buffer overflow - Stack corruption  (0) 2017.09.05
Comments