Article

Persistence Architecture Matters

Overview

This post relates to an initially confusing issue that I came across on a targeted attack, with a lot of discussion and help from Ben Campbell. The plan was to persist on a host by uploading a DLL and using rundll32 to execute it by adding it to the registry (HKEY_LOCAL_MACHINE\Software\Microsoft\CurrentVersion\Run). The target system, for the purposes of this demonstration, was a fully patched Windows 8.1 64-bit workstation and we have local administrative privileges. I was using Cobalt Strike's 32-bit Beacon as a RAT, but this issue is not specific to Cobalt Strike. I have illustrated the problem using an example EXE instead of a DLL; the underlying principle does not change. The first stage was to upload the malicious binary (mwr.exe); this was uploaded and placed in C:\Windows\System32.

Manual Approach

For demonstration purposes, the screenshots below show the command below being executed in a high integrity command process on the console.

reg add "HKLM\Software\Microsoft\Windows\CurrentVersion\Run" /v "MWR Connectback" /t REG_SZ /d "C:\Windows\System32\mwr.exe" /f

As expected, the registry key is created correctly and could be seen in regedit.exe.

persist matters initialreg

RAT

When attempting to run the same command on an administrative process remotely (e.g. through Beacon), the output implied that it was successful:

beacon> shell whoami /groups
[*] Tasked beacon to run: whoami /groups
[+] host called home, sent: 22 bytes
[+] received output:

GROUP INFORMATION
-----------------

Group Name                                                    Type             SID          Attributes

============================================================= ================ ============ ===============================================================
Everyone                                                      Well-known group S-1-1-0      Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Local account and member of Administrators group Well-known group S-1-5-114    Mandatory group, Enabled by default, Enabled group
BUILTIN\Administrators                                        Alias            S-1-5-32-544 Mandatory group, Enabled by default, Enabled group, Group owner
BUILTIN\Performance Log Users                                 Alias            S-1-5-32-559 Mandatory group, Enabled by default, Enabled group
BUILTIN\Users                                                 Alias            S-1-5-32-545 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\INTERACTIVE                                      Well-known group S-1-5-4      Mandatory group, Enabled by default, Enabled group
CONSOLE LOGON                                                 Well-known group S-1-2-1      Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Authenticated Users                              Well-known group S-1-5-11     Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\This Organization                                Well-known group S-1-5-15     Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Local account                                    Well-known group S-1-5-113    Mandatory group, Enabled by default, Enabled group
LOCAL                                                         Well-known group S-1-2-0      Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\NTLM Authentication                              Well-known group S-1-5-64-10  Mandatory group, Enabled by default, Enabled group
Mandatory Label\High Mandatory Level                          Label            S-1-16-12288

beacon> shell reg add "HKLM\Software\Microsoft\Windows\CurrentVersion\Run" /v "MWR Connectback" /t REG_SZ /d "C:\Windows\System32\mwr.exe" /f
[*] Tasked beacon to run: reg add "HKLM\Software\Microsoft\Windows\CurrentVersion\Run" /v "MWR Connectback" /t REG_SZ /d "C:\Windows\System32\mwr.exe" /f
[+] host called home, sent: 135 bytes
[+] received output:
The operation completed successfully.

However, the key did not appear to be created despite the successful response; regedit.exe did not reveal it.

Investigation

Ben and I then used Procmon to monitor reg.exe. When reg.exe was called from the console, it wrote to HKEY_LOCAL_MACHINE\Software\Microsoft\CurrentVersion\Run as expected. However, when reg.exe was called from the RAT, it instead wrote to HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\CurrentVersion\Run, despite the actual command line being identical. The EXE did appear to execute on restart, meaning that Windows searches both of these locations. The only difference between the two situations above was that the console cmd.exe was a 64-bit process and the RAT was a 32-bit process.

persist matters wow64

Analysis

It turns out that the answer to this lies in an understanding of "Windows on Windows" (WOW) which is a solution to the problem of 32-bit and 64-bit programs needing to work at the same time. It affects both the registry and the filesystem. In the old days of 32-bit Windows, there was a relatively easy structure to follow; for example, C:\Windows\System32 contained the windows system binaries and that was where you looked if you needed them. However, users of 64-bit operating systems expect both 32-bit and 64-bit code to work properly, meaning that references to "C:\Windows\System32" needs to point to 32-bit binaries for 32-bit processes and 64-bit binaries for 64-bit processes. A similar issue exists in the system registry for certain keys.

Filesystem

In order to deal with this, Microsoft implemented a WOW redirection layer, which 'redirects' some parts of the filesystem and registry depending on the architecture of the calling process. The best way to explain this is by example.

64-bit Process

From the perspective of a 64-bit process:

TargetWhat it containsWhere the folder actually is
C:\Windows\System32 It contains 64-bit system binaries. C:\Windows\System32
C:\Windows\SysWOW64 It contains 32-bit system binaries. C:\Windows\SysWOW64

32-bit Process

From the perspective of a 32-bit process:

TargetWhat it containsWhere the folder actually is
C:\Windows\System32 It contains 32-bit system binaries. C:\Windows\SysWOW64
C:\Windows\sysnative It contains 64-bit system binaries. Note that this is a virtual folder; you can't see it unless you are in a 32-bit process. C:\Windows\System32

This is initially quite confusing but it does make sense. When a 32-bit process wants to access C:\Windows\System32, WOW 'redirects' it to c:\Windows\SysWOW64 which contains the 32-bit system binaries. When a 64-bit process wants to access C:\Windows\System32, WOW lets it carry on because it knows that it is a 64-bit process.

Registry

The same problem exists in the registry. For example:

64-bit Process

