Monday, June 29, 2020

Some DOS bugs while processing Microsoft LNK files

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.

 

[1] https://blog.vincss.net/2020/06/cve49-microsoft-windows-lnk-remote-code-execution-vuln-cve-2020-1299-eng.html

[2] https://github.com/wmliang/pe-afl

[3] https://www.zerodayinitiative.com/blog/2020/3/25/cve-2020-0729-remote-code-execution-through-lnk-files

[4] https://www.slideshare.net/wmliang/make-static-instrumentation-great-again-high-performance-fuzzing-for-windows-system

[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.

 

[1] https://blog.vincss.net/2020/06/cve49-microsoft-windows-lnk-remote-code-execution-vuln-cve-2020-1299-eng.html

[2] https://github.com/wmliang/pe-afl

[3] https://www.zerodayinitiative.com/blog/2020/3/25/cve-2020-0729-remote-code-execution-through-lnk-files

[4] https://www.slideshare.net/wmliang/make-static-instrumentation-great-again-high-performance-fuzzing-for-windows-system

[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

2 comments:

  1. I also fuzzed same search lnk files provided in ZDI blog. I was able to create that lnk file mentioned in the ZDI blog (lots of python code i wrote to reach that vulnerable part. its bit complex). I used WinAFL and used harness code as mentioned in "vincss's blog".
    I found lots of crashes and most of them are stack overflow. mostly they cause DOS.. As i am not having good reversing skill so have not analyzed them properly....your blog given me one more point to look upon that is PE-AFL.... thanks for this nice post

    ReplyDelete
  2. Do you have plan to open source of your modified pe-afl code? or Can I use your source code for further research? Thanks.

    ReplyDelete