본문 바로가기

My Study/Exploit

RTL로 푼 해커스쿨 level11

아..^^ 하면서 도중에 문제 해결에 도움을 주신 전남대학교 정지훈 선배님께 감사의 말씀을 드리면서..

이 글은 RTL의 개념을 잡기에는 충분하나 실전이나 해킹대회에선 좀 더 응용을 해서 해야될 것입니다.
저도 공부를 하면서 쓰는 글이라 많이 부족할 수도 있고 모든 정보를 다 올릴 수 없습니다. 모르기 때문이죠 -.-;
제가 아는 선에서 최대한 이해하기 쉽도록 쓰도록 노력하겠습니다.
======================================================
RTL = Return To Library
말 그대로 입니다. 리턴 값을 라이브러리가 있는 곳으로 바꿔버린다는 것이지요.
왜 이런 방법을 사용하느냐??
아마 해커스쿨 문제를 푸신 분들이라면 아시겠지만 대부분 스택에 쉘코드를 넣어두고 리턴 주소를 쉘코드가 있는 곳으로 바꿔서 쉘을 떨치는 방법을 사용했을 것입니다. 저도 level20까지 풀면서 전부 스택에 쉘코드를 넣어두고 쉘을 따는 형식을 썼지요.
에그쉘도 스택에 쉘코드를 넣는 것이지요. 하지만! 더이상은 이런 방법이 통하지 않습니다. 옛날부터 말이죠...
요새는 거의다가 랜덤스택입니다. 즉, 스택 주소가 일정치가 않다는 것입니다. 공격하기가 힘들겠죠. 어떤 해킹대회 문제풀이를 보니 랜덤스택일 경우 반복문을 만들어서 계속 돌리버리더군요.
또 한가지 더 스택에서 코드실행을 막는 다는 것입니다. 쉘코드를 보면 쉘떨치는 코드입니다. 실행코드이죠. 실행코드!
그렇기 때문에 아무리 맞는 주소를 찾고 제대로 공격을 했다고 하더라도 스택에서 코드실행이 불가능하기 때문에 절대로 쉘을 떨칠수가 없습니다.

위 두가지 이유 때문에 더이상 예전에 쓰던 방법은 먹히지 않습니다. 그래서 나온 방법이 RTL방법입니다.
RTL방법은 스택에 쉘코드를 넣지도 않고 실행시키는 것도 아닙니다.
바로 리턴 주소를 우리가 실행시킬 라이브러리 안의 함수주소로 돌리는 것이지요.
아래 그림으로 표현을 해볼탠데 우리가 실행을 시켜볼 함수는 ( system 함수 입니다. )

스택 그림을 보시겠습니다.


예전에 쓰던 방법이 1번 방법입니다. 스택에 쉘코드를 넣어두고 BOF를 일으켜 그 주소로 리턴 값을 바꾸는 것 입니다.
지금 설명할 방법이 2번 방법입니다. 리턴 주소를 우리가 실행시킬 system함수 주소로 바꾸는 것입니다.
그러면 system함수 인자는 어떻게 전달할 것인가?? 그것도 BOF를 일으켜 자리에 맞게 전부 인자도 설정해 주시면 됩니다.

이제 system함수의 주소와 인자가 어떻게 전달되는지 봐보도록 하겠습니다.
( 넣을 인자는 하나이므로 첫번째 인자이고 당연히 ebp에서 ret를 건너뛰고 그 다음인 [ebp+8] 이겠지만요;; )

1. system함수 주소 구하기

위와 같이 간단히 코드를 짜주시고 정적이 아닌 그냥 컴파일을 해줍니다.

파일이 제대로 생겼습니다. 이제 test파일에서 system함수의 주소를 구하도록 하겠습니다.

사용한 명령어들에는 전부 빨간색 네모를 쳤습니다. system함수의 주소를 보니 0x4005f430입니다.
이제 주소는 구했습니다.

2. 인자 전달되는 방법 보기

아까 구했던 system함수 주소로 가보니 위에서 설명했듯이 [ebp+8] 위치에 인자가 있습니다. 인자도 어떤 위치에 넣어야 되는지 구했습니다.


이제 무엇을 해야할까요?? 공격해야겠죠. 하지만 하기전에 스택을 다시한번 보도록 하겠습니다.

