Process Whitelist 'sanity'

I'm keeping a WhiteList of proceses in KM:

  • Paths to executables are stored in UM.
  • In ProcessNotifyRoutine I store the PID.
  • In ImageNotifyRoutine I get the exepath (based on PID, on first match I discard this PID). And request UM if this program is whitelisted (it also checks the hash of the exe, so not just the path).

I don't really have control over any of the whitelisted processes, it is completely user-defined. So also the access that other programs have to these whitelisted processes is out of my control.

This implementation is working well, so I'm looking at steps to circumvent this setup. One of which is a malicious behaving program could create a remote thread in one of the whitelisted programs and I would see this as 'allowed' (I basically use IoThreadToProcess).

Now I've been looking into ways to at least detect this behavior. First I'd like to state what research I've done, where I am kind of stuck and I hope someone can point me in a correct direction to look.

First of all, I'm looking into ways to do this without having to hook any kernel functions(or any functions for that matter). I've talked to some (anti-)malware expert about this and this was the first thing he suggested. But I hope that there is a clean way to do this.

So I set my journey off looking at the thread and process structures(I have the Windows Internals book as well). I know there is a relation between a thread and it's owning process. And a relation between a process and a parent process. But after CreateRemoteThread the thread belongs to the injected process(correct?), so it will point to the whitelisted process' PEB which in turn gives me WhiteListed's parent.

I know that directly reading from these structures would be undocumented, but I am more confident to have some undocumented code as oppose to dirty code(hooks). Unless of course there is a documented way to get a thread's parent that I have overlooked ;).

So when this was sort-of a dead end I started testing with ThreadNotifyRoutine. I created a 'malicious' behaving process injecting a thread into another process and put an ASSERT in the notify routine.
I saw that when the NotificationRoutine was called, I was still in the context of the Attacker:

1: kd> !thread
THREAD fffffa800d3448c0 Cid 01d0.011c Teb: 000000007efdb000 Win32Thread: 0000000000000000 RUNNING on processor 1
Owning Process fffffa800d376060 Image: Attacker.exe

Which is something I don't understand. As far as I know, the NotificationRoutines are called at the end of Create(Remote)Thread, so I should already be in the context of the injected process.
I think this is where something is wrong with my attacker, I have tried another dll injector and it failed when running in the VM(that is how I do my debugging) but worked on my host.
So I'm guessing that if I DbgPrint in the ThreadNotifyRoutine and run it on my host with dbgview I will see that I am in the context of the injected process, I did not try this yet but I should.

I've looked at the CreateThread disassembly and it basically is a wrapper around CreateRemoteThread with PsGetCurrentProcess[-1] as HANDLE parameter. So I assume there is no real different between how a remote or a local thread is created(e.g. no obvious differences that I could 'expoit'). Except for some dedicated section in CreateRemoteTread where handle==PsGetCurrentProcess();

Next I thought about examining the callstack of a thread(in ThreadNotify isn't very useful.. as this is a new thread) at the point where I want to check if it belongs to a WhiteListed Process. I could then check if the call comes from a module inside the WhiteListed Process that I don't know about (injected DLL)... but there are so many caveats to this I don't consider it a good solution, if even possible atall.

That is basically where I stand at the moment, I know that CreateRemoteThread is not the only way to inject a thread but step by step I want to improve the solidity of the solution.

Hopefully someone can shed some light on this for me (I actually don't understand why there is no supported way to check this... provided of course that I did not miss it).

> This implementation is working well, so I’m looking at steps to circumvent this setup.

For the code running under admin privileges - lots of ways.

Everything can be circumvented.

Note that Ctrl-C creates a remote thread :slight_smile:


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

I know there are lots of ways ;), but that is no reason to give up :P.

And the ctrl-c thread won’t hurt me… the execution of that thread won’t reach anything that I need to monitor (and if it does, access is just logged… no more)

You will not produce an implementation that stands up to serious scrutiny or attack by going this route.

  • S

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Friday, June 04, 2010 10:42 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Process Whitelist ‘sanity’

I know there are lots of ways ;), but that is no reason to give up :P.

And the ctrl-c thread won’t hurt me… the execution of that thread won’t reach anything that I need to monitor (and if it does, access is just logged… no more)


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Ok, would you care to elaborate as oppose to giving me non-constructive criticism?

The security model of the system is based on user account separation. There is code all over the operating system that makes conditional access decisions based on user accounts.

You can’t just throw in some ad-hoc checks in the create process/thread hooks and hope to come out with something that provides security guarantees on a more fine grained basis than the user account, especially a fully privileged an administrator account.

All of the logic in the system that depends on user accounts for security decisions is completely, blissfully unaware of the additional policy you are trying to provide. Finding and changing all of these regions, which in many cases would result in moving access decisions further ‘upstream’, is an enormous undertaking even if you had a team of folks fully versed in all of the code that had to be touched system-wide.

