Windows shellcode và ứng dụng khai thác lỗi tràn bộ đệm

Hôm nay tôi xin chia sẻ tới các bạn loạt các bài viết về chủ đề “Windows shellcode và ứng dụng khai thác lỗi tràn bộ đệm”. Những bài viết này tôi đã thực hiện cách đây 5 năm và hôm nay tôi sẽ biên tập lại để chia sẻ tới tất cả các bạn, những người quan tâm đến “lỗ hổng phần mềm”, “khai thác”, “shellcode”.

Bài viết của tôi sẽ bao gồm các thành phần sau đây:

I. Khái niệm

II. Shellcode cơ bản

  1. System Calls & Shellcode
  2. API & Shellcode
  3. Lấy địa chỉ hàm trong Shellcode
  4. Mã hóa shellcode

III. Shellcode nâng cao

  1. Ý tưởng
  2. Tìm kiếm địa chỉ Kernel32.dll
  3. Process Enviroment Block
  4. Structured Exception Handling
  5. TOPSTACK
  6. Lấy địa chỉ hàm bên trong Kernel32.dll
  7. Tối ưu độ dài của Shellcode

IV. Các shellcode phổ biến

  1. MessageBox Shellcode Version 1
  2. MessageBox Shellcode Version 2

Hi vọng các bạn sẽ thu được những kiến thức hữu ích qua các bài viết này. Những kiến thức mà tôi đã tích lũy được trong suốt 8 năm nghiên cứu về an toàn thông tin, khai thác lỗ hổng phần mềm.

1. Khái niệm

Khai thác lỗi tràn bộ đệm cho phép kẻ tấn công chiếm quyền điều khiển chương trình bị lỗi hay chính xác là có thể điều khiển con trỏ lệnh của chương trình đó. Như vậy, sau khi đã thực hiện việc khai thác và chiếm được quyền điều khiển con trỏ lệnh, kẻ tấn công cần phải thực thi thực hiện đoạn chương trình nào đó cho phép chiếm quyền điều khiển hệ thống. Đoạn chương trình này chính là Shellcode.

Shellcode là một đoạn mã máy nhỏ cho phép thực hiện chỉ một nhiệm vụ nào đó bên trong một chương trình bị khai thác. Nhiệm vụ đó có thể đơn giản là đưa ra thông báo (MessageBox), có thể là tạo User, cài đặt trojan… Bài viết này sẽ hướng dẫn cách viết một shellcode từ đơn giản đến nâng cao.

Bài viết yêu cầu người đọc phải biết khái niệm về các ngôn ngữ Assembly32 cho bộ vi xử lý 8086 của intel, lập trình API cho Windows 9x và Windows NT.

Một số công cụ yêu cầu :

  • NASM32 & MakeShell
  • OllyDbg
  • Hiew
  • Depends (một công cụ trong bộ Visual Studio 6.0)
  • MSDN

2. Shellcode cơ bản

System Calls & Shellcode

System calls (SysCall) hay hàm gọi hệ thống là một kỹ thuật cho phép chương trình user-mode gọi một thủ tục của Kernel cho phép thao tác vào ra trực tiếp với hệ thống. SysCall có thể hiểu là một cổng trung gian giữa User-modeKernel-mode. Để hiểu về SysCall, ta có thể nhìn hình dưới đây :

Bui Quang Minh: Windows shellcode và ứng dụng khai thác lỗi tràn bộ đệm

Hình 1 : Hoạt động của System Calls

SysCall làm nhiệm vụ trung gian nhận lời gọi API từ ứng dụng User-mode, tìm kiếm chỉ số hàm Kernel trong System Call Table, thực thi hàm đó rồi trả lại kết quả cho ứng dụng. Việc nhận lời gọi API từ ứng dụng thực ra là nó nhận được ngắt từ ứng dụng, SysCall gọi trình phục vụ ngắt thực hiện chuyển đổi dữ liệu của API (tham số, cờ, thanh ghi…) từ User Stack sang Kernel Stack.

Trong Windows, SysCall cho phép quản lý bộ nhớ, vào ra dữ liệu, quản lý thư mục, quản  lý tiến trình, … Tuy nhiên, đa phần API có giao tiếp SysCall đều là các hàm Undocument.

Ngắt được sử dụng để yêu cầu SysCall :

  • Windows 2000  : “int 0x2e
  • Windows XP     :  SYSENTER

Như vậy, Dựa vào cơ chế của System Call, ta có thể viết Shellcode bằng cách gọi hàm bởi chỉ số của hàm bên trong bảng System Call Table. Đoạn asm dưới đây thực hiện kết thúc tiến trình bằng cách gọi API ntTerminalProcess với số SysCall của nó:

            MOV    EAX, 0x000000bb     ; 0xbb là số SysCall hàm ntTerminalProcess

            LEA     EDX, [ESP+4]          ; EDX lưu tham số của hàm

            INT       0x2E                            ; Gọi Syscall thực hiện hàm

