관리 메뉴

c0smicb0y

[Hackerschool F.T.Z] Level11 본문

정보보안/Hackerschool FTZ

[Hackerschool F.T.Z] Level11

2015. 2. 5. 03:07

정보보안 스터디를 시작했다. 간단한 면접 후 합격을 통보해준댔는데 다행히도 합격했다. 면접이라고 했는데 사실상 Hackerschool FTZ Level11을 Format String Bug로 풀어오라는것이였다. 아는게 아무것도 없는데 매우 당황했다. 다들 FTZ 로컬서버를 구축해서 풀던데 나는 그냥 텔넷으로 직접 접속해서 풀었다. 접속방법은 이러하다 텔넷을 열고,



o ftz.hackerschool.org 라고 입력하면 ftz 서버에 접속할 수 있다.


login에 level11을 적고, Password에 what!@#$? 라고 적으면 level11에 접속할 수 있다.


파일과 폴더의 목록을 볼 수 있는 명령어인 ls를 입력하여 뭐가 있는지 살펴보자.


-l 이나 -al 옵션을 주어서 좀 더 자세하게 살펴볼 수 도 있다.


파일명에서도 알 수 있듯이 attackme 파일에 공격을 하면된다. 실제로 이 파일에 suid가 설정되어 있으니 공격을해서 쉘을 획득하면 현재 사용자의 권한보다 상승된 권한으로 명령을 내릴 수 있다.


hint를 한 번 보자.


아마도 attackme의 소스코드를 보여주는 듯 하다.

입력인자를 str에 복사해서 printf함수로 str을 출력하는 단순한 프로그램이다.

실제로 attackme에 인자를 주고 실행을 해보면,


인자가 그대로 출력되는걸 볼 수 있다.


이 프로그램에는 두가지의 취약점이 있다.


strcpy는 입력크기를 제한하지 않기 때문에 버퍼 오버플로우가 발생할 수 있고, printf함수를 저렇게 서식문자를 통하지 않고 바로 포인터변수를 가지고 사용하게 되면 FSB가 발생하게 된다. 


gdb를 통해 main함수를 disassemble하면 

밑줄 친 부분이 str[256]을 할당해준 것이라고 짐작할 수 있다.0x108을 10진수로 바꾸면 264이다. 소스코드에서는 256만큼의 크기지만 실제로는 264로 8만큼의 dummy가 들어갔다. 그리고 이래저래 실행되다가 거의 마지막쯤에 printf를 call하고 있다. 

여기서 FSB에 대해 알 필요가 있는데 printf함수를 저렇게 쓰게 되면 str내에 %8x같은 서식문자가 존재하게되면 그걸 그냥 문자열이 아닌 진짜 서식문자로 인식하게 되어 서식문자 하나당 스택의 4바이트씩 읽어서 출력을 하게 된다. printf와 str[256]사이에 공간이 좀 있을텐데 서식문자를 통해 그 길이를 가늠해보면,

서식문자가 4번 들어갔을때 AAAA의 아스키값인 41414141이 출력되는 것을 볼 수 있다.


이를 통해 스택을 구성해보면,

이렇게 될 것이다.


그리고 FSB에서 제일 중요한 서식문자인 %n(%hn)을 알 필요가 있다. 일반적으로 서식문자는 출력을 위해 사용되지만 %n(%hn)은 입력을 수행하는 서식문자이다. printf함수 안에서 출력된 바이트 크기만큼을 10진수로 저장하는 서식문자가 %n이다(%n은 4바이트 크기만큼 저장하고 %hn은 2바이트 크기만큼 저장한다).


이를 종합하여 공격코드를 구성해보면

./attackme  `python –c’print”AAAARET주소를 Little Endian으로 나타낸수%8x%8x%8x%쉘코드주소를 10진수로 바꾼 수c%n”’` 

하지만 여기서 문제가 발생한다. 쉘코드주소의 최대 크기는 0xffffffff인데 10진수 정수형으로는 이만큼을 표현을 하지 못한다. 그래서 쉘코드주소를 반으로 나누어서 입력할 것이다.

