Executing Windows malware in Windows Subsystem for Linux (Bashware)

Origin Story

I did a talk recently at the Bangalore null/OWASP meetup where I spoke about and demoed the concept of the research done by Check Point Security folks, called Bashware.

Bashware (bash+(mal)ware) is the idea of running Windows binaries (malware) in the Windows Subsystem for Linux (WSL) using wine support. This allows for some programs (not all Windows PE executables though) to be run inside WSL while being shielded from system inspection tools like Antivirus solutions, process monitor etc.

While setting up the demo for this talk, I realised that the speed of execution that is shown in the video released by Check Point Security was very likely not possible as it took me couple of hours of setup and downloading/installing of components required to make this run from scratch. In the video, a binary called malware.exe is run and within a minute the binary does the following

  1. Enables WSL
  2. Enables Developer Mode
  3. Installs WSL
  4. Installs wine
  5. Executes nc.exe -lvp 1337 via wine

In my opinion, the malware.exe simply runs the last command while everything else is already setup on the system. Let’s go ahead and build a PoC and see what we happens.

Let’s build a PoC!

In any case, if you want to try setting this up, here are the commands that worked for me. This is 5 step process at the very least. You will need to be on a Windows 10 64 bit Edition machine with Windows 10 version higher than the Anniversary Update (version 1607):

Step 1: Enable WSL

The Windows Subsystem for Linux can be enabled either by using the dism binary using an elevated command prompt or using Powershell’s Enable-WindowsOptionalFeature module as shown below. A reboot is required after this step:

C:\>dism /Online /Enable-Feature /All /FeatureName:Microsoft-Windows-Subsystem-Linux /NoRestart
PS C:\> Enable-WindowsOptionalFeature -O -F Microsoft-Windows-Subsystem-Linux

Step 2: Enable Developer mode (Optional)

Developer Mode in Windows 10 allows developers to install and test unsigned applications and was required to install WSL, but post 16215, you no longer have to enable Developer Mode to install WSL. I ran into some installation issues though which did not recur once I had enabled Developer Mode, so including this step here.

To enable Developer Mode, go to Settings -> Update & Security -> For Developers and click on the Developer mode radio button and click Yes on the message box that is shown

To script this or to do this via a command prompt, we can use the reg command to add registry values directly. The following command sets the required values in the Windows registry (requires elevation).

reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" /v AllowAllTrustedApps /t REG_DWORD /d 1 /f

reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" /v AllowDevelopmentWithoutDevLicense /t REG_DWORD /d 0 /f

Step 3: Install WSL and Linux components

This can be done via the Turn Windows features on or off applet as shown below

or using the command prompt with the lxrun command

lxrun /install /y

Step 4: Install wine inside WSL

From the Wine website,

Wine (originally an acronym for “Wine Is Not an Emulator”) is a compatibility layer capable of running Windows applications on several POSIX-compliant operating systems, such as Linux, macOS, & BSD. Instead of simulating internal Windows logic like a virtual machine or emulator, Wine translates Windows API calls into POSIX calls on-the-fly, eliminating the performance and memory penalties of other methods and allowing you to cleanly integrate Windows applications into your desktop.

Basically, Wine allows you to run Windows programs on Linux by translating Windows API calls to Linux (POSIX) equivalent API calls. Not all Windows programs can be run using Wine though, however there are a large number of programs that do work.

Anyways, Wine is required to run the Windows binary (malware) to complete this PoC for bashware. You can do this using a bash terminal in WSL. Open cmd and type bash and press enter to launch the WSL environment. In bash, type the following commands to enable 32 bit architecture support, add the Wine PPA, download and update the package lists from the repositories and finally install wine:

dpkg --add-architecture i386
add-apt-repository -y ppa:ubuntu-wine/ppa
apt-get update
apt-get install wine1.6-amd64

Step 5: Download and run netcat 64 bit using wine

This was the trickiest of all the steps. The original research article on the Check Point Security website does not mention the binary type that will be eventually executed, although there are hints throughout the article.

Looking at the video and pausing at 0:12 seconds I realized that the netcat binary used in the video was the original Hobbit version compiled by someone into its 64 bit equivalent on 26th December 2010. Using a little bit of Google search I found the exact binary that was used in the video, which I subsequently used in the demo as well.

So go ahead and grab a copy of the netcat 1.11 from https://eternallybored.org/misc/netcat/

(You can compare the Date Modified of the files in the video and this download and chuckle along :D)

