Event ID 7039 – out…pid a pid

This event is not very well explained on the internet, so I took a liberty of describing it below:

The event message is as follows:

A service process other than the one launched by the Service Control Manager connected when starting the [SERVICE_NAME] service. The Service Control Manager launched process [PID1] and process [PID2] connected instead.

Note that if this service is configured to start under a debugger, this behavior is expected.

The message kinda tells us what happened – two different processes talk to SCM instead of one. It doesn’t really tell us WHY this happens.

Example from a case I looked at in response to a query on Twitter:

In this particular case the c:\windows\sysmon.exe was registered as a program that service process starts from. I believe this file was later manually replaced with a newer version of sysmon.exe. The little-known fact about distributable version of Sysmon (sysmon.exe from the sysinternals page) is that it is built as a 32-bit executable with an embedded 64-bit executable inside its resources. When launched on a 64-bit system the 32-bit version extracts and spawns that 64-bit version executable (note the PIDs and compare them against the Event Log):

Looking at it in general terms: when you register a service its configuration in Registry points to an executable file. This executable is then used to launch a service. Some services are not designed in a very good way. Once such programs are launched as a service, they spawn other processes, sometimes even batch files that may as well launch other programs. If one of these spawn programs talks to SCM the latter immediately recognizes that it’s not the same executable as the service process the service configuration points to. Such design is in general poor and could be a subject to possible privilege escalation (in a lolbinish way). And since this is a security concern the event 7039 is being logged.

And this leads me to the key reason I wanted to write an article. The Event 7309 tells you two things:

  • Whoever designed the service didn’t do the best job, OR, more importantly,
  • A bad guy may be using a badly designed service to escalate privileges.

Hence, you should be looking at these.

And last, but not least – does it mean Sysmon is designed badly? Nope. It’s designed in a clever way to use a single portable executable for 32-bit and 64-bit systems. The problem arises from a corner case in a way it was manually upgraded, instead of using the “-u” switch.

Code Execution via surgical callback overwrites (e.g. DNS memory functions)

Today I looked at Sysmon v10 and its support for logging DNS queries. It’s a pretty cool feature that intercepts all the DNS requests on a monitored host, and if possible, maps them to the process name making that request. It is a nice addition to Sysmon’s already awesome logging capabilities.

Just for fun, I created a simple POC that used DnsQuery_A API to send a multiline DNS query, because I wanted to see how Sysmon will react to it. It was obviously a non-sensical exercise, but it’s fun to see we can modify the layout of Event Logs by introducing some unexpected, redundant data:

Anyway…

I decided to look at the DnsQuery_A function in IDA as well. I was curious if/what characters it accepts & if there is any limit to the buffer it can process. This was a quick & dirty attempt to see if I could send a query that Sysmon would truncate in a similar fashion as I described in this post.

While digging into the code I noticed an interesting way dnsapi.dll is allocating memory. Instead of a fixed (inline) function it relies on a couple of callbacks. One of them is a memory allocation routine. When the library needs memory, it calls the function, and if it is not set, it relies on its own internal routines.

This immediately caught my attention. If we can find the address of this callback inside a remote process we can use it to execute code next time DNS library asks for memory.

This is the memory allocation function used by DnsQuery_* functions (32-bit):

Under normal circumstances finding callback pointers in a remote process memory is quite hard and noisy (lots of ReadProcessMemory calls, possible disassembling). Unless of course there is an interface we can use to surgically target some specific callback (e.g. using documented windows messages, or SetProp function). As far as I can tell there is no such interface in our case.

I found a surrogate solution that we can try to exploit though.

When I looked at references to the callback function (which I named fnMemAlloc on the listing above) I discovered a exported function called DnsApiHeapReset. It takes 3 arguments and each of them is … a callback replacement:

I quickly analyzed each callback’s role and they just are 3 basic/core memory allocation/reallocation/release primitives.

So…

If we can locate the address of dnsapi.dll in a remote process (easy), find the address of exported DnsApiHeapReset function (easy), then with a basic parsing of its code we can discover the address of each callback (also easy). Then, with a single, surgical WriteProcessMemory call we can modify any of them.

This is not a new code injection trick. It’s just one way to execute code without engaging remote threads, APCs, windows hooks, side-loading, process hollowing, patching API code (e.g. NtClose), etc..

There are of course tons of other callbacks like this, but finding their exact location without any point of reference is hard. Or… not really. Just think of all the Windows Procedures – all of them are callbacks.