Last updated at Wed, 07 Feb 2024 20:10:10 GMT

We recently decided to finally take a stab at integrating kernel-mode payloads into Metasploit 3.0.  This presented an interesting challenge for us in terms of architectural integration.  We wanted to make it so users could continue to use the existing set of user-mode payloads for both kernel and non-kernel exploits.  Strictly speaking, every payload in Metasploit to date is a user-mode payload, and as such they will not function properly with a kernel-mode exploit.  However, the goal of making it possible to re-use the existing payload modules meant either re-architecting the way the payload subsystem is designed or coming up with an alternative way of generically staging user-mode payloads from kernel-mode.  At the moment, we've opt'd for the latter choice.

In the current implementation, we assume that an exploit will either be exploiting a kernel-mode bug or a user-mode bug.  If it's a kernel-mode bug, the exploit should include the Msf::Exploit::KernelMode mixin.  This mixin overrides a method on the Msf::Exploit base class that is used during the process of encoding a payload.  Since the goal is to stage user-mode payloads from kernel-mode, the overriden method acts as an encapsulation step in the encoding process.  The method does this by passing the user-mode payload to a routine that selects the approrpriate kernel-mode stager (based on architecture, platform, and other restrictions).  The end result is a pre-encoded buffer that will first execute in kernel-mode and then eventually result in the embedded user-mode payload being executed.  Thus, for all intents and purposes, kernel-mode exploits are able to continue to use the existing set of user-mode payloads.

While this works fine, a more long term solution may involve abstracting the payload module design.  Rather than continuing to consider a payload module as being strictly buffer-centric, it may be better to represent it in terms of a series of containers (or functions).   A function is a more apt comparison.  When constructing a payload, it can undergo a series of mutations, each of which alters the payload in a certain way at a specific phase in construction, such as replacing variable values.  Given explicitly ordered containers, this can result in a payload being constructed from the ground up.  In principle, this means payload generation can be represented in a manner like:

windows/shell/reverse_tcp (1st stage with kernel-mode wrapper)

encapsulate_user_mode(
  replace_variable(
        replace_variable(
                generate_user_mode(),
              'LHOST',
              ...),
        'LPORT',
        ...)
)

Regardless of implementation, the fact that we have the initial integration of kernel-mode payloads complete can mean only one thing: it's time for Metasploit 3.0 to have some kernel-mode exploits.  To that point, H D has spent some time wrappering lorcon in ruby.  If successful, this will allow us to exploit some of those nefarious layer-2 WiFi bugs (yes, they do exist) out there, but it will only work on platforms that lorcon is compatible with.  Imagine what it will be like to get a user-mode meterpreter instance, without touching the disk, through a reverse TCP connection when exploiting a flaw in a wireless device driver.  If this were a mastercard commercial, I'd be shooting for the priceless slot.  Surely there will be more fun things to come.

Finally, the current code on trunk is somewhat limited.  There's only one kernel-mode stager defined for Windows and it will only work on XPSP2/2K3 SP1.  The stager we're using is basically a more limited implementation of the one described here.  In the near future, we'll integrate some other kernel-mode payloads, many of which we'll derive from previous research and any other useful kernel-mode payloads people want to send us.