Với số lượng SysCall tương đối trong Windows, ta có thể thực hiện viết Shellcode chỉ thông qua SysCall. Tuy nhiên, Việc viết shellcode như vậy có cả ưu điểm và hạn chế:

Ưu điểm:

  • Không cần sử dụng của hàm API, cụ thế là không cần xác định   địa chỉ  của các hàm API.
  • Có thể sử dụng để vượt qua cơ chế bảo vệ chống tấn công tràn bộ đệm ở user-mode.

Nhược điểm:

  • Giới hạn khả năng làm việc của Shellcode vì số lượng SysCall là có hạn (trong Windows khoảng hơn 1000)
  • Vì các hàm socket API không được Windows hỗ trợ giao tiếp SysCall nên Shellcode sử dụng SysCall không có khả năng làm việc với mạng.
2. API & Shellcode

Windows API là thư viện các hàm cho phép phát triển các ứng dụng khác nhau trên nền hệ điều hành của Microsoft. Shellcode cũng coi như là một ứng dụng trên nền Windows, do đó nó cũng có thể được viết thông qua các hàm API. Khác với viết Shellcode bằng SysCall, Shellcode viết bằng hàm API có khả năng rất đa dạng, đặc biệt nó có thể làm việc với các hàm socket API.

Với ưu điểm trên, hầu hết các Shellcode được sử dụng cho các cuộc tấn công ngày nay đều được viết bằng các hàm API và thực hiên các nhiệm vụ như connect back,download, send mail, cài đặt trojan … Tuy nhiên, cũng giống như SysCall, địa chỉ của các hàm API bị thay đổi cho mỗi phiên bản khác nhau của Windows nên một Shellcode có địa chỉ API cố định sẽ chỉ có thể thực thi ở đúng phiên bản Windows. Trước tiên, chúng ta sẽ viết một đoạn Shellcode đơn giản, chỉ sử dụng địa chỉ cố định của hàm API.

Công cụ sử dụng :

  • Depends (Công cụ trong bộ VS6.0).
  • Text Editor (EditPlus, NotePad…)
  • NASM&MakeShell

Trước tiên, ta biết các ứng dụng khi thực thi đều phải nạp thư viện Kernel32.dll vào không gian bộ nhớ. Do đó, Shellcode đầu tiên này sẽ sử dụng 2 hàm API trong Kernel32.dll với nhiệm vụ gọi “notepad” bắt hàm “Winexec()”, sau đó kết thúc chương trình bằng hàm “ExitProcess()”.

Sử dụng Depends để xác định địa chỉ hàm “Winexec()” cho Windows XP SP2 ta nhận được địa chỉ cơ sở của Kernel32.dll (0x7C800000) và địa chỉ tương đối của hàm (0x6114D). Như vậy, địa chỉ tuyệt đối Shellcode sử dụng là 0x7C86114D. Tương tự như vậy ta có địa chỉ hàm “ExitProcess()” là 0x7C81CAA2.

 Bui Quang Minh: Windows shellcode và ứng dụng khai thác lỗi tràn bộ đệm

Hình 2 : Sử dụng Depends xác định địa chỉ hàm MaViDu

Biên dịch đoạn asm sau ra file nhị phân rồi chuyển sang Shellcode :

nasmw.exe -s -fbin file.asm

makeshell.exe file

Kết quả là đoạn Shellcode có thể thực hiện trên Windows XP SP2:

\xBB\x4D\x11\x86\x7C\xE9\x0E\x00\x00\x00\x58\x68\x05\x00\x00\x00\x50\xFF\xD3\xE9\x0D\x00\x00\x00\xE8\xED\xFF\xFF\xFF\x6E\x6F\x74\x65\x70\x61\x64\x00\x68\x01\x00\x00\x00\xBB\xA2\xCA\x81\x7C\xFF\xD3

Như vậy, ta đã có được đoạn Shellcode thực hiện một nhiệm vụ nhỏ. Tuy nhiên, vì chỉ sử dụng các hàm trong Kernel32.dll nên khả năng của Shellcode rất hạn chế vì thế ta cần phải nạp thêm các thư viện.

Trong bài viết tới tôi sẽ tiếp tục với việc “Lấy địa chỉ hàm trong Shellcode” và “Mã hóa shellcode“.

#LƯU Ý: Các ví dụ trên đều được thực hiện trên Windows XP.

Bình luận

Từ khóa: