18/09/2018, 13:48

Windows Shell Code và Ứng dụng khai thác lỗi tràn bộ đệm – Phần 2

Chào các bạn, tiếp tục chủ đề về “Windows Shell Code và Ứng dụng khai thác lỗi tràn bộ đệm”. Hôm nay chúng ta tiếp tục giải quyết các vấn đề liên quan tới việc lấy địa chỉ hàm, nạp thêm thư viện và việc mã hóa shellcode. Nếu bạn nào chưa đọc bài viết trước của tôi, bạn có thể tham ...

Chào các bạn, tiếp tục chủ đề về “Windows Shell Code và Ứng dụng khai thác lỗi tràn bộ đệm”. Hôm nay chúng ta tiếp tục giải quyết các vấn đề liên quan tới việc lấy địa chỉ hàm, nạp thêm thư viện và việc mã hóa shellcode.

Nếu bạn nào chưa đọc bài viết trước của tôi, bạn có thể tham khảo tại đây.

Lấy địa chỉ hàm trong Shellcode

Để đa dạng hóa khả năng của Shellcode, ta sẽ nạp thêm các thư viện khác như User32.dll… bằng 2 hàm API là LoadLibrary & GetProcAddress

Nạp thư viện bằng hàm LoadLibrary:

HINSTANCE LoadLibrary ( LPCTSTR lpLibFileName);

Lấy địa chỉ hàm bằng hàm GetProcAddress:

FARPROC GetProcAddress( HMODULE hModule,   LPCWSTR lpProcName);

Như vậy, ta sẽ phải biết địa chỉ của hàm LoadLibrary & GetProcAddress bên trong thư viện Kernel32.dll. Đoạn asm dưới đây sẽ thực hiện gọi MessageBox từ thư viện User32.dll:

ShellCode-MinhBQ1

4. Mã hóa shellcode

Nhắc lại một chút về tấn công tràn bộ đệm (Buffer Overflow), ta biết lỗi tràn bộ đệm về cơ bản là do lập trình cẩu thả, không kiểm soát các giá biên của dữ liệu. Do vậy, khi ta sử dụng các hàm ghi dữ liệu vào vùng nhớ như printf(), strcpy()… vùng nhớ sẽ bị tràn. Kẻ tấn công dựa vào các hàm này để đưa mã độc vào các vùng nhớ đó. Tuy nhiên, các hàm trên đưa dữ liệu vào vùng nhớ dưới dạng chuỗi ký tự (string), nghĩa là tất cả các ký tự NULL hay 0x00 đều là điểm ngắt của chuỗi ký tự và Shellcode chứa ký tự 0x00 sẽ không được đưa vào vùng nhớ. Như vậy, mã hóa Shellcode là cần thiết để loại bỏ các giá trị không mong muốn mà vẫn cho phép được thực thi bình thường.

Bài viết này sử dụng phương phép XOR đoạn mã nhị phân với một giá trị cụ thể (ví dụ như 0x02). Dưới đây là đoạn mã nhị phân chưa được XOR và đoạn mã nhị phân sau khi XOR :

x55x89xe5x57x56x53xe8x00x00x00x00x5b…

x57x8bxe7x55x54x51xeax02x02x02x02x59…

Mã hóa tất nhiên sẽ phải có cơ chế giải mã, đoạn mã sau sẽ thực hiện giải mã đoạn Shellcode trên.

ShellCode-MinhBQ2

Đoạn Shellcode sau đây bao gồm cả mã hóa và giải mã sẽ không còn các giá trị không mong muốn (0x00) :

xebx0dx5ex31xc9xb1x66x80x36x02x46xe2xfaxebx05xe8xeexffxffxffx57x8bxe7x55x54x51xeax02x02x02x02x59… 

Phương pháp mã hóa trên có hạn chế là phải có cơ chế giải mã tương ứng. Ngoài phương pháp trên đây còn nhiều phương pháp khác để tránh cho Shellcode gặp những giá trị đặc biệt, không mong muốn :

  • Viết Shellcode bằng ký tự.
  • Unicode Shellcode.

Trong các bài tới tôi sẽ tiếp tục với các chủ đề còn lại bao gồm:

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
0