본문으로 바로가기

C :: 포맷스트링

category Programing/C 2017. 3. 12. 22:07


첫번째 과제가 주어졌다.


1. K.Knock 홈페이지에 가입후 자기소개 남기기

2. 해커스쿨 FTZ Trainer10까지 완료후 인증샷을 첨부파일로 올리기

3. C언어

   - 변수란 무엇인가?

   - 자료형에는 뭐가 있을까?

   - 포맷스트링은 뭐지?

   *ppt로 제작해서 올리기


일단 1번과 2번은 완료했다.

이번에는 C언어에 대해서 알아가보도록 하자


3. 포맷스트링은 뭐지?


이 3번 과제가 가장 어려웠던것 같다.


포맷스트링에 대해 검색하면 포맷스트링 공격기법만 나오고 시원한 정의가 나오지 않았기 때문이다.


자 일단 포맷스트링이 무엇인지부터 알아보자


아래는 c언어에서 출력함수를 이용해 a라는 정수변수를 출력하는 한 줄을 작성해 본것이다.


printf("%d\n",a);


여기서 '%d' 이것이 포맷스트링의 한 종류라고 할 수 있다.


포맷 스트링의 종류를 알아보자



%d : 정수 출력

%f : 실수 출력

%c : 문자 출력

%s : 문자열 출력

%o : 8진수 출력

%u : 10진수 출력

%x : 16진수 출력

%n : 앞에 쓰인 총 바이트 수


즉 이 포맷스트링을 정의하면


'포맷스트링을 사용하는 함수에 대해, 어떤 형식 혹은 형태를 정해주는 문자열' 이라고 할 수 있다.


그렇다면 포맷스트링을 검색했을 때 결과화면을 도배했던 포맷스트링 공격이란 무엇일까?


과제는 아니라서 일단 대충 읽어봐도 너무 어려워보였지만 궁금증이 생긴이상 포기할 수 없다. 알아보자


일단 포맷스트링 공격에 대서 알기 위해선 C언어의 장벽에서부터 막힌다.


그동안 수박 겉핥기 식으로 배웠던 순간들이 후회가 되는 순간이다... 반성하자.


포맷스트링의 성질을 알아보기 위해서 다음 두 코드를 비교해보자


#include <stdio.h>          

                  

main(){                               

  char *buffer = "wishfree"; 

  printf("%s\n", buffer)      

}        


이에 대한 결과는 아래와 같다


wishfree


위의 코드는 buffer가 가르키는 주소에서 %s라는 문자스트링을 읽어서 wishfree라는 문자열을 출력하였다.

다음 코드를 보자


#include <stdio.h>                   

                                          

main(){                                   

  char *buffer = "wishfree\n"; 

  printf(buffer);                     

}              


이에 대한 결과는 아래와 같다


wishfree


위의 코드는 첫번째 코드와 동일한 결과를 출력한다. 보다 짧은 코드를 구현할 수 있기 때문에 많이 사용하지만


이 코드는 취약한 코드라고 할 수 있다.


첫번째 코드에서는 %s로 buffer의 형태를 알려주었지만 두번째 코드에서는 알려주지 않았다


이는 스파이가 접선자를 만날 때 인상착의를 모르는 상태로 접선하러 간것과 같다고 한다.


두번째 코드를 살짝 변형해서 메모리를 열람할 수 있다.


 #include <stdio.h>


main(){

char *buffer = "wishfree\n%x\n";

printf(buffer);

}


이에 대한 결과는 아래와 같다


wishfree

8048440 


%x\n만 추가했을 뿐인데 아까와 다르게 알수없는 숫자가 출력된 것을 볼 수 있다.


이것은 wishfree문자열이 저장된 다음 메모리에 존재하는 값을 출력한 것으로 16진수인 0x08028440을 뜻한다.


이처럼 포맷스트링 문자를 이용하여 메모리를 열람할 수 있는 취약점을 알아보았다.


다음으로 포맷스트링 문자를 이용하여 메모리를 변조하는 공격기법에 대해 알아보자


#include <stdio.h>


main(){

long i=0x00000064, j=1;

printf("i의 주소 : %x\n", &i);

printf("i의 값 : %x\n", i);


printf("%64d%n\n", j, &i);

printf("변경된 i의 값 : %x\n",i);

} 


이에 대한 결과는 아래와 같다


i의 주소 : bbffffd34

i의 값 : 64

                                                     1

변경된 i의 값 : 40


