Shell Link là một định dạng binary file, chứa
thông tin cho phép truy cập đến các đối tượng dữ liệu khác. Định dạng này có
phần mở rộng là “LNK”, chúng ta thường gọi là shortcut file. Về cấu trúc của
định dạng này rất phức tạp, Microsoft có cung cấp document về định dạng file
LNK để tham khảo[1].
Tôi đã theo dõi các bản vá của Microsoft trong
nhiều năm. Năm 2018, tôi nhận thấy Microsoft Windows bị phát hiện có 2 bug LNK đã
được khắc phục và đều là lỗ hổng RCE. Gần đây @Lays đã tìm ra được 1 loạt các
lỗi về parsing file LNK, với định dạng file là dạng binary này, tôi nghĩ rất phù
hợp để sử dụng fuzzing. Tuy nhiên cần reverse và tìm hiểu cách xử lý file LNK
này trên Windows.
Giới thiệu
File Explorer trước đây gọi là Windows Explorer
(explorer.exe),
là một ứng dụng quản lý tệp và được tích hợp sẵn trong các hệ điều hành
Microsoft Windows từ Windows 95 trở đi. Nó cung cấp một giao diện GUI để truy
cập các hệ thống tập tin. Nó cũng bao gồm nhiều thành phần giúp người dùng
tương tác như taskbar, desktop,…
Explorer có rất nhiều tính năng, trải qua mỗi
phiên bản hệ điều hành nó lại được Microsoft nâng cấp và phát triển thêm. Ở đây
tôi phát hiện ra rằng Explorer sẽ tự động parsing file LNK nếu file LNK đó xuất
hiện trong ngữ cảnh mà Explorer đang truy xuất. Ví dụ nếu chúng ta đang ở màn
hình desktop, Explorer sẽ parsing các file LNK xuất hiện ở desktop và có thể sẽ
ở trong 1 số thư mục thứ cấp (về độ sâu của thư mục mà Explorer có thể truy
xuất thì tôi không biết).
Tìm hiểu parsing LNK file trong Explorer
Làm thế nào ta có thể xây dựng một harness để
fuzz định dạng file LNK này? Chúng ta cần phải dựa vào Explorer, hãy debug thử,
dùng windbg attach vào process explorer.exe:
Tôi đặt break-point tại 2 hàm là CreateFileA và CreateFileW, tôi đoán rằng Explorer sẽ sử dụng nó để đọc file
trước khi parsing.
Sau 1 vài lần break trên hàm CreateFileW thì đến đây tôi thấy Explorer đang gọi hàm CreateFileW với file “Process Hacker 2.lnk”, file LNK này nằm ở
desktop. Tôi view call stack tại điểm breakpoint này:
Chúng ta có thể thấy rằng một loạt các API liên
quan đến CShellLink
được gọi trong DLL windows.storage.dll. Đến đây tôi quay trở lại MSDN tìm hiểu về các api
liên quan đến CShellLink
này và tôi tìm thấy thông tin này[2]:
Chúng ta hoàn toàn có thể tạo chương trình
parsing LNK bằng IShellLink
interface. Dựa vào những thứ MSDN cung cấp tôi sử dụng IPersistFile để load và parsing LNK file, đây là harness tôi sử
dụng để fuzzing.
Tôi debug thử với harness mà tôi xây dựng trên
file “test_debug.lnk”
So sánh call stack giữa harness của tôi và với Explorer
có vẻ khá giống nhau. Tôi quyết định sử dụng harness này để fuzzing.
Fuzzing LNK
Corpus đối với file LNK này tôi thấy cũng có sẵn
khá nhiều trên các repo github. Tôi tìm và download về, sử dụng chúng để fuzz. Vẫn
với winafl[3] và Dynamorio[4]
quen thuộc, tôi sử dụng nó với coverage_module là windows.storage.dll. Chạy fuzzing với 1 master và 7 slave. Về fuzzing và coverage mọi người có thể tìm đọc ở các blog của tôi
trước đây[5][6].
Sau một thời gian chạy fuzzing, tôi quay lại
kiểm tra các crash của mình, tôi nhận thấy có 4 unique crash:
- Out of bound read ở trong windows_storage!CRegFolder::_AttributesOf
- Out of bound read ở trong windows_storage!CRegFolder::_CreateCachedRegFolder
- Out of bound read ở trong shell32!CControlPanelCategoryFolder::_IsValidCategoryPidl
- Double free ở windows_storage!DSA_DestroyCallback
Tôi kiểm tra 4 crash này trên Explorer thì chỉ
có lỗi double free mới gây crash cho explorer.exe, còn 3 lỗi out of bound read thì không. Tôi thông báo
cả 4 lỗi này cho Microsoft nhưng Microsoft chỉ chấp nhận một lỗi double free
của tôi. Họ từ chối 3 lỗi còn lại vì crash không xảy ra trên cấu hình mặc định
của hệ thống và không thể khai thác được (về phần cấu hình mặc định của hệ
thống tôi nghĩ do harness tôi sử dụng không đầy đủ như Explorer khi parsing 1
file LNK).
CVE-2020-1299
Lỗi double free tôi tìm thấy ở trên đã được fix
trong bản vá tháng 6 của Microsoft, dưới đây là 1 chút về nguyên nhân gây ra
lỗi này:
Chúng
ta có struct DSA như sau:
DSA object:
struct DSA
{
INT nItemCount;
LPVOID pData;
INT nMaxCount;
INT nItemSize;
INT nGrow;
};
DSA
object[7] được khởi tạo tại DSA_Create[8] và
insert thêm các item với hàm DSA_InsertItem[9].
Trong khi insert thêm các item, nó sẽ cấp phát một vùng nhớ cho trường pData trong struct DSA.
Khi giải phóng DSA, chương trình đã gọi hàm DSA_DestroyCallback hai lần để giải phóng cùng một object DSA.
Hàm s_DestroyCacheItemCB xảy ra lỗi:
Khi tiến hành giải phóng trường pData, nó đã không kiểm tra sự khả dụng của vùng nhớ này
dẫn đến lỗi double free. Vùng nhớ pData đã được free ở trước đó, tôi không phân tích sâu hơn
về nguyên nhân tạo sao một object DSA lại bị destroy 2 lần có thể do một điều kiện nào đó
trong luồng xử lý trước.
Đối với lỗi này chúng ta có thể sử dụng use
after free trên object DSA để
trigger RCE.
Kết luận
Trên đây là toàn bộ quá trình tôi nghiên cứu tìm
ra một attack surface đối với file LNK, áp dụng fuzzing để tìm lỗi của quá
trình parsing LNK. Tại thời điểm tôi tìm lỗi này, tôi chỉ nhắm mục tiêu vào DLL
windows.storage.dll mà
không biết rằng LNK còn có một loại nữa là LNK search (sau khi ZDI viết blog
phân tích một lỗi của @Lays tôi mới biết định dạng này)[10]. Ngoài windows.storage.dll sử dụng để parsing LNK file mà còn có windows.storage.search.dll và StructuredQuery.dll. Trong bài blog tới, tôi sẽ nói về 1 số lỗi tôi tìm
thấy trong StructuredQuery.dll nhưng Microsoft không sửa mặc dù nó có thể gây ra DOS
tạm thời. Microsoft gợi ý tôi viết blog nói về các lỗi đó và họ tự tin rằng có
thể trả lời mọi câu hỏi của khách hàng với những lỗi họ không fix.
[2] https://docs.microsoft.com/en-us/windows/win32/shell/links
[3] https://github.com/googleprojectzero/winafl
[4] https://github.com/DynamoRIO/dynamorio
[5] https://ezqelusia.blogspot.com/2020/05/start-fuzzing-fuzz-various-image-viewers.html
[6] https://ezqelusia.blogspot.com/2020/05/microsofts-first-bug.html
[7] https://docs.microsoft.com/en-us/windows/win32/api/dpa_dsa/
[8] https://docs.microsoft.com/en-us/windows/win32/api/dpa_dsa/nf-dpa_dsa-dsa_create
[9] https://docs.microsoft.com/en-us/windows/win32/api/dpa_dsa/nf-dpa_dsa-dsa_insertitem
Click here for English version
No comments:
Post a Comment