4. Kĩ thuật sandbox
• Sandbox kiểm soát quyền truy cập của ứng dụng tới tài
nguyên hệ thống
• Khai thác lỗ hổng trong môi trường có sandbox thường khó
khăn vì:
• Môi trường bị giới hạn và bị kiểm soát
• Trong một số trường hợp không thể ghi file
• Không tạo được tiến trình mới
6. Ví dụ về khai thác lỗ hổng
• Khai thác lỗ hổng Adobe Flash CVE 2015-5119 trong trình
duyệt, sử dụng CVE 2015-1701 để thực hiện leo quyền
CVE 2015-1701
CVE 2015-5119
Browser
Exploit
Privilege
Escalation
Elevated
process
8. CVE 2015-5119
Tạo một lớp tên là MyClass, có
hàm valueOf()
Tạo một đối tượng có kiểu
ByteArray , đặt là ba
Gán cho ba một đối tượng, có
kiểu là MyClass
Hàm valueOf() của đối tượng
MyClass được gọi
Hàm valueOf() ghi đè chính đối
tượng ba
2015-5119
9. CVE 2015 - 1701
1.Đăng kí window class 3. Tạo đối tượng window
Message
Kernel Mode
2. Gọi hàm CreateWindow
4. Chuyển sang user mode để gọi
hàm loadImage (thông qua
Usermode callback)
5. Gọi SetWindowLongPtr
với tham số
DefWindowProc
5’. Bật cờ ”Server side
Window Proc”
7. Đối tượng window
đã bật cờ ”Server side
Window Proc”
Gọi WindowProc Gọi WindowProc
User Mode
6. Trả về đối tượng
window được tạo mới
YN
11. Khai thác lỗ hổng và leo quyền
CVE 2015-1701
CVE 2015-5119
Browser
Exploit
Privilege
Escalation
Find Kernel32 base
Exploit code
Steal SYSTEM token
Elevated
process
PEB, TEB
Get API Functions
12. Motivation
• Leo quyền trên Windows - Ứng dụng cao
• Browser Exploit
• Bypass AD Policy
• Nhiều PoC được công bố - Ít stable exploit
• Xây dựng exploit qua rất nhiều bước, kỹ thuật
WinEoP Framework
• Dễ dàng xây dựng stable exploit – chỉ tập trung vào lỗi
• Hỗ trợ nhiều nền tảng, nhiều kịch bản
• x86, x64 CPU
• Executable, Shellcode output
14. WinEoP - Egg Hunting
• Xác định vị trí shellcode trên mem
• Tagging
• Data tag
• Code tag
• Tag scanning
• Theo từng page, theo từng byte
• Chỉ page hợp lệ
• Kiểm tra PAGE_GUARD, PAGE_NOACCESS
• Chỉ byte hợp lệ
• Kiểm tra Bad Pointer
15. WinEoP – Exploit (1)
• Chuẩn bị môi trường
• Địa chỉ các hàm API cần thiết
• Địa chỉ các pointer
• Thông tin hệ thống
• Phiên bản của hệ điều hành
• Địa chỉ của nt!_TEB và nt!_PEB
• Offset các struct
• Các giá trị này được lưu vào cấu trúc _ENVIRONMENT
17. WinEoP – Exploit (2)
• Callback trong khai thác một số lỗi
• Địa chỉ hàm phải là trực tiếp chỉ xác định khi thực thi
• Shellcode không có biến toàn cục
• Hàm callback cần tham chiếu đến biến toàn cục
• Fix Callback Pointers
• Đối với địa chỉ hàm
• Chuyển đổi thành địa chỉ tương đối khi build
• Tự động chuyển thành địa chỉ tuyệt đối khi chạy.
• Đối với biến toàn cục
• Sử dụng dwUserData trong cấu trúc _ENVIRONMENT
19. WinEoP – Exploit (3)
• Vuln Code: hỗ trợ các hàm để viết mã khai thác:
• StealSystemProcessToken(): hàm ghi đè token của process hiện
tại bằng token của system process (PID=4)
• ClearHandleTableEntry(): hàm xóa một handle bất kì trong bảng
ObjectHandleTable của tiến trình hiện tại
• InjectCodeToAnotherProcess(): Inject một đoạn mã vào một tiến
trình bất kì (dựa theo PID)
• NullPagePreparation(): cấp phát null-page và setup callback
• GetAddressByHandle(): chuyển đổi HWND sang địa chỉ của struct
win32k! _tagWND
• PoolAllocAndCopyViaAccelTable() cấp phát một khối bộ nhớ bất
kì thông qua win32k!NtUserCreateAcceleratorTable
• IsVm(): Kiểm tra và phát hiện tiến trình có đang thực thi trong
môi trường máy ảo hay không?
20. WinEoP – Exploit (4)
• Elevated process
• Nâng quyền process hiện tại
• Nâng quyền process bất kỳ theo ID
• Nâng quyền process cha
• Tạo process mới quyền SYSTEM
21. Multi-platform output
• Viết mã khai thác một lần – Build nhiều nền tảng
• Shellcode x86
• Shellcode x64
• Executable x86
• Executable x64
• Sử dụng ngôn ngữ lập trình C
• No assembly
• Dễ dàng viết exploit
22. Demo: CVE 2015-1701
• Xây dựng mã khai thác cho CVE 2015-1701 bằng
framework.
• Dựa theo mã nguồn CVE 2015-1701 của @hfiref0x
• https://github.com/hfiref0x/CVE-2015-1701
Sandbox là một môi trường có kiểm soát và cách ly, khiến cho ứng dụng bên trong để đảm bảo nó sẽ không ảnh hưởng bên ngoài.
- Khi bạn có một object ByteArray tên là ba và gán cho nó một object nào đó, ví dụ ba[0]=object, nó sẽ gọi hàm lượng giá ValueOf().
- Hàm lượng giá ValueOf() có thể bị ghi đè, nhờ đó hacker có thể thay đổi giá trị của ba trong khi gọi hàm lượng giá ValueOf().
- Khi bạn thay đổi dung lượng bộ nhớ cho ba trong hàm ValueOf(), nó sẽ gây ra lỗi use-after-free (UAF) bởi ba[0]=object sẽ lưu lại bộ nhớ ban đầu và sử dụng lại nó sau khi hàm ValueOf() đã được gọi.
Sau khi kích hoạt lỗ hổng bảo mật UAF, độ dài Vector. bị sai lệch cho phép tiến trình đọc và ghi bộ nhớ một cách tùy ý. Với khả năng này, hacker có thể thực hiện các tác vụ sau:
- Tìm kiếm địa chỉ của kernel32.dll và tìm địa chỉ VirtualProtect.
- Tìm địa chỉ của shellcode (mã khai thác lỗ hổng bảo mật) được lưu trong ByteArray
- Gọi VirtualProtect để biến địa chỉ bộ nhớ chứa shellcode thành "mã có thể thực thi".
- Có một hàm static có tên Payload được định nghĩa trong mã AS3.
- Tìm địa chỉ đối tượng hàm Payload này, và sau đó tìm địa chỉ mã hàm thực chứa trong đối tượng.
- Ghi đè địa chỉ này bằng địa chỉ của shellcode.
- Gọi hàm Payload trong AS3, khiến cho mã shellcode được thực thi.
- Sau khi mã shellcode được thực thi thì hoàn trả lại địa chỉ hàm static nói trên.
Chúng ta có thể thấy rằng phương pháp khai thác lỗ hổng bảo mật này có thể vượt qua kiểm soát Control Flow Guard bằng cách ghi đè địa chỉ hàm static.
Ứng dụng sẽ đăng kí một class mới với hệ thống, định nghĩa kiểu và địa chỉ của hàm WindowProc. Thuộc tính quan trọng nhất của window class là WindowProc, đây là hàm xử lý thông điệp.
Ứng dụng sau đó gọi API CreateWindow / CreateWindowEx với class trên và tạo ra một window mới. Các API này sẽ chuyển sang kernelmode để gọi hàm hệ thống NtUserCreateWindowEx. NtUserCreateWindowEx là hàm tạo một đối tượng cửa số mới trong hệ thống Windows. Trong khi thực hiện, nó sẽ chuyển sang usermode nhiều lần để gọi các hàm chỉ có ở usermode. Những hàm này làm nhiệm vụ tương ứng (ví dụ: để tải một hình ảnh, vv).
Attacker có thể lợi dụng điều này bằng cách thay thế các hàm callback, sử dụng API SetWindowLongPtr. Nếu tham số là " DefWindowProc", các đối tượng window sẽ bật cờ "Server Side Window Proc". Điều này có nghĩa là khi các cửa sổ nhận được một message gửi đến, WindowProc của ứng dụng sẽ thực thi trong kernelmode.
Find Kernel32 base: tìm địa chỉ của thư viện kernel32.dll
Lấy các biến môi trường: PEB, TEB, UserModeCallbackTable
Get API Functions: lấy địa chỉ các hàm API( các hàm usermode và hàm nt! PsLookupProcessByProcessId)
Steal SYSTEM token: lấy token của hệ thống
Các lỗ hổng cho phép khai thác leo quyền được công bố nhiều, luôn đi kèm với PoC.
Các trình duyệt hiện nay đều có nhiều thành phần bảo vệ khác nhau, trong đó có sandbox. Exploit leo quyền thường được sử dụng kèm trong các khai thác khác trình duyệt để vượt qua cơ chế bảo vệ của sandbox.
Chuyển đổi một mã PoC leo quyền thành mã Exploit (dùng để vượt ra ngoài sandbox) rất mất thời gian:
Thực hiện theo từng trường hợp riêng rẽ, không có công cụ hỗ trợ.
Một số shellcode được viết bằng assembly, khó nâng cấp.
Không hỗ trợ đồng thời cả 2 kiến trúc CPU 32bit và 64bit.
mã exploit cho bug nhưng dùng framework: người lập trình chỉ cần viết mã cho phần Vulncode ( màu vàng) , không cần thiết phải làm lại các đoạn khác
Đoạn mã khai thác leo quyền thường có kích thước rất lớn giải quyết bằng phương pháp egg hunting.
WinEoP Egg hunting có nhiệm vụ xác định chính xác địa chỉ của vùng chứa mã exploit, thiết lập quyền cho phép thực thi và chuyển quyền thực thi cho nó.
GetEnvironment(): hàm có nhiệm vụ lấy các tham số môi trường của hệ điều hành, bao gồm:
Địa chỉ các hàm API của hệ thống( bao gồm cả nt! PsLookupProcessByProcessId)
Phiên bản của hệ điều hành.
Địa chỉ của nt!_TEB và nt!_PEB
Offset của các trường:
nt! _EPROCESS: Token, ActiveProcessLinks, UniqueProcessId
win32k!_tagWND: WndProcOffset, ThreadInfoOffset
win32k!KeUserModeCallback
Địa chỉ win32k! _gSharedInfo
Các giá trị này được lưu vào cấu trúc _ENVIRONMENT
Cấu trúc chứa dữ liệu mà GetEnvironment trả về.
Ở chế độ shellcode, hàm callback sẽ gặp các vấn đề sau:
Địa chỉ của hàm phải là địa chỉ trực tiếp chỉ xác được khi shellcode thực thi.
Shellcode không có khái niệm biến toàn cục (global variables).
Hàm callback cần tham chiếu đến biến toàn cục.
Giải pháp:
Đối với địa chỉ hàm: WinEoP chuyển đổi tất cả các địa chỉ trực tiếp thành địa chỉ tương đối khi build, tự động chuyển thành địa chỉ tuyệt đối khi chạy.
Đối với biến toàn cục: Trong cấu trúc _ENVIRONMENT có chứa biến dwUserData , người viết mã khai thác tùy ý sử dụng biến này như một con trỏ để thay biến toàn cục.
FixPointer() sẽ patch lại biến lpEnv thành địa chỉ đúng
Ở chế độ shellcode, hàm callback sẽ gặp các vấn đề sau:
Địa chỉ của hàm phải là địa chỉ trực tiếp chỉ xác được khi shellcode thực thi.
Shellcode không có khái niệm biến toàn cục (global variables).
Hàm callback cần tham chiếu đến biến toàn cục.
Giải pháp:
Đối với địa chỉ hàm: WinEoP chuyển đổi tất cả các địa chỉ trực tiếp thành địa chỉ tương đối khi build, tự động chuyển thành địa chỉ tuyệt đối khi chạy.
Đối với biến toàn cục: Trong cấu trúc _ENVIRONMENT có chứa biến dwUserData , người viết mã khai thác tùy ý sử dụng biến này như một con trỏ để thay biến toàn cục.