본문 바로가기

Wargame/LOB(Redhat)

[Lv.1] Gate

LOB Redhat은 보호기법이 적용되어 있지 않은, 취약점이 무수히 많이 존재하는 환경입니다.


이 환경에서 Gate 문제는 기본적인 bof 취약점만 가지고 있기 때문에 쉘을 얻어낼 수 있는 방법 또한 다양합니다.


이걸 다 적기에는 제가 너무 힘들기 때문에 문제 풀 때마다 알려드리고 싶은 게 생각나면 다른 방법으로도 접근하는 방법을 보여드리고자 합니다.




Login :  gate

pass   :  gate



Gate 문제입니다. 코드를 보아하니 아주 대놓고 stack corruption을 일으켜주라고 하네요.


심지어 dep, aslr도 없기 때문에 스택에 쉘코드를 올려놓아 쉘을 띄우는 방법과 RTL, 환경변수에 쉘코드를 올려놓는 방법, argv[2]에 쉘코드를 올려놓는 방법, 


... 등등 여러 방법이 있습니다.


우선 기본적인 bof 방법으로 접근하도록 하겠습니다.



0x8048466은 strcpy 함수가 콜되는 부분이고 그 위의 push eax는 strcpy의 첫번째 인자인 buffer 입니다.

그 위의 push edx는 두번째 인자인 argv[1]이구요. 여기서 저희는 strcpy가 실행된 후 스택에 값이 어떻게 쌓이는지 확인하고 싶으므로

b* 0x804846b 를 합니다.




input에 a값을 256만큼 넣은건 gdb에서 편하게 input값을 확인하기 위함입니다. (디버깅할 때에 이런 방법이 있다는 걸 알려주기 위해 이런 방법을 써봤습니다.)

cat으로 출력해보니 256개가 잘 나오네요.




r `cat input` 으로 input 안에 있는 a 256개를 argv[1] 위치에 넣고 실행해봤는데. 실행되지 않습니다. 이건 gremlin의 권한이 gremlin, gremlin이기 때문에


gate 권한을 가지고 있는 저희들이 디버깅을 할 수 없는 환경이에요. 그러므로 gremlin 을 카피해서 저희들만의 분석환경을 만들어봅니다.




cp gremlin grem


이 명령어는 gremlin을 grem으로 복사하는 명령어입니다. 이렇게 복사하면 grem의 권한은 gate, gate이기 때문에 gdb로 디버깅할 수 있는 환경이 됩니다.



 

다시한번 grem에 붙어서 r `cat input`을 하면? (b* 0x804846b 로 strcpy밑에 브레이크 걸어놓은 상태입니다.)


스택에 값이 256개 쌓여있네요. 그 뒤에는 ebp 4바이트, return address 4바이트가 보입니다.


buffer의 시작주소가 0xbffff958 임을 알 수 있습니다. (기억해두세요)



간단한 그림으로 확인해보면 이런 상태입니다. input에 넣었던 a 256개가 buffer 공간을 다 채운 상태이고 그 뒤에는 이전 함수의 ebp인 sfp값, 그 뒤는 return address이지요.


저희는 쉘을 얻기 위해 return address를 조작하여 쉘코드가 있는 위치를 가리켜야 합니다.




정말로 스택에 쉘코드를 올려도 되는지 확인해볼까요?


bfffe000 - c0000000 rwxp fffff000 00 : 00 0


이 부분은 스택영역으로 읽기(r), 쓰기(w), 실행(x)권한이 있음을 알 수 있습니다. 실행권한이 있으므로 쉘을 올려놔도 잘 돌아간다는 뜻이지요.



테스트도 안해보고 그냥 바로 뙇! ..하면 Segmentation falut가 뜨네요. 제 기억에 Redhat 6의 환경에서는 "\xff" 와 "\x99"? 는 0x00으로 변환되는 문제점이 있습니다.

(저 문자들은 인식이 안됩니다.)


고로 bash2를 입력하여 bash2 환경으로 넘어가서 실행해보도록 합니다.




페이로드는 nop sled 100 byte + shellcode 24 byte + nop sled 136 byte + return address 4 byte 입니다.


