As mentioned in the article about CVE-2020-1299 [1], this article I will
present some bugs I found in processing the "LNK search" file of windows.
In the article I will introduce pe-afl [2], a fuzzer I usually use instead
of Winafl when Winafl is unstable on newer versions of windows.
The bugs I present below are not fixed, but this blog I wrote at the
suggestion of MSRC, they will prepare every answer with customer questions
around these unresolved bugs.
Introduction
I will use pe-afl to fuzz the "LNK search" file format, this is the file
format I ignored until the ZDI public blog analyzed the error related to
this file format [3], about the file structure "LNK search" is very clear in
ZDI's blog (I think it is too complicated, I don't read much about it,
lol).
Pe-afl
As I mentioned a lot that Winafl does not work well on new windows
versions, plus Winafl using dynamic instruments to calculate coverage will
result in overhead, which reduces performance.
Pe-afl is a fuzzer built on the AFL used for binary close sources. It uses
static instruments to calculate coverage and feedback-driven. A static
instrument is always better than a dynamic instrument. However, currently
pe-afl only supports instruments for 32-bit binaries and has some
limitations because not every binary can be instrumental (most binaries
built with visual studio can be instrumental). This is an introduction slide
for pe-afl [4] [5].
About using pe-afl is similar to Winafl, except that Winafl requires
Dynamorio to calculate coverage + feedback-driven and pe-afl does not.
Pe-afl will use IDA to find basic blocks, which are highlighted as shown in
the picture.
Then pe-afl will insert the code at the beginning of these basic blocks to
mark coverage. Binary instrumented by pe-afl is similar to afl-gcc
instrument when building a program.
For pe-afl we will instrument the DLLs or even the EXE executables we want
fuzz (pe-afl also supports fuzz, instrument kernel .sys). Then the fuzzer
will do everything from calculating the coverage, feedback-driven like
afl.
Windows.storage.search.dll and StructuredQuery.dll
Here I debug with the harness I used to fuzz in the previous article [1], I
found the program also loads 2 more DLLs: windows.storage.search.dll and
StructuredQuery.dll to parsing a file “LNK search”.
I want to use pe-afl to fuzz both DLLs, not just StructuredQuery.dll alone.
However, if we use pe-afl to fuzz, we can only cover one module, so in order to cover more modules, I decided to fix a bit of pe-afl's source.
Pe-afl uses an array of 65536 bytes to store coverage for a module, so I doubled the size of this array to be able to cover another module. This way is quite simple but affects the running speed of fuzzer a lot. I don't know what Dynamorio used to cover multiple modules at a time, but for now, I can only use this simple method. I fixed the maximum pe-afl coverage to 3 modules at a time. In addition, I also integrated afl-fast [6] of @thuanpv_ and afl-mopt [7] (inspired by afl++ [8]).
Above is one of the pieces of code I modify pe-afl. Check how it works
after I fix it with afl-showmap:
Now everything is available, but the most important thing is that corpus is
not available. Corpus about the "LNK search" file format is not mentioned
anywhere on the internet. The only way here is to create it manually. I use
the search interface of Explorer, creating enough search cases under
conditions such as Date, kind, size, ... but also only create about 200
files (boring work makes me impatient).
I then use afl-cmin to reduce the number of corpus and start fuzz. I use
pe-afl fuzz on 2 DLLs that are windows.storage.search.dll and
structuredquery.dll, after 1 week I checked the crash that fuzzer found and
had 3 unique crashes:
- Stack overflow (0xc00000fd)
- 2 null pointer dereference
All three crashes appear in structuredquery.dll and can cause explorer.exe
to crash.
I reported to Microsoft but they said that these errors only caused DOS temporarily they would not fix. However, in my opinion, due to the nature of the LNK file, the default explorer will automatically handle them. For ordinary users who encounter these cases, it is often not clear the cause to fix (simply delete it but due to a continuous crash it will be very difficult to manipulate).
Conclusion
Above are some errors I found for the "LNK search" file format, I will not
publish these DOS POCs, but if someone reads this blog and follow it, it can
easily get those POCs, even there may be errors that cause RCE that I cannot
find (I think there are still errors that exist in processing LNK files).
Windows users should protect themselves, not arbitrarily download file
formats such as LNK, maybe your computer will be exploited as soon as this
file is saved.
[2]
https://github.com/wmliang/pe-afl
[5]
https://www.youtube.com/watch?v=OipNF8v2His
[6]
https://github.com/mboehme/aflfast
[7]
https://github.com/puppet-meteor/MOpt-AFL
[8]
https://github.com/AFLplusplus/AFLplusplus
--------------
Vietnamese version
Như đã đề cập ở bài viết về CVE-2020-1299 [1], bài này tôi sẽ trình bày 1
số lỗi tôi tìm thấy trong quá trình xử lý file LNK search của windows. Trong
bài viết tôi sẽ giới thiệu pe-afl [2], 1 fuzzer tôi thường sử dụng thay thế
winafl khi mà winafl chạy không ổn định trên các phiên bản windows mới
hơn.
Những lỗi tôi trình bày dưới đây đều không được fix nhưng blog này tôi viết
theo gợi ý của MSRC, họ sẽ chuẩn bị mọi câu trả lời với những câu hỏi của
khách hàng quanh những lỗi không được fix này.
Introduction
Tôi sẽ sử dụng pe-afl để fuzz định dạng file LNK search, đây là định dạng
file tôi đã bỏ qua mãi cho đến khi ZDI public blog phân tích lỗi liên quan
đến định dạng file này [3], về cấu trúc file LNK search trong blog của ZDI
nói rất rõ (tôi nhận định rằng nó quá phức tạp, tôi đọc cũng không đọng lại
được gì nhiều).
Pe-afl
Như tôi đã đề cập rất nhiều rằng winafl chạy không ổn định trên các windows
version mới, cộng thêm việc winafl sử dụng dynamic instrument để tính
coverage thì sẽ xảy ra overhead, hiệu năng giảm.
Pe-afl là 1 fuzzer được xây dựng dựa trên afl sử dụng đối với các binary
close source. Nó sử dụng static instrument để tính coverage và feedback
driven. Tất niên static instrument sẽ luôn luôn tốt hơn dynamic instrument.
Tuy nhiên hiện tại pe-afl chỉ hỗ trợ instrument đối với các binary 32 bit và
có 1 số hạn chế vì không phải binary nào cũng có thể instrument được (đa số
các binary được build với visual studio đều có thể instrument được). Đây là
slide giới thiệu về pe-afl [4] [5].
Về cách sử dụng pe-afl cũng gần tương tự như winafl, chỉ khác cái là winafl
cần có Dynamorio để tính coverage + feeback driven còn pe-afl thì không.
Pe-afl sẽ sử dụng IDA để tìm các basic-block, các basic-block được highlight
như ở trong hình.
Sau đó pe-afl sẽ chèn những đoạn code tại đầu các basic-block này để đánh
dấu coverage. Binary được instrument bởi pe-afl cũng tương tự như afl-gcc
instrument khi build 1 chương trình.
Đối với pe-afl ta sẽ instrument những DLL hay thâm chí là những file thực
thi exe mà chúng ta muốn fuzz (pe-afl cũng hỗ trợ fuzz, instrument kernel
.sys). Sau đó fuzzer sẽ làm mọi việc từ tính toán coverage, feeback driven
giống như afl.
Windows.storage.search.dll and StructuredQuery.dll
Ở đây tôi debug với harness tôi sử dụng để fuzz ở bài viết trước [1], tôi
nhận thấy chương trình còn load thêm 2 dll là windows.storage.search.dll và
StructuredQuery.dll để parsing 1 file LNK search.
Tôi muốn sử dụng pe-afl để fuzz cả 2 DLL trên, chứ không chỉ 1 mình
StructuredQuery.dll. Tuy nhiên nếu sử dụng pe-afl để fuzz thì chúng ta chỉ
có thể coverage được 1 module, để có thể coverage được nhiều module hơn tôi
quyết định sửa 1 chút source của pe-afl.
Pe-afl sử dụng 1 mảng 65536 bytes để lưu lại coverage đối với 1 module, tôi
đã tăng kích thước của mảng này lên gấp đôi để có thể coverage thêm 1 module
nữa. Cách này khá đơn giản nhưng ảnh hưởng đến tốc độ chạy của fuzzer rất
nhiều. Tôi không biết Dynamorio dùng cách gì để có thể coverage nhiều module
1 lúc nhưng hiện tại thì tôi chỉ có thể sử dụng cách đơn giản này. Tôi sửa
pe-afl tối đa có thể coverage được 3 module 1 lúc. Ngoài ra tôi còn tích hợp
afl-fast [6] của anh @thuanpv_ và afl-mopt [7] (lấy cảm hứng từ afl++ [8]).
Trên đây là 1 trong 1 số những đoạn code tôi modify pe-afl. Kiểm tra nó
hoạt động như thế nào sau khi tôi sửa với afl-showmap:
Bây giờ đã có đủ mọi thứ nhưng cái quan trọng nhất là corpus thì không hề
có sẵn. Corpus về định dạng file LNK search không được đề cập ở bất cứ đâu
trên internet. Cách duy nhất ở đây là chỉ có thể tự tạo bằng tay. Tôi sử
dụng giao diện search của explorer, tạo đủ các trường hợp search theo điều
kiện như Date, kind, size, … nhưng cũng chỉ tạo được khoảng hơn 200 files
(công việc thật nhàn chán khiến tôi thiếu kiên nhẫn)
Sau đó tôi sử dụng afl-cmin để giảm số lượng corpus xuống và bắt đầu fuzz.
Tôi sử dụng pe-afl fuzz trên 2 DLL là windows.storage.search.dll và
structuredquery.dll, sau 1 tuần tôi kiểm tra đống crash mà fuzzer tìm được
và có 3 unique crash:
- Stack overflow (0xc00000fd)
- 2 null pointer dereference
Cả 3 crash này đều xuất hiện trong structuredquery.dll và có thể gây crash
cho explorer.exe
Tôi report cho Microsoft nhưng họ nói rằng những lỗi này chỉ gây ra DOS tạm
thời họ sẽ không sửa. Tuy nhiên theo tôi thì do tính chất của file LNK mặc
định explorer sẽ luôn tự động xử lý chúng. Với những người dùng bình thường
gặp những trường hợp này thường sẽ không rõ nguyên nhân để khắc phục (đơn
giản là xóa nó đi nhưng do crash xảy ra liên tục nên sẽ rất khó thao
tác).
Conclusion
Trên đây là 1 số lỗi tôi tìm thấy đối với định dạng file LNK search, tôi sẽ
không public những POC gây DOS này tuy nhiên nếu ai đó đọc blog này và làm
theo đều có thể dễ dàng có được những POC đó, thậm chí có thể sẽ tồn tại
những lỗi gây ra RCE mà tôi không tìm thấy (tôi nghĩ vẫn còn những lỗi đó
tồn tại trong quá trình xử lý file LNK). Người dùng windows nên tự bảo vệ
chính mình, không nên tùy tiện tải về những định dạng file như LNK, có thể
máy của bạn sẽ bị khai thác ngay sau khi file này được lưu xuống.
[2]
https://github.com/wmliang/pe-afl
[5]
https://www.youtube.com/watch?v=OipNF8v2His
[6]
https://github.com/mboehme/aflfast