Finally, to run the netcat and complete the PoC, cd to the directory where you unzipped the download and run the following command (all in bash, obviously). You may very likely see multiple preloader: Warning: failed to reserve range 00007ffffe000000-00007fffffff0000. You can ignore these warnings and proceed.

wine64 nc64.exe -e cmd.exe -lvp 1337

This will run the netcat binary inside WSL using wine. The netcat parameters in this command cause it to verbosely listen on port 1337 and execute and send STDIN, STDOUT and STDERR of cmd.exe back to the connecting client.

You can verify if the port is open using netstat or TCPView

C:\> netstat -anto | findstr "1337"

From a different machine or another command prompt window on the same computer connect to the open port using another copy of netcat (I used the nmap version) as such:

ncat 1337 -v

Is this really stealthy?

Once the connection was established, I wanted to see if this can be detected by some common Windows system inspection tools. I used TCPView, Process Explorer and Process Monitor. The results were interesting as expected.

Using TcpView

TCPView provides a graphical UI to view all network connections, the teardowns and new connections being made along with the process information of the PID that created the connection.

In this case, TCPView was able to list the open port, attributing it to wineserver, but was unable to get more information.

Using Process Explorer

Process Explorer was able to detect the wine64-preloader and the wineserver, but beyond that very little information was available.

The process memory and network listening status was all that was available in Process Explorer. The error message shown in place of the path is shown when (amongst other things) the handle of a privileged process, opened with PROCESS_QUERY_LIMITED_INFORMATION, is used to call QueryFullProcessImageName

Using Process Monitor

I had better luck with Process Monitor in looking at the process and the execution path. I would highly recommend trying this out on your own setup as the number of entries is just too many to go into details.

The wine64 binary path (on the Windows Filesystem) was detected as well as several CreateFile, ReadFile and CloseFile references to nc64.exe by a process that had no name or path (!?). The LXCORE.SYS driver was also visible in the stack of the process with various API calls to execute and manage the wine64 invocation of nc64.exe.

Final Thoughts

In my opinion, the video and research published by the folks at Check Point Security had some glaring and obvious holes in it. But given the overall simplicity of execution and the absence of proper tools to inspect and analyze Windows binaries running through Wine through WSL (whew!), this can become very tricky very fast.

To be fair, it really is a lengthy process, requiring privileged execution, multiple reboots and Internet access. No wonder Microsoft downplayed the whole thing as is. However, it cannot be denied that this is a cool technique at camouflaging execution.

As is always with any untrusted sources, practice caution when opening email attachments or executing downloaded content.

Till my next post, Happy Hacking!

PS: The slides from the talk that spurred this blogpost are at: https://www.slideshare.net/riyazwalikar/executing-windows-malware-through-wsl-bashware


  1. https://research.checkpoint.com/beware-bashware-new-method-malware-bypass-security-solutions/
  2. https://www.youtube.com/watch?v=fwEQFMbHIV8
  3. https://blogs.msdn.microsoft.com/wsl/2016/04/22/windows-subsystem-for-linux-overview/

A Windows UAC Bypass using Device Manager

Today while working on a Windows 10 machine, I had the need to open the Device Manager for some hardware maintenance. While opening the Windows Device manager I noticed that there was no UAC prompt when I started it. This was a little strange because the Device Manager exists as a Management Console snap-in in %systemroot%\System32\devmgmt.msc and is launched by mmc.exe.

When you start the Device Manager, mmc.exe is launched with %systemroot%\System32\devmgmt.msc as an argument.

Independently, the Microsoft Management Console requires elevation to run. When you go to run and launch mmc.exe, Windows will ask you to allow elevation using the UAC prompt.

If the Device Manager can be opened without a UAC prompt it means that it was launched with High Integrity level. If this process can be used to spawn other processes, they will be launched with High integrity level too.
It was trivial from here to find a way to open an elevated Command Prompt without being prompted by UAC.
User Access Control on my machine was set to the default value of “Notify me only when apps try to make changes to my computer (default)”
To reproduce this:
1. Go to Start run and type devmgmt.msc. Notice that there is no UAC prompt.
2. Once the Device Manager opens, goto Help > Help Topics
3. This will open up the Microsoft Management Console Help window. Right click any where in the right pane and select View Source
4. This will open notepad (the editor may vary if you have set IE’s source viewer to a different text editor).
5. Using notepad’s File > Open menu, navigate to the System32 directory.
6. Set the File type to “All files (*.*) and right click select “Run as Administrator” on cmd.exe
7. This should launch a elevated Command Prompt without any UAC prompts. You can run whoami /priv to check that you have a lot of privileges available now (disabled but available).
8. The process tree also shows that the cmd.exe that was spawned was started with High Integrity level.
There are several other techniques available on Windows that allow you to bypass UAC and most of them are well documented (see references below).