From the perspective of a 64-bit process:

TargetWhat it containsWhere the registry key actually is
HKEY_LOCAL_MACHINE\Software\Microsoft\CurrentVersion\Run Contains the run keys in '64-bit' mode. HKEY_LOCAL_MACHINE\Software\Microsoft\CurrentVersion\Run
HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\CurrentVersion\Run It contains the run keys in '32-bit' mode. HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\CurrentVersion\Run

32-bit Process

From the perspective of a 32-bit process:

TargetWhat it containsWhere the registry key actually is
HKEY_LOCAL_MACHINE\Software\Microsoft\CurrentVersion\Run Contains the run keys in '32-bit' mode. HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\CurrentVersion\Run

Note that you can pass /reg:64 or /reg:32 as parameters to reg.exe in order to force it to manipulate either the 64-bit or 32-bit view.

 

Effect

Most of the time, binaries just work with no configuration. However, this can be problematic if you are on a penetration test and are looking to upload to C:\Windows\System32 or backdoor an executable in there. It is especially relevant for DLLs because C:\Windows\System32\rundll32.exe is meant for 64-bit DLLs and C:\Windows\SysWOW64\rundll32.exe is meant for 32-bit DLLs. Most RATs (metasploit, cobalt strike etc.) can create stager DLLs to help with this, but you need to make sure that the right version of rundll32 is in use if the DLL uses any form of process hollowing or injection because the wrong architecture will just cause a crash.

There is arguably a more serious consequence of this confusion from a professionalism perspective. The scenario in this case is that you are delivering a 'red team' style penetration test for a client which has included persistence and you have decided to persist by installing a meterpreter DLL (windows/meterpreter/reverse_https) executed using rundll32; the relevance of this is that it is a 32-bit process. You therefore:

  1. Upload rat32.dll to C:\Windows\System32 (remember that this would get silently remapped to c:\Windows\SysWOW64).
  2. Write a registry run key to HKLM\Software\Microsoft\Windows\CurrentVersion\Run (remember that this would get silently remapped to HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\CurrentVersion\Run).

For whatever reason, you are unable to clean up, have to provide an audit trail or client asks for the artefacts to be preserved in order to test their incident response and investigation. You therefore inform the client that there is an artefact (c:\windows\system32\rat32.dll) and a registry key (HKEY_LOCAL_MACHINE\Software\Microsoft\CurrentVersion\Run) that requires deletion. The client connects to the host using RDP and then loads regedit.exe and Explorer to look for the file and registry key; they will find neither because the tools they were using are 64-bit and therefore are looking in different places. They then assume that everything is cleaned up despite the artefact still being technically present. This could cause confusion or criticism later on if the implants are discovered and incorrectly believed to be a real attack. Therefore, it is important that this is taken into account during debriefing and reporting. I match the host architecture so will always give "64-bit" paths because that is what the client will most likely be familiar with. In the example above, the client should have been told that:

  1. The binary was uploaded to C:\Windows\SysWOW64\rat32.dll
  2. The registry key was added to HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\CurrentVersion\Run

Remember that the environment changes depending on the key. For example, if 'rundll32' is called from HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\CurrentVersion\Run, it will run C:\Windows\SysWOW64\rundll32.exe which is the 32-bit version so everything will be remapped accordingly. If 'rundll32' is called from HKEY_LOCAL_MACHINE\Software\Microsoft\CurrentVersion\Run, it will run C:\Windows\System32\rundll32.exe. Be aware of this; if otherwise reliable DLLs crash or do not work properly, it may be because the architecture of the calling process is not what you expected it to be.

Autoruns

Autoruns is aware of this and will perform the remapping back. For example, the following commands were executed:

meterpreter > sysinfo
Computer        : TESTER
OS              : Windows 8.1 (Build 9600).
Architecture    : x64 (Current Process is WOW64)
System Language : en_GB
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x86/win32

meterpreter > upload /tmp/payload.exe c:\\windows\\system32\\payload.exe
[*] uploading  : /tmp/payload.exe -> c:\windows\system32\payload.exe
[*] uploaded   : /tmp/payload.exe -> c:\windows\system32\payload.exe

meterpreter > shell
Process 4964 created.
Channel 2 created.
Microsoft Windows [Version 6.3.9600]
(c) 2013 Microsoft Corporation. All rights reserved.

C:\Windows\system32>reg add "HKLM\Software\Microsoft\Windows\CurrentVersion\Run" /v "MWR Connectback" /t REG_SZ /d "C:\Windows\System32\payload.exe" /f                        
reg add "HKLM\Software\Microsoft\Windows\CurrentVersion\Run" /v "MWR Connectback" /t REG_SZ /d "C:\Windows\System32\payload.exe" /f
The operation completed successfully.

C:\Windows\system32>exit
exit
meterpreter >

As this has been uploaded by a 32-bit process running on a 64-bit OS, the remapping will have occurred. However, Autoruns has correctly translated the paths, meaning that its output can be relied on.

persist matters autoruns

Conclusion

It does at first make your head hurt because \system32 contains 64-bit binaries and \SysWow64 contains 32-bit binaries. However, it is what it is and it is a very clever way of offering compatibility across architectures in a seamless way. Once it makes sense, it will save a whole lot of confusion. The diagrams below show the registry and file redirection.

persist matters fsredirect

persist matters regredirect

 Thanks to Ben Campbell for his help with this.

Further Reading

The WOW64 Implementation Details, accessible at https://msdn.microsoft.com/en-us/library/windows/desktop/aa384274%28v=vs.85%29.aspx covers this in detail. It is worth reading the 'Registry Redirector' and 'Filesystem Redirector' sections a couple of times.