왼쪽 그림, BOF일으켜서 main함수 ret부분을 system함수 시작 주소로 바꿔주고 main함수 [ret+8] 자리에는 system함수 인자를 넣어줍니다. 그 후 실행을 하면 오른쪽 그림처럼 나오게 되죠. 이해가 되셨나요?? 직접 주소값 확인과 위 그림을 보시면 아마 이해가 가실 것입니다. 이제 쉘을 떨치는 공격을 해보겠습니다.

system함수 인자로 전달 될 문자열은 무엇이냐면 .. 바로 " /bin/sh " 입니다.
그러면 "/bin/sh"는 어떻게 넣을 것이냐?? 바로 환경변수를 이용하려 했으나.. 랜덤스택일 경우를 고려해서 환경변수를 이용하는 방법은 안될거 같습니다. 어떻게 해야할까요??

전 이 부분에서 막혔습니다. 그래서 정지훈 선배님이 말씀해 주시기를...

" system함수가 내부에서 /bin/sh -c를 사용해서 인자로 전달된 프로그램 실행하는거 알지?? "

전 몰랐습니다. 그래서 바로 실험을 해보았습니다.

오호!!!! +_+ 정말 되는군요. 이제 힌트를 얻었습니다. 무엇이냐구요??
" /bin/sh " 문자열을 입력해서 하려고 하지말고 라이브러리에 있는 " /bin/sh " 를 사용하면 될꺼같습니다.
라이브러리에 " /bin/sh " 문자열이 있는 위치만 찾으면 모든 문제는 해결 될거같습니다.
처음에 어떻게 찾을까..고민했습니다. 선배님 말씀으로는 system함수 내부 잘 뒤져보면 나올 것이다..라고 말씀해 주셨는데..
조금 해본결과 시간이 걸릴꺼 같아서 다른 방법을 생각해보았습니다.

=========================================
라이브러리에서 " /bin/sh " 있는 위치 찾기
=========================================

system함수가 어떤 라이브러리에 있는지 위치 확인

system함수에 들어왔을 때 멈춰보니 libc.so.6 라이브러리에 있다고 나옵니다. 해당 파일을 윈도우에서 ida로 열어보았습니다.
그리고 "/bin/sh" 가 어디 있는지 찾아보았습니다.

찾아보니 .rodata 섹션에 있습니다. 이제 .rodata섹션에 대한 정보를 얻기위해 libc.so.6 파일의 섹션헤더를 보겠습니다.

하지만..해당 섹션의 offset값만 나와있지 윈도우에서 해당하는 imagebase 주소 같은건 없는거 같았습니다.
 ( 있다면 어떻게 보는지 좀 알려주세요 ㅜㅜ )
그래서 전 imagebase구하는 방법을 아래와 같이 했습니다.

실제 파일상에서 실행되는 system함수 주소 - libc.so.6 안에 있는 system함수 주소

실제 파일상에서 실행되는 system함수 주소는 위에서 구했으므로
libc.so.6안에있는 system함수 주소를 구해보겠습니다.

구했습니다. 0x41430
이제 두 값을 빼주고 .rodata offset값을 더해주겠습니다.

0x4005f430 - 0x41430 + 0x118da0 = 0x40136DA0

파일이 실행될 때 .rodata 주소를 구했습니다. 이제 " /bin/sh " 가 .rodata에서 얼마만큼 떨어져 있는지 구하겠습니다.
그냥 ida에서 계산했습니다. ( 어짜피 자세히 주소 안 구해도 " /bin/sh "근처 주소가서 x/1000bs [주소] 이런식으로 그냥 찾아버리는 방법이 더 편하더군요. 머리가 아파요.. ㅜㅜ )

전 0x4014acd0 주소에서부터 검색을 시작했습니다.

빙고~~ 찾았습니다. 주소는 "0x4014ad24" 입니다.

( 이 문제를 풀 당시는 위와 같이 "/bin/sh"의 주소를 찾았으나 지금은 system함수부터 반복문을 돌려 "/bin/sh"문자열을 찾아버리는 소스코드를 사용해 쉽게 구하고 있습니다. )

이제 모든 준비는 끝났으니 바로 공격하고 끝내버리겠습니다.

성공입니다. 깔끔하네요...;;