/*
 http://sosal.tistory.com/
 * made by so_Sal
 */


BOF에 대해 기본적인 지식이 없으신 분은
아래 링크에 가셔서 글을 읽고오세요~


LINK_

/*
 * 사실 요즘 나오는 OS들은 BOF 버그가 통하지 않습니다..
 * 그럼에도 이 해킹기법을 공부하는 이유는..
 * 컴퓨터 메모리 구조에 대한 이해(?)를
 * 극대화 시킬 수 있는 재미있는 놀이이기도 하고..
 * ftz.hackerschool.org 워게임 문제들중..
 * 대략 50% 만큼의 비중을 차지하고 있는
 * 공격기법이기도.. ㅎㅎ
 * 여튼 한번 Buffer over flow를 한번 일으켜 봅시다.. ㅠ
 * 아래 bof 실습 환경은 제가 리눅스 구버전을 가지고 있지 못해서
 * ftz.hackerschool.org 의 id : level1 , pw : level1
 * 환경에서 실습함을 알려드리는 바입니다.
 */

================================= 고고싱? ㅎㅎ

그럼 기본적인 BOF의 원리를 아시는 분은.. 이제
BOF 실습을 해보셔야겠죠?
메인함수의 리턴값을 어쩌고 하면서.. 그 값을 바꾸면
우리가 마음대로 할 수 있다고는 했는데..
그 값을 어떻게 바꾸냐 ㅡㅡ. 그게 문제입니다 .. 하핫..

메인함수의 리턴값에 우리가 원하는 내용
(흔히 쉘을 실행시킨다던가 간단히 ls라도 출력해보는 내용?)
을 넣기 위해서는 그 파일을 실행시키는 내용이 있어야합니다. (으잉?)
이 내용은.. C언어로 쉽게 넣어줄순 없겠지요?
리턴값(4Byte)에다 무언가 넣어야하는데
컴퓨터가 그 값을 인식하려면.. C언어??? 아니지요!!
기계어를 넣어야 합니다..

기계어 느님이라니요 ㅠㅠ
10011001101100 숫자의 남발 아닙니까?..
\xda\xcb\x33\xc9\xb1\x0a\xbb\x74\xa0\xa2\x03\xd9\x74\x24\xf4
요로코롬 생겼다고 하네요.. ㅡㅡㅋ

이것을 우리가 GDB로 어셈블리 코드를
기계어로 바꿔서 하나하나 붙이기란
엄청난 노력 (아주 하찮은 일이지만)이
필요하게 되므로......
쉽게 기계어를 구할 방법이 필요합니다.

기계어를 쉽게 구하는 방법??
누군가 이 방법을 만들어놨겠죠!!
그 주인공이 바로 Metasploit !! 위엄입니다.
제 주위에 계신 유명한 해커분들이
쉘코드를 짤때 항상 유용하게 쓴다고 합니다 ^-^

하여튼 Metasploit을 설치하고,
BOF를 이용하여 간단히 ls 프로그램을 출력해보는
글을 아래에 계속 써내려 갈것입니다 ㅎㅎ
Metasploit은 꼭.. 챙겨두세요!!

================ 아래는 단순히 설치.. 내용입니다.

http://metasploit.com/
사이트 접속 후 메타스플로잇 다운로드!!

   
알맞는 본인의 OS를 선택하여 설치하세요~ ^-^
저는 주로 윈도우에서 작업하므로..
(Putty를 이용하여 원격으로.. 리눅스를 이용합니다.)
그리구.. 설치도 다하시구.. NMAP을 깔꺼냐고 묻는데
본인의 선택입니다.~ ㅎㅎ

그리고 설치 완료후.. 시작을 누르면.. 아래 메뉴가 있죠?


Metasploit Web을 클릭!!
콘솔창이 뜨고 초기화 어쩌고 메세지를 부부붕 띄우며
곧 새로운 웹창이 뜨게됩니다.
윗부분을 볼까요?


Payloads를 클릭합니다 !! ㅎㅎ