Please note, according to Microsoft, UAC bypasses are not a security problem as UAC is a convenience feature (more references in that page).

Other UAC Bypass references

1. https://enigma0x3.net/2016/08/15/fileless-uac-bypass-using-eventvwr-exe-and-registry-hijacking/
2. https://enigma0x3.net/2016/07/22/bypassing-uac-on-windows-10-using-disk-cleanup/
3. https://github.com/hfiref0x/UACME
4. https://habrahabr.ru/company/pm/blog/328008/ [Use Google translate, worth reading]

I will try and find other bypasses and post them here. Till then Happy Hacking!!

psexec using a local admin account to a UAC enabled system

To protect users across the network, Windows UAC imposes token restrictions on local administrators logging in via the network (using the net use \\computer\\c$ share for example). This means that a local administrator will not be able to perform administrative tasks and will not have the ability to elevate to full admin rights.

This works well if you are securing systems. However, during a pentest, hash/password reuse via psexec for example, will fail. Simply because connecting to the C$ admin share to run the psexec service will fail. My friend and systems hacker Anant Shrivastava pointed this out during some testing that he was doing, prompting me to blog about this.

I setup a Windows 7 machine with UAC enabled, an administrative account called “testadmin” with password “testadmin” and used the exploit/windows/smb/psexec exploit module from metasploit to test this in my lab environment and saw the following error:

Microsoft recommends a registry edit to disable UAC remote restrictions. To make this change, follow these steps:

  1. Open the registry editor using the regedit command via Start > Run
  2. Navigate to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System
  3. In the right pane, if the LocalAccountTokenFilterPolicy DWORD value doesn’t exist, create it.
  4. Set its value to 1

The changes take effect immediately. I tried the Metasploit exploit again and voila it worked this time:

This registry change allows Sysinternals Psexec utility to function as well apart from other utilities that require a privileged token on the C$ share (or any other admin share).

Happy Hacking!

Get username from PID in VB.NET

As part of a larger program that I’m writing to work with Windows processes, threads and window objects, I wrote a function that allows you to get the username of the user who owns a given process. As simple as it sounds, there is no straightforward way of obtaining the username given the process id in Windows. You could use a WMI query to get the username from a PID but that is painfully slow especially if you plan on doing enumeration for all the processes running on your system. The faster way is to use the Win32 API.  The primary APIs that are needed to achieve this are:

The flow would be as follows:

  1. Using OpenProcess with the PROCESS_QUERY_INFORMATION access right, you can open a handle to a process. This will fail if you do not have the necessary access levels. For example, a limited user using querying a process owned by NT Authority\System.
  2. Once you have the handle, you can call OpenProcessToken requesting the TOKEN_QUERY access right. This function returns a pointer to a handle that identifies the newly opened access token.
  3. Once you have obtained the handle to the access token, calling GetTokenInformation with the access token handle returns the length of the buffer for the TokenInformation parameter when a null TokenInformation value is passed.
  4. The GetTokenInformation function has to be called again with the length of the buffer obtained from the previous call along with a pointer to the buffer that will be populated via the TokenInformation parameter. The TokenInformation structure can then be cast to a structure that is defined as TOKEN_USER that contains a structure called SID_AND_ATTRIBUTES that defines the SID that represents the user associated with the access token that was passed to GetTokenInformation.
  5. Once the TokenUser variable is populated, we can use the ConvertSidToStringSid function which takes in a SID structure and provides a readable SID value.
  6. This SID value can then be passed to Principal.SecurityIdentifier to be translated to a username using the Principal.NTAccount type.

Here’s the code in VB.NET.

Imports System.Runtime.InteropServices
Imports System.Security
Imports System.ComponentModel