리턴 주소는 0xbffff970으로 했는데 디버깅 환경에서 확인한 주소와 실제 환경의 주소와 +- 16 byte 정도 차이나기 때문에 (OS 환경에 따라 차이가 납니다.)


buffer의 시작주소인 0xbffff958로 안하고 넉넉하게 띄어 쉘코드를 실행하였습니다.


* nop sled에 대해 궁금하신 분은 제 글 중 Basic System Hacking Technique의 핸드레이 글을 참고하시길 바랍니다.


뒤에 굳이 nop sled를 넣어준 이유는 , 제가 redhat 6 환경에서 테스트해본 결과 특정 함수를 생성할 때에 ret 뒤에 nop 14~16바이트정도 붙습니다.

그냥 환경이 이러려니.. 하시고 쉘코드를 넣을 때 nop 16 ~20 byte 정도 넣어주시면 됩니다. 



또 다른 방법으로 접근하는 방법은,

RTL 을 이용할 수 있습니다. 이 지식은 여기서 나오기엔 이해하기 어렵고 헷갈릴지도 모르나 이런 방법이 있다는 것만 알아두시기 바랍니다.

기본적인 RTL은 제 글 중 Basic System Hacking Technique의 Return To Library 를 확인하시면 됩니다.




gremlin 바이너리는 /lib/libc.so.6 라이브러리를 쓰고 있습니다. 


이 라이브러리에서 printf나 scanf, system을 갖다 쓰고 있어, 실제 함수들은 이 라이브러리에 있다고 보시면 됩니다.


그리고 여기에는 /bin/sh 문자열이 박혀있는데 저희는 이 문자열이 들어있는 주소를 system 함수의 첫번째 인자로 사용할 수 있습니다.


확인해볼까요.



strings -tx /lib/libc.so.6 | grep "/bin/sh"


이 명령어를 입력하면 /lib/libc.so.6의 "/bin/sh" 문자열과 문자열이 위치한 곳의 주소를 16진수 형태로 출력해줍니다.


/bin/sh가 많네요. 여기서 전 0xe3ff9 주소에 위치한 문자열을 사용하도록 합니다.



공유 라이브러리의 system offset은 0x40ae0 입니다. 바이너리의 함수 주소들은 이런 고정주소들을 이용해 계산이 되지요.


제가 방금 전에 확인한 "/bin/sh"의 문자열 주소 0xe3ff9와 system offset 0x40ae0을 빼면?


0xa3519 라는 offset 이 나옵니다. 이걸 다시 system과 더하면? 문자열 주소를 가리키겠지요.


"/bin/sh"의 문자열 주소 - system 주소 = offset

system 주소 + offset = "/bin/sh"의 문자열 주소


라고 생각하시면 됩니다.


이걸 이제 실제 바이너리에서 확인해보도록 합니다.



공유라이브러리가 바이너리에 붙은 상태여야 하기 때문에 b* main, r 로 실행해준 뒤 p system으로 시스템 주소를 확인하고


p/x system + 0xa3519를 해주면 "/bin/sh"의 문자열 주소가 나옵니다.


여기서 저희는 system의 주소가 0x40058ae0이고 "/bin/sh"의 문자열 주소가 0x400fbff9라는 걸 알아냈습니다.


이제 이걸 이용해서 RTL 공격을 시도합니다.




쟈란! 페이로드는 더미값 260 byte + return address (system 주소) + 더미값 4 byte + "/bin/sh"의 문자열 주소 입니다.


쉘이 성공적으로 떴네요.


이걸로 Lv.1 을 마칩니다.


Login : gremlin

pass  : hello bof world


ps. 제가 생각나는걸 주저리주저리 적어놨으므로 처음 접하는 분들은 이해 안되는 부분이 있을 수밖에 없습니다. 이해안되면 댓글에 적어놓으세요.

필요에 따라 글을 수정하도록 하겠습니다.

'Wargame > LOB(Redhat)' 카테고리의 다른 글

[Lv.2] Gremlin  (0) 2016.04.10
들어가기 전, 편한 환경에서 풀기 위한 환경세팅  (0) 2016.04.07