mirror of https://github.com/fdiskyou/Zines.git
380 lines
16 KiB
Plaintext
380 lines
16 KiB
Plaintext
FUTo
|
|
Peter Silberman & C.H.A.O.S.
|
|
|
|
|
|
1) Foreword
|
|
|
|
Abstract:
|
|
|
|
Since the introduction of FU, the rootkit world has moved away from
|
|
implementing system hooks to hide their presence. Because of this change
|
|
in offense, a new defense had to be developed. The new algorithms used
|
|
by rootkit detectors, such as BlackLight, attempt to find what the
|
|
rootkit is hiding instead of simply detecting the presence of the
|
|
rootkit's hooks. This paper will discuss an algorithm that is used by
|
|
both Blacklight and IceSword to detect hidden processes. This paper will
|
|
also document current weaknesses in the rootkit detection field and
|
|
introduce a more complete stealth technique implemented as a prototype
|
|
in FUTo.
|
|
|
|
Thanks:
|
|
|
|
Peter would like to thank bugcheck, skape, thief, pedram, F-Secure for
|
|
doing great research, and all the nologin/research'ers who encourage
|
|
mind growth.
|
|
|
|
C.H.A.O.S. would like to thank Amy, Santa (this work was three hours on
|
|
Christmas day), lonerancher, Pedram, valerino, and HBG Unit.
|
|
|
|
|
|
2) Introduction
|
|
|
|
In the past year or two, there have been several major developments in
|
|
the rootkit world. Recent milestones include the introduction of the FU
|
|
rootkit, which uses Direct Kernel Object Manipulation (DKOM); the
|
|
introduction of VICE, one of the first rootkit detection programs; the
|
|
birth of Sysinternals' Rootkit Revealer and F-Secure's Blacklight, the
|
|
first mainstream Windows rootkit detection tools; and most recently the
|
|
introduction of Shadow Walker, a rootkit that hooks the memory manager
|
|
to hide in plain sight.
|
|
|
|
Enter Blacklight and IceSword. The authors chose to investigate the
|
|
algorithms used by both Blacklight and IceSword because they are
|
|
considered by many in the field to be the best detection tools.
|
|
Blacklight, developed by the Finnish security company F-Secure, is
|
|
primarily concerned with detecting hidden processes. It does not attempt
|
|
to detect system hooks; it is only concerned with hidden processes.
|
|
IceSword uses a very similar method to Blacklight. IceSword
|
|
differentiates itself from Blacklight in that it is a more robust tool
|
|
allowing the user to see what system calls are hooked, what drivers are
|
|
hidden, and what TCP/UDP ports are open that programs, such as netstat,
|
|
do not.
|
|
|
|
|
|
3) Blacklight
|
|
|
|
This paper will focus primarily on Blacklight due to its algorithm being
|
|
the research focus for this paper. Also, it became apparent after
|
|
researching Blacklight that IceSword used a very similiar algorithm.
|
|
Therefore, if a weakness was found in Blacklight, it would most likely
|
|
exist in IceSword as well.
|
|
|
|
Blacklight takes a userland approach to detecting processes. Although
|
|
simplistic, its algorithm is amazingly effective. Blacklight uses some
|
|
very strong anti-debugging features that begin by creating a Thread
|
|
Local Storage (TLS) callback table. Blacklight's TLS callback attempts
|
|
to befuddle debuggers by forking the main process before the process
|
|
object is fully created. This can occur because the TLS callback routine
|
|
is called before the process is completely initialized. Blacklight also
|
|
has anti-debugging measures that detect the presence of debuggers
|
|
attaching to it. Rather than attempting to beat the anti-debugging
|
|
measures by circumventing the TLS callback and making other program
|
|
modifications, the authors decided to just disable the TLS routine. To
|
|
do this, the authors used a tool called LordPE. LordPE allows users to
|
|
edit PE files. The authors used this tool to zero out the TLS callback
|
|
table. This disabled the forking routine and gave the authors the
|
|
ability to use an API Monitor. It should be noted that disabling the
|
|
callback routine would allow you to attach a debugger, but when the user
|
|
clicked "scan" in the Blacklight GUI Blacklight would detect the
|
|
debugger and exit. Instead of working up a second measure to circumvent
|
|
the anti-debugging routines, the authors decided to analyze the calls
|
|
occuring within Blacklight. To this end, the authors used Rohitabs API
|
|
Monitor.
|
|
|
|
In testing, one can see failed calls to the API OpenProcess (tls zero is
|
|
Blacklight without a TLS table). Blacklight tries opening a process with
|
|
process id (PID) of 0x1CC, 0x1D0, 0x1D4, 0x1D8 and so on. The authors
|
|
dubbed the method Blacklight uses as PID Bruteforce (PIDB). Blacklight
|
|
loops through all possible PIDS calling OpenProcess on the PIDs in the
|
|
range of 0x0 to 0x4E1C. Blacklight keeps a list of all processes it is
|
|
able to open, using the PIDB method. Blacklight then calls
|
|
CreateToolhelp32Snapshot, which gives Blacklight a second list of
|
|
processes. Blacklight then compares the two lists, to see if there are
|
|
any processes in the PIDB list that are not in the list returned by the
|
|
CreateToolhelp32Snapshot function. If there is any discrepancy, these
|
|
processes are considered hidden and reported to the user.
|
|
|
|
|
|
3.1) Windows OpenProcess
|
|
|
|
In Windows, the OpenProcess function is a wrapper to the NtOpenProcess
|
|
routine. NtOpenProcess is implemented in the kernel by NTOSKRNL.EXE. The
|
|
function prototype for NtOpenProcess is:
|
|
|
|
NTSTATUS NtOpenProcess (
|
|
OUT PHANDLE ProcessHandle,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
|
IN PCLIENT_ID ClientId OPTIONAL);
|
|
|
|
The ClientId parameter is the actual PID that is passed by OpenProcess.
|
|
This parameter is optional, but during our observation the OpenProcess
|
|
function always specified a ClientId when calling NtOpenProcess.
|
|
|
|
NtOpenProcess performs three primary functions:
|
|
|
|
1. It verifies the process exists by calling PsLookupProcessByProcessId.
|
|
2. It attempts to open a handle to the process by calling
|
|
ObOpenObjectByPointer.
|
|
3. If it was successful opening a handle to the process, it passes the
|
|
handle back to the caller.
|
|
|
|
PsLookupProcessByProcessId was the next obvious place for research. One
|
|
of the outstanding questions was how does PsLookupProcessByProcessId
|
|
know that a given PID is part of a valid process? The answer becomes
|
|
clear in the first few lines of the disassembly:
|
|
|
|
PsLookupProcessByProcessId:
|
|
mov edi, edi
|
|
push ebp
|
|
mov ebp, esp
|
|
push ebx
|
|
push esi
|
|
mov eax, large fs:124h
|
|
push [ebp+arg_4]
|
|
mov esi, eax
|
|
dec dword ptr [esi+0D4h]
|
|
push PspCidTable
|
|
call ExMapHandleToPointer
|
|
|
|
From the above disassembly, it is clear that ExMapHandleToPointer
|
|
queries the PspCidTable for the process ID.
|
|
|
|
Now we have a complete picture of how Blacklight detects hidden processes:
|
|
|
|
1. Blacklight starts looping through the range of valid process IDs, 0
|
|
through 0x41DC.
|
|
2. Blacklight calls OpenProcess on every possible PID.
|
|
3. OpenProcess calls NtOpenProcess.
|
|
4. NtOpenProcess calls PsLookupProcessByProcessId to verify the
|
|
process exists.
|
|
5. PsLookupProcessByProcessId uses the PspCidTable to verify the
|
|
processes exists.
|
|
6. NtOpenProcess calls ObOpenObjectByPointer to get the handle to the
|
|
process.
|
|
7. If OpenProcess was successful, Blacklight stores the information
|
|
about the process and continues to loop.
|
|
8. Once the process list has been created by exhausting all possible
|
|
PIDs. Blacklight compares the PIDB list with the list it creates by
|
|
calling CreateToolhelp32Snapshot. CreateToolhelp32Snapshot is a Win32
|
|
API that takes a snapshot of all running processes on the system. A
|
|
discrepancy between the two lists implies that there is a hidden
|
|
process. This case is reported by Blacklight.
|
|
|
|
|
|
3.2) The PspCidTable
|
|
|
|
The PspCidTable is a "handle table for process and thread client IDs".
|
|
Every process' PID corresponds to its location in the PspCidTable. The
|
|
PspCidTable is a pointer to a HANDLE_TABLE structure.
|
|
|
|
typedef struct _HANDLE_TABLE {
|
|
PVOID p_hTable;
|
|
PEPROCESS QuotaProcess;
|
|
PVOID UniqueProcessId;
|
|
EX_PUSH_LOCK HandleTableLock [4];
|
|
LIST_ENTRY HandleTableList;
|
|
EX_PUSH_LOCK HandleContentionEvent;
|
|
PHANDLE_TRACE_DEBUG_INFO DebugInfo;
|
|
DWORD ExtraInfoPages;
|
|
DWORD FirstFree;
|
|
DWORD LastFree;
|
|
DWORD NextHandleNeedingPool;
|
|
DWORD HandleCount;
|
|
DWORD Flags;
|
|
};
|
|
|
|
Windows offers a variety of non-exported functions to manipulate and retrieve
|
|
information from the PspCidTable. These include:
|
|
|
|
- [ExCreateHandleTable] creates non-process handle tables. The
|
|
objects within all handle tables except the PspCidTable are pointers
|
|
to object headers and not the address of the objects themselves.
|
|
- [ExDupHandleTable] is called when spawning a process.
|
|
- [ExSweepHandleTable] is used for process rundown.
|
|
- [ExDestroyHandleTable] is called when a process is exiting.
|
|
- [ExCreateHandle] creates new handle table entries.
|
|
- [ExChangeHandle] is used to change the access mask on a handle.
|
|
- [ExDestroyHandle] implements the functionality of CloseHandle.
|
|
- [ExMapHandleToPointer] returns the address of the object corresponding to the handle.
|
|
- [ExReferenceHandleDebugIn] tracing handles.
|
|
- [ExSnapShotHandleTables] is used for handle searchers (for example in oh.exe).
|
|
|
|
Below is code that uses non-exported functions to remove a process
|
|
object from the PspCidTable. It uses hardcoded addresses for the
|
|
non-exported functions necessary; however, a rootkit could find these
|
|
function addresses dynamically.
|
|
|
|
typedef PHANDLE_TABLE_ENTRY (*ExMapHandleToPointerFUNC)
|
|
( IN PHANDLE_TABLE HandleTable,
|
|
IN HANDLE ProcessId);
|
|
|
|
void HideFromBlacklight(DWORD eproc)
|
|
{
|
|
PHANDLE_TABLE_ENTRY CidEntry;
|
|
ExMapHandleToPointerFUNC map;
|
|
ExUnlockHandleTableEntryFUNC umap;
|
|
PEPROCESS p;
|
|
CLIENT_ID ClientId;
|
|
|
|
map = (ExMapHandleToPointerFUNC)0x80493285;
|
|
|
|
CidEntry = map((PHANDLE_TABLE)0x8188d7c8,
|
|
LongToHandle( *((DWORD*)(eproc+PIDOFFSET)) ) );
|
|
if(CidEntry != NULL)
|
|
{
|
|
CidEntry->Object = 0;
|
|
}
|
|
return;
|
|
}
|
|
|
|
Since the job of the PspCidTable is to keep track of all the processes
|
|
and threads, it is logical that a rootkit detector could use the
|
|
PspCidTable to find hidden processes. However, relying on a single data
|
|
structure is not a very robust algorithm. If a rootkit alters this one
|
|
data structure, the operating system and other programs will have no
|
|
idea that the hidden process exists. New rootkit detection algorithms
|
|
should be devised that have overlapping dependencies so that a single
|
|
change will not go undetected.
|
|
|
|
|
|
4) FUTo
|
|
|
|
To demonstrate the weaknesses in the algorithms currently used by
|
|
rootkit detection software such as Blacklight and Icesword, the authors
|
|
have created FUTo. FUTo is a new version of the FU rootkit. FUTo has
|
|
the added ability to manipulate the PspCidTable without using any
|
|
function calls. It uses DKOM techniques to hide particular objects
|
|
within the PspCidTable.
|
|
|
|
There were some design considerations when implementing the new features
|
|
in FUTo. The first was that, like the ExMapHandleXXX functions, the
|
|
PspCidTable is not exported by the kernel. In order to overcome this,
|
|
FUTo automatically detects the PspCidTable by finding the
|
|
PsLookupProcessByProcessId function and disassembling it looking for the
|
|
first function call. At the time of this writing, the first function
|
|
call is always to ExMapHandleToPointer. ExMapHandleToPointer takes the
|
|
PspCidTable as its first parameter. Using this knowledge, it is fairly
|
|
straightforward to find the PspCidTable.
|
|
|
|
PsLookupProcessByProcessId:
|
|
mov edi, edi
|
|
push ebp
|
|
mov ebp, esp
|
|
push ebx
|
|
push esi
|
|
mov eax, large fs:124h
|
|
push [ebp+arg_4]
|
|
mov esi, eax
|
|
dec dword ptr [esi+0D4h]
|
|
push PspCidTable
|
|
call ExMapHandleToPointer
|
|
|
|
A more robust method to find the PspCidTable could be written as this
|
|
algorithm will fail if even simple compiler optimizations are made on
|
|
the kernel. Opc0de wrote a more robust method to detect non-exported
|
|
variables like PspCidTable, PspActiveProcessHead, PspLoadedModuleList,
|
|
etc. Opc0des method does not requires memory scanning like the method
|
|
currently used in FUTo. Instead Opc0de found that the KdVersionBlock
|
|
field in the Process Control Region structure pointed to a structure
|
|
KDDEBUGGER_DATA32. The structure looks like this:
|
|
|
|
typedef struct _KDDEBUGGER_DATA32 {
|
|
|
|
DBGKD_DEBUG_DATA_HEADER32 Header;
|
|
ULONG KernBase;
|
|
ULONG BreakpointWithStatus; // address of breakpoint
|
|
ULONG SavedContext;
|
|
USHORT ThCallbackStack; // offset in thread data
|
|
USHORT NextCallback; // saved pointer to next callback frame
|
|
USHORT FramePointer; // saved frame pointer
|
|
USHORT PaeEnabled:1;
|
|
ULONG KiCallUserMode; // kernel routine
|
|
ULONG KeUserCallbackDispatcher; // address in ntdll
|
|
|
|
ULONG PsLoadedModuleList;
|
|
ULONG PsActiveProcessHead;
|
|
ULONG PspCidTable;
|
|
|
|
ULONG ExpSystemResourcesList;
|
|
ULONG ExpPagedPoolDescriptor;
|
|
ULONG ExpNumberOfPagedPools;
|
|
|
|
[...]
|
|
|
|
ULONG KdPrintCircularBuffer;
|
|
ULONG KdPrintCircularBufferEnd;
|
|
ULONG KdPrintWritePointer;
|
|
ULONG KdPrintRolloverCount;
|
|
|
|
ULONG MmLoadedUserImageList;
|
|
|
|
} KDDEBUGGER_DATA32, *PKDDEBUGGER_DATA32;
|
|
|
|
As the reader can see the structure contains pointers to many of the
|
|
commonly needed/used non-exported variables. This is one more robust
|
|
method to finding the PspCidTable and other variables like it.
|
|
|
|
The second design consideration was a little more troubling. When FUTo
|
|
removes an object from the PspCidTable, the HANDLE_ENTRY is replaced with
|
|
NULLs representing the fact that the process "does not exist." The
|
|
problem then occurs when the process that is hidden (and has no
|
|
PspCidTable entries) is closed. When the system tries to close the
|
|
process, it will index into the PspCidTable and dereference a null
|
|
object causing a blue screen. The solution to this problem is simple but
|
|
not elegant. First, FUTo sets up a process notify routine by calling
|
|
PsSetCreateProcessNotifyRoutine. The callback function will be invoked
|
|
whenever a process is created, but more importantly it will be called
|
|
whenever a process is deleted. The callback executes before the hidden
|
|
process is terminated; therefore, it gets called before the system
|
|
crashes. When FUTo deletes the indexes that contain objects that point
|
|
to the rogue process, FUTo will save the value of the HANDLE_ENTRYs and
|
|
the index for later use. When the process is closed, FUTo will restore
|
|
the objects before the process is closed allowing the system to
|
|
dereference valid objects.
|
|
|
|
5) Conclusion
|
|
|
|
The catch phrase in 2005 was, ``We are raising the bar [again] for
|
|
rootkit detection''. Hopefully the reader has walked away with a better
|
|
understanding of how the top rootkit detection programs are detecting
|
|
hidden processes and how they can be improved. Some readers may ask
|
|
"What can I do?" Well, the simple solution is not to connect to the
|
|
Internet, but a combination of using both Blacklight, IceSword and
|
|
Rootkit Revealer will greatly help your chances of staying rootkit free.
|
|
A new tool called RAIDE (Rootkit Analysis Identification Elimination)
|
|
will be unveiled in the coming months at Blackhat Amsterdam. This new
|
|
tool does not suffer from the problems brought forth here.
|
|
|
|
Bibliography
|
|
|
|
Blacklight Homepage. F-Secure Blacklight
|
|
http://www.f-secure.com/blacklight/
|
|
|
|
|
|
FU Project Page. FU
|
|
http://www.rootkit.com/project.php?id=12
|
|
|
|
|
|
IceSword Homepage. IceSword
|
|
http://www.xfocus.net/tools/200505/1032.html
|
|
|
|
|
|
LordPE Homepage. LordPE Info
|
|
http://mitglied.lycos.de/yoda2k/LordPE/info.htm
|
|
|
|
|
|
Opc0de. 2005. How to get some hidden kernel variables without scanning
|
|
http://www.rootkit.com/newsread.php?newsid=101
|
|
|
|
|
|
Rohitabs API Monitor. API Monitor - Spy on API calls
|
|
http://www.rohitab.com/apimonitor/
|
|
|
|
|
|
Russinovich, Solomon. Microsoft Windows Internals Fourth Edition.
|
|
|
|
|
|
Silberman. RAIDE:Rootkit Analysis Identification Elimination
|
|
http://www.blackhat.com/html/bh-europe-06/bh-eu-06-speakers.htmlSilberman
|