다시 공격코드를 구성해보면

./attackme  `python –c’print”AAAARET주소를 Little Endian으로 나타낸 수AAAARET주소+2를 Little Endian으로 나타낸 수%8x%8x%8x%쉘코드주소를 10진수로 바꾼 수c%n쉘코드주소의 반을 10진수로 바꾼 수c%n”’` 

그런데 문제는 아직도 존재한다. %n은 지금까지 나온 모든 바이트를 모두 세기때문에 쉘코드를 10진수로 바꾼 수앞에 나오는 문자들도 신경을 써줘야한다 AAAA(4) RET주소를 Little Endian으로 나타낸 수(4) AAAA(4) RET주소+2를 Little Endian으로 나타낸 수(4) %8x(8) %8x(8) %8x(8)이므로 4 + 4 + 4 + 4+ + 8 + 8 + 8 = 40이다. 그러므로 최종 공격코드는

./attackme  `python –c’print”AAAARET주소를 Little Endian으로 나타낸 수AAAARET주소+2 Little Endian으로 나타낸 수%8x%8x%8x%쉘코드주소의 반을 10진수로 바꾼 수-40c%n%쉘코드주소의 반을 10진수로 바꾼 수 앞 쉘코드주소의 반을 10진수로 바꾼 수c%n”’`


RET주소와 쉘코드주소를 구해서 대입만 하면 완성이다.


RET주소는 .dtors를 이용해서 알아낼 수 있다. gcc는 컴파일을 할 때 .ctors와 .dtors 두 세그먼트를 생성하는데, 이 두 영역의 특징은 .ctors 속성의 함수는 main전에 실행되고 .dtors 속성의 함수는 main종료 후에 실행 된다. 그러므로 main종료 후에 .dtors 속성의 함수가 실행되는 것을 이용해서 그 부분에 쉘코드가 있는 주소 값을 덮어 쉘코드를 실행시킬 수 있다.

.dtors주소는 쉽게 알아낼 수 있다.

0x0804960c에 4를 더해주면 그것이 RET주소가 될 수 있다.


쉘코드주소는 eggshell이라는 것을 이용하여 환경변수에 쉘코드를 등록한 후 그 주소를 RET에 집어넣으면 쉘코드를 실행시킬 수 있을 것이다. eggshell을 컴파일하여 실행하면

저것이 쉘코드주소이다.


최종코드를 구성하기 위해 몇가지 계산을 해보자.

일단 RET주소를 Little Endian으로 나타내보자

RET주소 = 0x08049610 -> \x10\x96\x04\x08

RET주소 + 2 = 0x08049612 -> \x12\x96\x04\x08


쉘코드주소의 반을 10진수로 나타내면

쉘코드주소의 반 = 0xf2d2 -> 62162

쉘코드주소의 반 = 0xbfff -> 49151


쉘코드주소의 반(전자) - 40 = 62162 - 40 = 62124

쉘코드주소의 반(후자) - 쉘코드주소의 반(전자) = 49151 - 62162 = 음수

음수가 나오기 때문에 0x1bfff로 계산한다.

114687 - 62162 = 52525


최종 공격코드에 대입하여 코드를 완성시키면

./attackme `python -c'print"AAAA\x10\x96\x04\x08AAAA\x12\x96\x04\x08%8x%8x%8x%62124c%n%52525c%n"'`


이것으로 공격을 해보자.




엄청난 공백의 출력뒤에 쉘이 실행되었다!


id명령어를 통해 권한을 살펴보면

level12로 권한이 상승된 것을 볼 수 있다.


my-pass명령어를 통해 level12의 비밀번호를 살펴보면,


it is like this 라고 한다.


이 레벨은 주로 버퍼 오버플로우를 통해서 통과한다고한다. FSB를 통해서 풀이하는건 level20과 별반차이가 없다고하다. 그래서 level11을 FSB로 풀었으면 FTZ를 더 이상 풀지 않아도 된다고해서 바로 LOB로 넘어가게 되었다.



Comments