그럼 수많은 커맨드 쉘이 뜨는데....
여기서 필요하신것을 골라서 쓰시는 것입니다!

===================== 여기까지 설치.. 그럼 아래부터 .. 고고!!

이 포스트에서는 단순히 ls 라는 프로그램을
BOF를 이용하여 실행시켜보자는 생각으로. 글을 쓰고있기에 ^-^;;
ls라는 프로그램을 실행시키는 기계어 코드가 필요하겠죠?
이 기계어는 당연히 프로그램이 끝날시점의 리턴값 (메인의 리턴)에
들어갈 내용입니다.
Linux Execute shell 을 이용해봅시다.


을 클릭!!
그러면 아래와 같은 그림처럼.. 창이 새로 올라옵니다.




간단하게 ls를 실행시키는 기계어를 구하기 위함이니까..!!
ls만 딱 쳐주고 [Generate]를 클릭합니다 ㅎㅎ

/*
 * linux/x86/exec - 65 bytes
 *
http://www.metasploit.com
 * Encoder: x86/shikata_ga_nai
 * PrependSetresuid=false, PrependSetreuid=false,
 * PrependSetuid=false, PrependChrootBreak=false,
 * AppendExit=false, CMD=ls
 */

unsigned char buf[] =
"\xda\xcb\x33\xc9\xb1\x0a\xbb\x74\xa0\xa2\x03\xd9\x74\x24\xf4"
"\x5f\x31\x5f\x19\x03\x5f\x19\x83\xc7\x04\x96\x55\xc8\x08\x0e"
"\x0f\x5f\x69\xc6\x02\x03\xfc\xf1\x35\xec\x8d\x95\xc5\x9a\x5e"
"\x07\xaf\x34\x28\x24\x7d\x21\x29\xaa\x82\xb1\x42\xd9\x82\xe6"
"\xc9\x94\x62\xc5\x6e";

우와 우와.. 이게 진짜 그 기계어 느님 입니다 !! ㅎㅎ
눈이 휘둥그래지긴 하는데
이것을 이제 진짜 사용한다니 어꺠가 으쓱해지는 순간입니다.

그럼 기계어는 땃는데 ㅠㅠ
리턴값을 어떻게 바꾸고 또 뭐 리턴이 어쩌고..
혹시라도 BOF 원리가 이해 안되신분은
이 글의 가장 윗쪽 링크로 가셔서
간단하게 그림이나마 보고오시는게 좋을듯 합니다!!
(또 잡설이 길어지는군요. BOF를 시작해봅시다.)

아래는 BOF 실험파일 소스코드입니다.
// 위에서 언급했지만 ftz.hackerscool.org level1 / level1 계정이
// 아래 실습 환경임을 한번더 확인드리는 바입니다.

==========================================================
//bof.c
#include <stdio.h>

unsigned char buf[] =
"\xda\xcb\x33\xc9\xb1\x0a\xbb\x74\xa0\xa2\x03\xd9\x74\x24\xf4"
"\x5f\x31\x5f\x19\x03\x5f\x19\x83\xc7\x04\x96\x55\xc8\x08\x0e"
"\x0f\x5f\x69\xc6\x02\x03\xfc\xf1\x35\xec\x8d\x95\xc5\x9a\x5e"
"\x07\xaf\x34\x28\x24\x7d\x21\x29\xaa\x82\xb1\x42\xd9\x82\xe6"
"\xc9\x94\x62\xc5\x6e";

int main(void)
{
        int *ret;     // int형 포인터 변수를 하나
        ret = ( int* )&ret+2;   // 포인터 변수에서 2블럭만큼 증가 (8byte 증가)
        *ret = ( int )buf; // 포인터 변수에서 2칸 위로 위치이동 시킨곳에 쉘코드 삽입
}

==========================================================

메인함수 3줄의 코드를 설명하려 합니다.

int *ret;     // int형 포인터 변수를 하나 선언 했습니다.
               // 이 포인터를 이용해 ret 값을 바꾸려고 합니다.

