Shell Link Binary File Format, which contains information that can be used to access another data object. The Shell Link Binary File Format is the format of Windows files with the extension «LNK», we call it a shortcut file. Regarding the structure of this format is very complicated, Microsoft has provided a document about LNK file format for reference.
I’ve followed the Microsoft patches for a long time. In 2018, I found that they had 2 LNK bugs which were fixed and all of them were RCE. Recently, @Lays found a bunch of LNK file parsing bugs, so with this binary file format I think it is suitable for fuzzing. However, you need to reverse and learn how to handle this LNK file on Windows.
File Explorer, previously known as Windows Explorer, is a file manager application that has been included with releases of the Microsoft Windows operating system from Windows 95 onwards. It provides a graphical user interface for accessing the file systems. It is also the component of the operating system that presents many user interface items on the screen such as the taskbar and desktop.
Explorer has a lot of features, each version of the operating system has been upgraded it by Microsoft. Here I discovered that the Explorer will automatically parsing the LNK file if the LNK file appears in the context that the Explorer is accessing. For example, if we are on the desktop, the Explorer will parse the LNK files that appear on the desktop and maybe in some secondary directory (about the depth of the folder that the Explorer can access, I don’t know).
Introduce parsing LNK file in Explorer
How can we build an arsenal to fuzz this LNK file format? We need to rely on Explorer, debug it, use Windbg attach to process explorer.exe:
I put break-point at 2 functions are CreateFileA and CreateFileW, I guess that Explorer will use it to read the file before parsing.
After a few breaks on the CreateFileW function, I saw the explorer calling the CreateFileW function with the file «Process Hacker 2.lnk», this LNK file is on the desktop. I view the call stack at this breakpoint:
We can see that a series of APIs related to CShellLink are called in the windows.storage.dll. Here I returned to MSDN to learn about these CShellLink related API and I found this:
It is possible to create an LNK parsing program using the IShellLink interface. Based on what MSDN provides I use IPersistFile to load and parsing LNK files, this is the harness I use to fuzzing.
I debug the test with the harness that I built on the file «test_debug.lnk»
Comparing the call stack between my harness and Explorer looks quite similar. I decided to use this harness for fuzzing.
Corpus for this LNK file I found is also quite available on the Github repo. I found and downloaded, then used them to fuzz. With the familiar winafl and Dynamorio, I used it with coverage_module windows.storage.dll. Run fuzzing with 1 master and 7 slave. About fuzzing and coverage, you can read my blogs before.
After some time running fuzzing, I went back to check my crashes, I found 4 unique crashes:
- Out of bound read in windows_storage!CRegFolder::_AttributesOf
- Out of bound read in windows_storage!CRegFolder::_CreateCachedRegFolder
- Out of bound read in shell32!CControlPanelCategoryFolder::_IsValidCategoryPidl
- Double free in windows_storage!DSA_DestroyCallback
I checked these 4 crashes on Explorer, only double-free bug can cause explorer.exe crash, 3 out of bound read bugs do not cause explorer.exe crash. I reported all 4 bugs to Microsoft, Microsoft only accepted one of my double-free bug, they rejected the rest because the crash did not occur on the default configuration of the system and could not be exploited (regarding the default configuration of the system, I think due to the harness I use is not complete like Explorer when parsing 1 LNK file).
The double-free bug I found above was fixed in this June patch of Microsoft, here is a bit of the cause of this bug:We have struct DSA as follows:
};DSA object is initialized at DSA_Create and insert items with DSA_InsertItem. While inserting additional items, it will allocate a memory area for the pData field in the struct DSA.
When releasing DSA object, the program has called DSA_DestroyCallback function twice to release the same DSA object.
The function s_DestroyCacheItemCB has an error:
When freeing the pData field, it did not check the availability of this memory, resulting in a double-free bug. The pData memory has been free before, I don’t analyze further why the DSA object was destroyed twice due to some condition in the previous thread.
For this bug, we can use after free on the DSA object to trigger RCE.
Above is the whole process I researched to find an attack surface for the LNK file, apply fuzzing to find fault of the LNK parsing process. At the time I found this bug, I only targeted the windows.storage.dll DLL without knowing that LNK had another type: LNK search (after ZDI published blog which analyzed a bug of @Lays, I realized this format). In addition to windows.storage.dll used to parsing LNK files, there are also windows.storage.search.dll and StructuredQuery.dll. The following blog I will talk about some bugs I found in StructuredQuery.dll but Microsoft does not fix it although it may cause DOS temporarily. Microsoft suggests that I can blog about those bugs and they are confident that they can answer every customer’s questions with bugs they don’t fix.
 https://docs.microsoft.com/en-us/windows/win32/api/dpa_dsa/nf-dpa_dsa-dsa_insertitem https://www.zerodayinitiative.com/blog/2020/3/25/cve-2020-0729-remote-code-execution-through-lnk-files