첫번째 과제가 주어졌다.
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 |