ret = ( int* )&ret+2;   // 포인터 변수에서 2블럭만큼 증가 (8byte 증가)
                             // 스택 바로위에 스택 시작을 알려주는 ebp.
                             // ebp 바로위에 ret가 있죠.
                             // 
                             // ==   RET   ==
                             // ==   EBP   ==
                             // == int *ret ==
                             // 이런모양이겠네요!!?
                             // ret는 포인터니까 1만 증가시켜도
                             // 한 블럭씩 증가하겠죠? (포인터는 4바이트)
                             // 그러므로.. 2만큼 증가시켜주면
                             // 자신이 가리키는곳은? RET !!!!

*ret = ( int )buf;  // ret 본인이 가리키는곳이 RET 이므로..
                       // 이곳에 대망의 쉘코드만 삽입해주면
                       // 이프로그램이 끝날 시점에
                       // bof가 일어나게됩니다..

- 컴파일 -
gcc bof.c -o bof -mpreferred-stack-boundary=2

뒤에 -mpref ~~~ boundary=2 ~~ 이부분은 gcc 2.95버전 이후로
스택 구조가 변경되어서.. 그전의 환경을 맞춰주기 위해 추가해준 옵션입니다.



컴파일 후엔? 실행시켜보는것도 좋죠..!
하지만.. ret 바로 2칸위에 ret가 있다는 사실을...
한번더 확인사살 해보겠습니다.

위 프로그램을 gdb 로 디어셈 해보겠습니다.

(gdb) disas main
Dump of assembler code for function main:
0x080482f4 <main+0>:    push   %ebp
0x080482f5 <main+1>:    mov    %esp,%ebp     //esp를 ebp와 같은 위치에
0x080482f7 <main+3>:    sub    $0x4,%esp       //거기서 4바이트 아래로!!
0x080482fa <main+6>:    lea    0xfffffffc(%ebp),%eax
0x080482fd <main+9>:    add    $0x8,%eax
(이하생략)

int* 하나 선언했는데, ebp 아래 스택크기를 4만큼 줬다면..
그 공간은 우리가 선언한 변수의 공간임을 확신할 수 있죠
역시 int* 바로 위 (4byte 위)는 ebp겠고..
그 위는 (ret와 ebp가 항상 붙어다니기 때문에) ret 겠네요 ㅎㅎ

그럼 역시
ret = ( int* )&ret+2;
이것은.. 리턴으로 가는 길임을 증명하는 또다른 자료입니다 ㅎㅎ

========================== 아름다운 프로그램 실행

[level1@ftz tmp]$ gcc bof.c -o bof -mpreferred-stack-boundary=2
[level1@ftz tmp]$ ls
bof  bof.c
[level1@ftz tmp]$ ./bof
bof  bof.c      //bof가 일어난 결과
[level1@ftz tmp]$


제가 가지고 있는 리눅스에서는
세그멘테이션 오류
라는 엄청난 콩글리쉬로..
우릴 민망하게 하는 오류를 띄웁니다., ㅠㅠ

세그멘테이션 오류가 났다는건
메모리값에 대해서 문제가 발생했다는 증거이기도 합니다.
만약 bof를 일으키기 위한 포인터의 위치를
ret값으로 제대로 잡지 못했을때
실행시켜도 아무런 반응이 없는 상황이 오게됩니다.
그때엔 gdb라던지 코드를 다시 확인하여
제대로된 ret값을 잡도록 해주세요

해커스쿨 문제 레벨 11 이상 푸는것도
bof 이해해 상당히 도움이 됩니다.
처음 입문하는 사람들을 위해서..
쓴글이긴 한데
저도 넘 오랜만이라
막막하군요.. 하핫..
중요한 내용보다 잡설이 많은 글이었네요

Posted by sosal sosal

댓글을 달아 주세요

  1. 2010.09.12 02:42 신고

    조은글 ㅎㅎ 감사합니당
    검색하다보니 여기까지 왔어요 ㅋㅋㅋㅋㅋㅋㅋㅋ

  2. 2011.10.06 23:44

    비밀댓글입니다

  3. 2013.07.10 04:44 신고

    굿