응..? printf는 4번 사용했는데 결과는 3줄만 출력되었다...;; 대략난감이다.


차근차근 알아가보도록 하자


4번째줄에서 long자료형을 사용하여 i라는 변수에 16진수 64를 넣었고  j라는 변수에 정수 1을 넣었다


5번째줄에서는 i의 변수가 저장된 곳의 주소값을 출력했다. (&p라는 것이 p라는 변수가 저장된 곳의 주소값을 반환한다는 뜻이다)


6번째줄에서는 변수 i의 값을 16진수로 출력한 것이다.


문제는 8번째줄부터이다.... 이부분이 핵심인것같은데 이해하기가 쉽지가 않다.


printf는 출력함수인데 왜 결과창에 공백이 생겨버린걸까...


또한, %64d..... 보통 %뒤에는 문자가 와서 포맷스트링이라고 불리는 것으로 알고있는데...




으아!!! 드디어 알아내버렸다... ㅋㅋㅋㅋ


우선 %64d는 %d를 64번 반복하라는 뜻이었다!


그렇게 되면 j의 값이 64번 즉, 1이 64번 출력될테고 그것은 총 64바이트가 될 것이다!


그리고 바로 뒤에있는 %n은 앞의 바이트수를 세기 때문에 i에는 10진수 64가 들어갈 것이고


그 다음줄에서 16진수의 형태로 i를 출력하기때문에 10진수 64는 16진수 40으로 바뀌어 결과적으로 변경된 i의 값은 40인 것이다.


WOW 내가 해냈다 ㅋㅋㅋㅋ 


근데 여기서 또 궁금증이 생긴다.... 큰일이다 잠을 못이룰지도..


%64d 를 통해서 1을 64번 출력하여 그 바이트수를 %d가 세었다. 그렇다면 출력된 64개의 1은 어디로 갔을까..?


드디어 알아냈다 ㅠㅠㅠㅠ 눈물난다 진짜 ㅋㅋㅋㅋ 이것은 위의 취소선이 잘못된것이었다.


%64d의 뜻은 %d를 64번 반복하라는 것이 아니라 64자리로 표현하라는 뜻이었다.


즉 1을 64자리로 표현하려고 하기 때문에 63개의 공백이 생기고 맨 뒤에 달랑 1하나가 있는것이었다.


자 코드를 해석했으니 거의 다왔다.


이것이 이 해킹기법의 핵심이다.


정보보안개론이라는 책에서는 이렇게 기술하고 있다.


 printf("%64d%n\n", j, &i)문에서 i가 공격하고자 하는 취약 함수의 ret 주소 값인데 %64d 부분에 공격 쉘(egg shell)의

주소 값을 계산하여 넣으면 어떻게 될까?


일단 가볍게 이해하면 %64d에 의해서 i의 값을 바꾸어버렸다. 그 뜻은 이 자리에 공격 쉘을 실행할 수 있도록 코딩한다면


루트권한을 획득 즉, 해킹에 성공할 수 있다는 것이다!


여기서 의문점은 ret주소가 무엇이냐와 주소 값을 왜 계산하냐는 건데


RET의 정의는 따로 나와있지 않아 여러군데를 검색해본 결과 RET이 하는일에 대해 알 수 있었다.


RET은 함수호출 과정을 통해 특정 위치로 분기하여 함수의 logic을 수행하고 다시 원래의 위치로 복귀하게 되는데


이 때 복귀 주소를 저장하고 있는 곳이 RET이라고 한다.


만약 이 RET값이 비정상적으로 세팅되어서 원래 위치가 아닌 다른 위치를 지시하고 있다면 그 프로그램은 비정상적인 곳으로


복귀되어 프로그램 종료 또는 시스템 명령 실행 또한 가능하게 되는것이다.


위의 함수에서 i가 바로 ret주소값이고 이를 잘 이용하면 쉘을 띄울 수 있는것이다. 굿굿!


이걸로 첫번째 과제 + 궁금증을 해결했다. 이제 마지막으로 과제를 총 정리하는 PPT만 만들면 과제는 끝이난다 ><



'Programing > C' 카테고리의 다른 글

C :: C언어의 기본  (0) 2017.03.18
C :: C언어란?  (0) 2017.03.17
C :: 자료형에는 뭐가 있을까?  (0) 2017.03.11
C :: 변수란 무엇인가?  (0) 2017.03.11
C :: C언어란?  (0) 2017.03.09