A team of two German researchers has devised a method to detect Conficker (in its known variants) through the RSA keys which originally have been used by the Conficker authors against anyone attempting to fool Conficker into updating from an unauthorized (by its authors) source. They also offer a tool to scan the network for possibly infected systems and a tool to scan for and disinfect Conficker from memory.
Here’s the website and the paper by the same two guys is offered through the honeynet project.
There’s only one weakness I see in the current memory disinfection scheme. Just like watchdog processes, the threads could act as watchdog threads to observe each other’s state. Knowing that in Win32, the termination of a thread satisfies a waiter (e.g. WaitForSingleObject
), the current method could be thwarted by the Conficker authors through the use of watchdog threads.
However, since it is obviously possible to detect the threads executing Conficker code, it is possible in turn to make this potential workaround of the Conficker authors fail again and it should also work in the current version of the tool: suspending all detected threads. This serves the purpose that the threads won’t get signalled by the call to ExitThread
at the end of the NOP
-sled described in the research paper. Hence any waiting watchdog threads wouldn’t get notified. By the way, once all of them are suspended it is well possible to kill the threads using something like TerminateThread
– the waiters are all asleep and thus won’t get notified 😉
In order to demonstrate what I mean, I took an hour to write a little completely harmless sample program. It takes either nothing or /suspend
or /kill
as the only parameter. It is a Win32 console application, so make sure to start it within a console window instead of simply double-clicking it.
What do the parameters do?
- no parameter – the “evil” thread is started by the watchdog thread and will exit with a code of
0xDEADBEEF
after a number of loop runs. This simulates an ExitThread
call with said exit code. At that point you can abort the program by hitting CTRL+C
.
/kill
– the “evil” thread is started in the same way, but killed using the TerminateThread
every few seconds by the main thread, which will cause the watchdog thread to spawn a new “evil” thread.
/suspend
– the “evil” thread will happily start and will get suspended after a moment by the main thread, which will effectively inhibit any “evil” behavior. Also note how the watchdog thread is still fine with the state of the thread.
Now imagine this with numerous threads spread throughout numerous processes on a machine. Things will get really messy – especially if the evil and the watchdog threads cannot be separated because there is only one thread type containing both parts of the logic. Also note that the behavior without any parameter combined with the behavior of a defender (the good guys) killing the “evil” thread by any means (including the NOP
-sled and ExitThread
) is realistic only if the malware (or its authors for that matter) decide to “shut down”, which can be achieved by checking the exit code of the thread against a known value, so the watchdogs are not going to spawn new instances immediately. Honestly, though, I cannot see any reason why they would create this loop hole. After all the main thread of a process is the deciding factor for the life time of all threads owned by that process (so why provide an explicit mechanism to shut them down gracefully?).
Of course the sample code is available in my SVN repo and you can download the binary via HTTPS here. The usual disclaimer applies:
This software is provided ‘as-is’, without any express or implied warranty. In no event will the author be held liable for any damages arising from the use of this software.
SHA1: 1f8566eabf1319bb787fc27fb4dbcfca36116560 *thread-demo.zip
// Oliver
PS: I should note that the thread-safety is … ehrm … basically non-existent. However, 32bit static values shouldn’t cross page boundaries, so that I can safely assume that reading and writing those is atomic. The printf
and stdio caching is another story, though.
PPS: Past experience with Vundo/Virtumonde has proven this method (suspend all, then kill) to be efficient.