And that does not even begin to touch the surface when it comes to third party apps that use the security model as it was designed.

  • S

-----Original Message-----
From: xxxxx@gmail.com
Sent: Friday, June 04, 2010 12:11
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Process Whitelist ‘sanity’

Ok, would you care to elaborate as oppose to giving me non-constructive criticism?


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Hm, I’m sorry but I think you are misunderstanding my question (apologies that it is a long read :P).

First off as I mentioned in my first post, I’m not initially looking for a solution that requires hooking… that would be taking the dirty road… the reason I posted my question here is to try and find a clean way to know when a process creates a remote thread in ‘some’ monitored process.

The WhiteList is for a FileSystem mini-filter. I don’t work for a company to produce a commercial product, I’m a mechanical engineer with an interest in Kernel development and security in generalI am enrolling in a master in Computer Security next year. So in advance of this master I wish to play around with things like Filter drivers and the like.

So I give myself a project and start working on it. At this moment the project does what I intended, so then I start thinking about ways how to break my solution, another process ‘injecting’ a thread is one way. So I am not (yet) after a full-blown solution, at the moment I just wish to detect when another process creates a thread in a WhiteListed process using the CreateRemoteThread API.

Thanks for taking the effort to explain yourself though

I *think* you may have misunderstood Ken’s post (BTW, in case you’re not aware, he DOES know a bit about the area about which you’re inquiring).

Like we ALL wind-up saying so frequently on this list: The base security problem is the ability of MaliciousProcessA to get the necessary privileges to successfully inject a thread into GoodProcessB. Once MaliciousProcessA has, for example, admin privs, then there are darn few things it can’t do. I mean, it could shut the system down, right? Delete files? Whatever…

So, while you’re trying to slather another layer of security onto the the process execution structure, there are soo very many other entries that it’s not clear what you’d actually be preventing in the long run.

Peter
OSR

Hm my bad, I did not read his post that way, apologies.
I’ve not truely looked at it in this way… but now that you put it infront of me it does make sense.

Oh and I did not mean any offense with my ‘care to elaborate’ post by the way, I guess it may seem that way :P. I’m not one who accepts an answer like ‘it is wrong’ without trying to understand why ;).

In any case, I’ll re-think my approach and look deeper into how the Windows security model is ‘meant’ to work, thank you.

> This implementation is working well, so I’m looking at steps to circumvent this setup.

One of which is a malicious behaving program could create a remote thread in one of the
whitelisted programs and I would see this as ‘allowed’ (I basically use IoThreadToProcess).

There is a logical fallacy here. The very first thing the malicious code needs to do is to get started, in the first place. If you disallow loading ANY executable image (EXE,DLL or SYS) that does not happen to be on the whitelist, you will simply never ever reach the stage when the problem that you had mentioned may arise.

The problem that you have mentioned may arise only if the admin user modifies the whitelist and allows a program that exhibits above mentioned “peculiar behavior” to run. As Ken and Peter pointed out already, at this point game is over if the target program runs under admin account. However , you cannot protect admin user against himself/herself, can you…

It is understandable that you will have to compute a checksum/cryptographic hash/etc for every file
on the whitelist if you want your software to be reliable. Otherwise the whole thing may get broken by replacing executable image (which, btw, can be done by some “whitelisted” program without any malicious intent) on the disk…

Anton Bassov

I don’t wish to disallow anything (a non-whitelisted program is allowed to start). That would be way too intrusive (it might be an imaginary project, doesn’t mean it can be bad :P).

The whitelisted process are allowed to do some action (read from important.txt). And if a non-whitelisted process does this I want to log it (doesnt even have to deny it). And of course when an infected whitelisted process tries to read I wish to log as well.

But I understand the thought-mistake that I’ve made.

> I don’t wish to disallow anything (a non-whitelisted program is allowed to start). That would be way

too intrusive (it might be an imaginary project, doesn’t mean it can be bad :P). The whitelisted
process are allowed to do some action (read from important.txt). And if a non-whitelisted process
does this I want to log it (doesnt even have to deny it). And of course when an infected whitelisted
process tries to read I wish to log as well.

In other words, you are speaking about detection , rather than prevention. Whitelisting approach is normally associated with the latter, but never mind…

But I understand the thought-mistake that I’ve made.

In such case you “thought mistake” is a bit different . Just consider the scenario when multiple instances of the same program run under different accounts (I assume it does not do anything that requires root privilege level). However, you want your important.txt to be available to users A and B
for RW access, C and D for RO one, and unavailable to anyone else. Therefore, you may want to treat these instances of the same program differently from one another. How are you going to handle it if you simply “whitelist” certain programs??? This is yet another example that exposes the logical fallacy of relating security-related policies to a program per se, rather than to a user who runs it…

Anton Bassov