Module ProcessFunctions
 <DllImport("kernel32.dll")> _
 Public Function OpenProcess(processAccess As ProcessAccessFlags, bInheritHandle As Boolean, processId As Integer) As Integer
 End Function

 <DllImport("advapi32.dll", SetLastError:=True)> _
 Public Function OpenProcessToken(ByVal ProcessHandle As IntPtr, ByVal DesiredAccess As Integer, ByRef TokenHandle As IntPtr) As Boolean
 End Function

 <DllImport("advapi32.dll", SetLastError:=True)> _
 Public Function GetTokenInformation(ByVal TokenHandle As IntPtr, ByVal TokenInformationClass As TOKEN_INFORMATION_CLASS, _
 ByVal TokenInformation As IntPtr, ByVal TokenInformationLength As System.UInt32, ByRef ReturnLength As System.UInt32) As Boolean
 End Function

 <DllImport("advapi32.dll", SetLastError:=True)> _
 Public Function ConvertSidToStringSid(ByVal psid As IntPtr, ByRef pStringSid As String) As Boolean
 End Function

 <DllImport("kernel32.dll", SetLastError:=True)> _
 Public Function GetExitCodeProcess(ByVal hProcess As IntPtr, ByRef lpExitCode As System.UInt32) As Boolean
 End Function

 Public Structure SID_AND_ATTRIBUTES
   Public Sid As IntPtr
   Public Attributes As Int32
 End Structure

 Public Structure TOKEN_USER
 End Structure

 Enum ProcessAccessFlags
   All = &H1F0FFF
   Terminate = &H1
   CreateThread = &H2
   VirtualMemoryOperation = &H8
   VirtualMemoryRead = &H10
   VirtualMemoryWrite = &H20
   DuplicateHandle = &H40
   CreateProcess = &H80
   SetQuota = &H100
   SetInformation = &H200
   QueryInformation = &H400
   QueryLimitedInformation = &H1000
   Synchronize = &H100000
 End Enum

   TokenUser = 1
 End Enum

Public Function GetUsernameFromProcessID(pid As Long) As String
  Dim phnd As Integer = OpenProcess(ProcessAccessFlags.QueryInformation, False, pid)
  If phnd <> 0 Then
    Dim Thnd As Integer
    OpenProcessToken(phnd, Principal.TokenAccessLevels.Query, Thnd)
    Dim TokenUser As TOKEN_USER
    Dim TokenInfLength As Integer = 0
    Dim sUserSid As String = ""
    Dim TokenInformation As IntPtr

    GetTokenInformation(Thnd, TOKEN_INFORMATION_CLASS.TokenUser, IntPtr.Zero, 0, TokenInfLength)
    TokenInformation = Marshal.AllocHGlobal(TokenInfLength)
    GetTokenInformation(Thnd, TOKEN_INFORMATION_CLASS.TokenUser, TokenInformation, TokenInfLength, TokenInfLength)

    TokenUser = DirectCast(Marshal.PtrToStructure(TokenInformation, TokenUser.GetType), TOKEN_USER)

    ConvertSidToStringSid(TokenUser.User.Sid, sUserSid)

    Dim username As String = New Principal.SecurityIdentifier(sUserSid).Translate(GetType(Principal.NTAccount)).ToString()
    Return username
 Else : Return "<access denied>"
 End If
End Function
End Module
Add this code as part of your project in a module and access the function using GetUsernameFromProcessID(pid) which will return the username if you have access to the process and “<access denied>” if you don’t.
Happy Hacking!

Volume Mute and SendMessage() Fun

As the owner of the @wincmdfu twitter account, I try and find alternate ways of doing stuff in Windows. I normally have a bunch of batch files, VB script files and powershell cmdlets in a custom folder in %PATH% that I call when required. While listening to some music the other day, I realized there is no shortcut that I know (or have discovered yet) that allows me to mute the Audio on my system. I have a hardware key on the keyboard that mutes the volume, but no command to do this (remotely for example – which is cooler).

Enter the Windows SendMessage API. This is a fantastic API that Windows uses to send messages to windows given the handle of the target window. This window could be in a different process as well. The SendMessage function calls the window procedure for the specified window and does not return until the window procedure has processed the message.

I will be writing about additional fun stuff you can do with the SendMessage API, but for now coming back to my problem statement. SendMessage can be used to send the WM_APPCOMMAND with the APPCOMMAND_VOLUME_MUTE parameter to the current window handle to toggle mute. This can programmatically be put into a Form/console application and run from command line. Here’s my VB.NET code:

[code language=”vb” gutter=”false”]
Public Class Form1

<Runtime.InteropServices.DllImport("user32.dll")> _
Public Shared Function SendMessageW(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
End Function

Private Const APPCOMMAND_VOLUME_MUTE As Integer = &H80000
Private Const WM_APPCOMMAND As Integer = &H319

Private Sub Main_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
End Class

Compile this into an executable called mute.exe, store it in %PATH% and you are done!
Happy Hacking!