Request Membership
Categories
Posts By Month
Bloggers
Related Links
Input Validation RSS

Anti-Debugging Series - Part IV

In this final part of the anti-debugging series we’re going to discuss process and thread block based anti-debugging. Processes and threads must be maintained and tracked by the operating system. In user space, information about the processes and threads are held in memory in structures known as the process information block (PIB), process environment block (PEB) and the thread information block (TIB). These structures hold data pertinent to the operation of that particular process or thread which is read by many of the API based anti-debugging methods we discussed previously.

When a debugger or reverse engineer tries to get aggressive and hook calls to anti-debugging related APIs we can move lower than the API and directly access the process and thread information to detect the attached debugger. By side stepping the operating system provided methods for querying process and thread information, we can effectively bypass some API based hooking techniques used in anti-anti-debugging efforts.

For example, in part II of this anti-debugging series I demonstrated how to make a call to IsDebuggerPresent() to detect if the debugger present process flag is set.

Prototype: BOOL WINAPI IsDebuggerPresent(void); 

if (IsDebuggerPresent()) {
    //Debugger Detected - Do Something Here
} else {
    //No Debugger Detected - Continue
}

If we analyzed what this API call actually does we would notice that it reads a flag from the PEB which indicates the presence of a debugger. Instead of directly calling the API, it is possible to emulate what the IsDebuggerPresent() function does and directly query the PEB ourselves.

The first step in analyzing data within the PEB structure is to locate the PEB structure in memory. To do this we can use a number of different methods, some more direct and low level that others. The method that is easiest to grasp is to call the function NtQueryInformationProcess with a second parameter of ProcessBasicInformation. This returns a pointer to the process information block (PIB) for the requested process. Once we have access to this PIB structure we look at the PebBaseAddress member to determine the base address of the PEB. Finally, we look at the boolean member BeingDebugged to return the same result that would be returned had we called the function IsDebuggerPresent().

The following code demonstrates our example:

hmod = LoadLibrary(L"Ntdll.dll");
_NtQueryInformationProcess = GetProcAddress(hmod, "NtQueryInformationProcess");

hnd = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
status = (_NtQueryInformationProcess) (hnd, ProcessBasicInformation, &pPIB, sizeof(PROCESS_BASIC_INFORMATION), &bytesWritten);

if (status == 0 ) {
  if (pPIB.PebBaseAddress->BeingDebugged == 1) {
    MessageBox(NULL, L"Debugger Detected Using PEB!IsDebugged", L"Debugger Detected", MB_OK);
  } else {
    MessageBox(NULL, L"No Debugger Detected", L"No Debugger Detected", MB_OK);
  }
}

There are a number of different ways that we can query the PEB and TIB blocks to detect the presence of a debugger. Let’s divert from the straight forward and instead look at a novel and interesting method of detecting a debugger specifically designed to operate under Windows Vista. In Vista, when a process is started without a debugger present, the main thread environment block contains a pointer to a Unicode string referencing a system DLL such as kernel32.dll. If the process is started under a debugger, that system DLL name is replaced with the Unicode string “HookSwitchHookEnabledEvent”. Thus if we know that the process we are trying to protect is running within a Windows Vista environment, we can use this technique to determine if the processes was launched from within a debugging environment.

To use this technique, the anti-debugging function should first check that it is running on the Windows Vista operating system. After confirming the operating system revision, the technique should locate the TIB. The TIB can be accessed as an offset of segment register FS as in the following code:

void* getTib()
{
  void *pTib;
  __asm {
    mov EAX, FS:[18h] //FS:[18h] is the location of the TIB
    mov [pTib], EAX
  }
  return pTib;
}

Once the location of the TIB is found, the offset 0xBFC from the start of the TIB is read and the pointer checked. If this value is 0x00000C00 we then read the string at offset 0xC00 and compare this value to the Unicode string “HookSwitchHookEnabledEvent”. We check the pointer to ensure that we have a string located in the pointed to address and as a second level of assurance for the accuracy of this method. If we pass this final test we can be sure that our process running under Windows Vista was started from within a debugger.

wchar_t *hookStr = _TEXT("HookSwitchHookEnabledEvent");
strPtr = TIB+0xBFC;

delta = (int)(*strPtr) - (int)strPtr;
if (delta == 0x04) {
   if (wcscmp(*strPtr, hookStr)==0) {
      MessageBox(NULL, L"Debugger Detected Via Vista TEB System DLL PTR", L"Debugger Detected", MB_OK);
    } else {
      MessageBox(NULL, L"No Debugger Detected", L"No Debugger", MB_OK);
    }
} else {
   MessageBox(NULL, L"No Debugger Detected", L"No Debugger", MB_OK);
}

In the four parts of this series we have discussed classes of anti-debugging methods, a few basic API based anti-debugging techniques, some slightly more advanced API techniques, and finally two methods that directly access process and thread information to detect the presence of a debugger.

Instead of continuing this series in blog format, I’ve decided to release a paper outlining the details of nearly 35 different anti-debugging methods. I’ll be presenting the paper (and associated slides) at the SOURCE Boston 2009 security conference which starts March 11th, 2009 and finishes up March 13, 2009. The paper and presentation are geared towards developers and software engineers who may not understand the assembly dump of some anti-debugging code but can understand what I’ve presented to you thus far.

The pre-registration rates for SOURCE Boston end on February 28, 2009. So get your ticket at a discount while you still can! It’s going to be a fantastic conference with some of the best information security topics and presenters in the industry.

Additionally, as a speaker, I’ve been given one ticket at half price to do with as I choose. As of yet I haven’t given it away. If anyone would like a half off ticket to SOURCE Boston and can attend please let me know. I’ll get the discount code over to you ASAP. I look forward to seeing you all at the conference, please come up and say hello!

Anti-Debugging Series - Part III

It’s time for part three in the Anti-Debugging Series. With this post we will stay in the realm of “API based” anti-debugging techniques but go a bit deeper into some techniques that are more complex and significantly more interesting. Today we will analyze one method of detecting an attached debugger, and a second method that can be used to detach a debugger from our running process.

Advanced API Based Anti-Debugging

There are a number of functions and API calls within the Windows operating system that are considered internal to the operating system and thus not documented well for the average developer. Many of these functions have undergone extensive research and reverse engineering to be able to understand how they operate and what can be achieved using them. One such poorly documented API function is the NtQueryInformationProcess function which is used to retrieve information about a target process. The function prototype looks like the following:

NTSTATUS WINAPI NtQueryInformationProcess(
    __in HANDLE ProcessHandle,
    __in PROCESSINFOCLASS ProcessInformationClass,
    __out PVOID ProcessInformation,
    __in ULONG ProcessInformationLength,
    __out_opt PULONG ReturnLength
);

This function resides within the Ntdll.dll file and is not an exported function. Because of this, we must use run-time dynamic linking to gain access to the functionality. Run-time dynamic linking is the dynamic loading of a library and mapping of functions within the library to a function pointer allowing it to be called and executed. To load our function, “NtQueryInformationProcess”, we first call LoadLibrary(”ntdll.dll”) and then execute GetProcAddress(HMODULE, “NtQueryInformationProcess”) to receive a pointer to our required function.

HMODULE hmod;
FARPROC _NtQueryInformationProcess;
hmod = LoadLibrary(L"ntdll.dll");
_NtQueryInformationProcess = GetProcAddress(hmod, "NtQueryInformationProcess");

Note: The dynamic linking method is slightly different when using C++ due to declaration differences.

Once we have a function pointer to the NtQueryInformationProcess function, we can call the API. The function call takes five parameters, the first two of which are the most interesting to our anti-debugging efforts. The first parameter is a HANDLE to the target process that we wish to interrogate. Since we are trying to determine information about our own process, we will use a HANDLE that points to ourselves. By default, a HANDLE value of -1 will instruct the function to use the current process as the target. The second parameter is a value indicating what type of information is being requested from the target process. In the Microsoft MSDN documentation there are four documented values for this parameter ProcessBasicInformation (0), ProcessDebugPort (7), ProcessWow64Information (26), and ProcessImageFileName (27). There are other undocumented values that can be passed in, some of which allow for interesting anti-debugging techniques, however we will focus on the ProcessDebugPort (7) value. This value, when used as the second parameter in the NtQueryInformationProcess function will return a DWORD, returned in the address of the third parameter, indicating the DebugPort that is currently available for the process. If a non-zero value is returned, indicating that a DebugPort exists, we can be sure that a debugger is attached and act accordingly.

status = (_NtQueryInformationProcess) (-1, 0x07, &retVal, 4, NULL);

if (retVal != 0) {
    //Debugger Detected - Do Something Here
} else {
   //No Debugger Detected - Continue
}

The second anti-debugging method we will look at today also uses run-time dynamic linking of the Ntdll.dll library along with GetProcAddress() to gain access to the NtSetInformationThread function. This function’s primary purpose is to modify thread specific data for a targeted thread.

NTSTATUS NTAPI NtSetInformationThread(
    __in HANDLE ThreadHandle,
    __ in THREAD_INFORMATION_CLASS ThreadInformationClass,
    __in PVOID ThreadInformation
    __in ULONG ThreadInformationLength
)

For the anti-debugging use of this function we are again only interested in two particular parameters. The first parameter is an identifier to the thread we wish to target and the second parameter is the particular information we wish to modify on the target thread. To get a pointer to our current thread we will use a call to GetCurrentThread(). We will submit that as the first parameter and the enum value for ThreadHideFromDebugger, 0x11, as the second parameter. If a debugger is attached and we pass in 0x11 to NtSetInformationProcess, our process will immediately detach any attached debugger and terminate the process.

lib = LoadLibrary(L"ntdll.dll");
_NtSetInformationThread = GetProcAddress(lib, "NtSetInformationThread");

(_NtSetInformationThread) (GetCurrentThread(), 0x11, 0, 0);

MessageBox(NULL, L"Debugger Detached", L"Debugger Detached", MB_OK);

Many of the Microsoft API calls are intentionally not well documented to discourage their use/abuse. In this case we can make calls to two non-exported functions within the Ntdll.dll library to achieve our goals of detecting or detaching a debugger from our process. There are a number of other methods of API based anti-debugging, feel free to comment about them below.

Stay tuned for our next installment as we touch on process and thread block anti-debugging.

Anti-Debugging Series - Part II

Welcome back to the series on anti-debugging. Hopefully you have your debugger and development environment handy as we are about to dive into the first round of anti-debugging code. In the first post to this series we discussed six different types of anti-debugging techniques that are in common use today. To refresh, the classifications buckets that we chose to use are:

  • API Based Anti-Debugging
  • Exception Based Anti-Debugging
  • Process and Thread Block Anti-Debugging
  • Modified Code Anti-Debugging
  • Hardware and Register Based Anti-Debugging
  • Timing and Latency Anti-Debugging

Basic API Anti-Debugging

We’ll continue this series of posts by going into a bit more depth on the easiest of API based anti-debugging techniques. An application programming interface (API) is used to support requests made from other applications for resources or functionality within a target service or library. In our case we will be primarily focused on the Microsoft Windows operating system API. There are a number of calls built directly into the operating system API that make detection of a debugger possible. Minor differences in thread and process meta-data is present when processes are run within a debugger. These calls typically facilitate a process or thread examination technique in order to determine if the target thread has a debugger attached.

When learning about anti-debugging, a developer will typically first be introduced to the IsDebuggerPresent() function. This function analyzes the process block of a target process to determine if the processes is running under the context of a debugging session. We’ll save the details of how this actually works for a later article, however suffice it to say that the target process has a flag that will contain a non-zero value if the process is being debugged. This flag is queried and returned when IsDebuggerPresent() is called. A very basic debugging detection routine would be to call this function and execute different code paths based on the response.

Prototype: BOOL WINAPI IsDebuggerPresent(void); 

if (IsDebuggerPresent()) {
    //Debugger Detected - Do Something Here
} else {
    //No Debugger Detected - Continue
}

We could also use the API function CheckRemoteDebuggerPresent(). Contrary to first thought, this function does not target a process on a remote machine, nor does it even require that it target a process remote to itself. The call can use a parameter pointing to itself to determine if it is running inside of a debugger. In the example below we pass in a handle to our current process by calling the GetCurrentProcess() function along with a variable to hold the return value from the CheckRemoteDebuggerPresent() call.

Prototype: BOOL WINAPI CheckRemoteDebuggerPresent(__in HANDLE hProcess,
           __inout PBOOL pbDebuggerPresent);

BOOL pbIsPresent = FALSE;
CheckRemoteDebuggerPresent(GetCurrentProcess(), &pbIsPresent);
if (pbIsPresent) {
    //Debugger Detected - Do Something Here
} else {
    //No Debugger Detected - Continue
}

While these two methods are probably the easiest and most straightforward methods of anti-debugging, they are also the most likely to be understood by a person wishing to bypass them. We can mix it up a bit and use a call to OutputDebugString() instead. OutputDebugString() is typically used to output a string value to the debugging data stream. This string is then displayed in the debugger. Due to this fact, the function OutputDebugString() acts differently based on the existence of a debugger on the running process. If a debugger is attached to the process, the function will execute normally and no error state will be registered; however if there is no debugger attached, LastError will be set by the process letting us know that we are debugger free. To execute this method we set LastError to an arbitrary value of our choosing and then call OutputDebugString(). We then check GetLastError() and if our error code remains, we know we are debugger free.

Prototype: void WINAPI OutputDebugString(__in_opt  LPCTSTR lpOutputString);

DWORD Val = 123;
SetLastError(Val);
OutputDebugString(L"random");
if(GetLastError() == Val) {
    //Debugger Detected - Do Something Here
} else {
    //No Debugger Detected - Continue
}

These three methods are the basic starting point for a developer wishing to implement anti-debugging into their code base. The methods are so simple they could even be implemented as macros making a call quick and easy. Numerous other API based detection methods exist with a vast array of complexity. In the next post in this series we will discuss slightly more advanced API anti-debugging techniques that will make reverse engineering and debugging even more difficult.

Anti-Debugging Series - Part I

For those that don’t know, anti-debugging is the implementation of one or more techniques within computer code that hinders attempts at reverse engineering or debugging a target process. Typically this is achieved by detecting minute differences in memory, operating system, process information, latency, etc. that occur when a process is started in or attached to by a debugger compared to when it is not. Most research into anti-debugging has been conducted from the vantage point of a reverse engineer attempting to bypass the techniques that have been implemented. Limited data has been presented that demonstrates anti-debugging methods in a high level language that the average developer can understand. It is with this in mind that I hope to begin a series of posts that present some of the methods of anti-debugging in a clear, concise, and well documented fashion. The end goal of this series is to arm developers with the techniques and knowledge that will allow them to add a layer of protection to their software while simultaneous educating reverse engineers in some of the anti-debugging methods used by malware authors today.

Before we delve into the intricacies of individual methods of anti-debugging let’s use this post to define the classes of anti-debugging that we will be discussing. While other classes may exist, the definition of these classes is an attempt to include the majority of anti-debugging methods in use today. There is some overlap between classifications and we may have left out some methods due to limited exposure or effectiveness.

API Based Anti-Debugging
API based anti-debugging is the most straightforward and possibly the easiest to understand for a typical developer. Using both documented and undocumented API calls, these methods query process and system information to determine the existence or operation of a debugger. From single line calls such as IsDebuggerPresent() and CheckRemoteDebugger() to slightly more complex methods including debugger detaching and CloseHandle() checks. These methods are generally trivial to add to an existing code base and many can even be implemented in as few as two or three lines.

Exception Based Anti-Debugging
Exception based anti-debugging is slightly different than your basic API based techniques. Many times when a debugger is attached to a process, exceptions are trapped and handled by the debugger without regard to passing the exception back to the application for continued execution. Occasionally these exceptions can even crash or terminate a process when run under a debugger and be handled gracefully when running clean. It is these discrepancies that makes exception based anti-debugging techniques possible.

Process and Thread Block Anti-Debugging
Some of the API based anti-debugging methods use published functions to query information from within the process and thread blocks for our running code. Many API based detections can be subverted within a debugger by hooking the API call and returning values that indicate a clean process. One way around this subversion is to directly query the process and thread blocks, bypassing the API calls. Direct analysis of the process and thread blocks, while more complex, can lead to a more accurate and high assurance result.

Modified Code Anti-Debugging
One of the methods that a debugger uses to signal a breakpoint is to insert a break byte into the running code at the location that it wishes to stop execution. The process execution breaks when this value is seen, giving control to the debugger. When the program is resumed, the breakpoint value is removed and replaced with the original byte, the execution backed up one byte, and the program is resumed. Detection of software based breakpoints can be achieved by analyzing the process for modifications from the expected norm.

Hardware and Register Based Anti-Debugging
A second way that a debugger can break the execution of a process is by using a hardware breakpoint. A hardware breakpoint relies upon CPU registers to store the pertinent information and to detect when the target break addresses are seen on the bus. A break interrupt is triggered at the appropriate time based on these register values. Reading or modifying the hardware can allow for the detection of a debugger.

Timing and Latency Anti-Debugging
Finally timing and latency can be used as an effective anti-debugging method. When executing a program within a debugger, specifically when single stepping, a much larger latency occurs between execution of instructions. This latency can be detected and compared against a reasonable threshold to detect the existence of a debugger attached to our process.

Each of the classes of anti-debugging outlined above has merit when used individually to protect a process. While none of them can be assured to ever protect a program from a determined reverse engineer or debugger, implementation of these techniques (or many of them if appropriate) can sufficiently slow down the debugging process and hopefully make the attacker spend his time on other, easier, ventures. In the remainder of this series on anti-debugging we will review in depth some of the more interesting methods of each of the above classes. So bring along your debugger and your development environment and let the games begin.

BlackHat Recap

Another BlackHat has come and gone. As usual, it was a very busy week juggling customer meetings, recruiting, conference planning, vendor parties, and, oh yes, the actual BlackHat presentations. I had a fantastic time catching up with old friends and finally getting the opportunity to meet more of the Security Twits and others in the security community. I didn’t submit a talk this year, but nevertheless, fake Dan Kaminsky was still excited to see me.

My favorite talk, as expected, was the Sotirov/Dowd talk on How To Impress Girls With Browser Memory Protection Bypasses. The attack is a conceptually simple, yet completely reliable technique for exploiting vulnerabilities in web browsers. Of course, the media has sensationalized the impact of their findings, but ultimately, this is still significant as far as browser-based exploits are concerned (here is a more accurate report). It’s worth mentioning that part of the technique allowing them to load a .NET DLL at an arbitrary location under Vista was reliant on an implementation bug wherein the OS disables ASLR if the version in the .NET COR header was below a certain value. However, the address space spraying and stack spraying techniques are likely to be extended to other platforms utilizing similar memory protection mechanisms.

As for the girls? I can report first-hand that the ladies at TAO on Wednesday night were hanging on Alex’s every word. They were particularly impressed when he whipped out the laptop for a live demo. Unfortunately, none of the dozen iPhone owners in the immediate vicinity thought to snap a picture (too busy Twittering). Oh well.

I also enjoyed Hovav Shacham’s talk on return-oriented programming. Simply put, he described a generalization of the return-to-libc shellcode approach with the intent to demonstrate that one could achieve Turing-complete computation using “found code” in process images. By chaining together series of mini-computations ending in return (RET) instructions, it was possible to build higher-level programming constructs such as branches and loops. The nature of the x86 instruction set provides some flexibility because instructions are interpreted differently depending on how you align the instruction pointer (i.e. the old shellcode trick of searching the process image for any JMP EBX instruction and using that as your EIP). In RISC architectures such as SPARC, however, you don’t have that luxury; if your %pc isn’t aligned properly you get a bus error. So it was quite interesting to see that they were able to extend the concept to RISC. The practicality of the attack technique is limited by the fact that the shellcode is tuned to a particular binary image — if the shellcode was built using instructions extrapolated from glibc 2.3.5, it won’t work for a system running glibc 2.4.

I thought Scott Stender’s talk on Concurrency Attacks in Web Applications was interesting as well. In a nutshell, spewing thousands of simultaneous requests at web application transactions that are not thread-safe can create interesting problems. In the presentation, Scott ran his demo against a VM running on the attack machine. I found myself wondering how effective the same attack would be over the Internet — would it be significantly less reliable (or not at all)? Race conditions are generally easier to exploit locally than remotely due to more predictable execution conditions. Certainly this is an under-tested vulnerability class though.

One presentation I wasn’t able to attend but want to follow up on is Nate McFeters, John Heasman, and Rob Carter’s talk which discussed the GIFAR attack I’ve been hearing so much about lately. The gist is that you can create a file that is both a valid GIF and a valid JAR, then use some Java applet tricks to initiate HTTP requests on behalf of the victim.

Finally, the Pwnie Awards didn’t fail to disappoint. Drama ensued over the Most Overhyped award, but at least this year some of the winners showed up to claim their awards! Halvar rapping Symantec lyrics was also quite memorable.

All in all, a fun and informative week, but as usual, I was relieved to get the hell out of Vegas and head home on Friday morning.

P.S. For a much more entertaining BlackHat/Defcon Recap, read Jennifer Jabbusch’s account of the week’s events. It’s my favorite one so far!

Trip Report: PH-Neutral

I spent the weekend in Berlin attending a conference called PH-Neutral, run primarily by the Phenoelit crew. This was the first European security conference I’ve attended and I found it quite different from any North American security gathering I’ve been to, such as BlackHat, CanSecWest, SOURCE Boston, BlueHat, or RSA. Everything was far more casual and laid back, which is something I had heard about European conferences but hadn’t experienced until now (even EUSecWest is held in a club whereas CanSecWest is in a Marriott).

PH-Neutral Bridge

The event was held at Die Insel, on a tiny island a few kilometers outside of Berlin’s city center, near Treptower Park. The venue is mostly used for live music so basically it feels like a dark, somewhat dingy club (certainly the bathrooms are reminiscent of a club). The presentations were on the 3rd floor in a room that probably held about 60 people in close quarters; to handle overflow, a closed-circuit feed was being simulcast on the 4th floor, which was a bit less crowded and, more importantly, opened out onto a rooftop deck which meant better ventilation. The bottom floor led out to a Biergarten with tables, beach chairs, and a stage which was used for DJing. The layout was actually pretty efficient for allowing around 200 people to mill about and socialize/network while not having to stray too far from where the talks were presented.

Bridge to Die Insel

As far as the event itself, when I said “laid back” earlier, don’t interpret that to mean disorganized or watered down in any way. It was run with stereotypical German efficiency, from badging to presentations to the after-hours parties. The presentations were just as technical and relevant as any of the more “corporate” conferences. Unfortunately for me, I don’t know that many people in European security circles, and most of the ones I do know weren’t in attendance. Those I did meet, however, were impressively smart and well-versed. Nobody was trying to conduct business transactions or slip away for meetings, which is inevitably what happens when only technical folks are present!

PH-Neutral Registration

For me, a few talks stood out. Fukami and BeF’s talk on SWF and the Malware Tragedy discussed methods for automated static detection of malware in Flash movies. Much of it centered on heuristics related to inconsistencies in the file format or tag structure, abnormal concentrations of strings in the constant pool, or the existence of various obfuscation techniques. Ultimately, there are false positive issues to be addressed but that is just a fact of life with static analysis, and it will be an iterative process to refine those heuristics as the attack vectors evolve. I thought this talk was particularly timely given the increasing prevalence of Flash as a conduit for exploits/malware, such as the most recent Flash 0day that made the news (granted, this was an exploit against Flash itself, not just using Flash as a delivery mechanism, but close enough).

I also enjoyed pierre’s talk on counterintelligence, basically a mélange of wiretapping and other bugging devices discovered in the wild. War stories are always interesting, particularly when it comes to the realm of physical security. One of the x-ray images he showed of a bugged pen was identical to a pen that I own (minus the bugging device of course… I hope). The feel of the talk reminded me a bit of James Atkinson’s talk at SOURCE, “Telephone Defenses Against the Dark Arts” (video: Part 1 and Part 2), which also got rave reviews.

Mike Eddington’s presentation on the Peach 2 fuzzing framework was also quite interesting. Peach 2 was released several months back but I haven’t really been paying much attention to it or any other fuzzing tool for some time. In fact the last time I really had to implement a protocol fuzzer, I was using SPIKE 2.9, so that gives you some indication of how long it’s been. Peach 2 includes some powerful built-in capabilities such as node relationships (e.g. field 1 represents the length of field 2; field 10 is a CRC-32 of fields 1 through 9), data transforms (those with battle scars from ASN.1 will be happy), state machines (packets 1 and 2 have to be normal in order to fuzz packet 3), monitoring agents (detecting when a crash happens and under what conditions), and much more. I am itching to go fuzz something now just so I can tinker with Peach.

All in all, it was a good trip and I enjoyed the opportunity to see how things are done across the pond, and to do a little sightseeing in a historic and beautiful city.

Responsible-ish Disclosure

Yesterday, Dave Lewis over at LiquidMatrix Security Digest cried foul at Core Security for releasing too much detail about a recent DoS vulnerability they had discovered. His specific gripe was that they provided an IDA Pro excerpt that showed where the vulnerability was triggered. The excerpt is short, so I’ll even copy/paste it here:

.text:00405C1B mov  esi, [ebp+dwLen]  ; Our value from packet
...
.text:00405C20 push edi
.text:00405C21 test esi, esi          ; Check value != 0
...
.text:00405C31 push esi               ; Alloc with our length
.text:00405C32 mov  [ebp+var_4], 0
.text:00405C39 call operator new(uint); Big values return NULL
.text:00405C3E mov  ecx, esi          ; Memcpy with our length
.text:00405C40 mov  esi, [ebp+pDestionationAddr]
.text:00405C43 mov  [ebx+4], eax      ; new result is used as dest
.text:00405C46 mov  edi, eax          ; address without checks.
.text:00405C48 mov  eax, ecx
.text:00405C4A add  esp, 4
.text:00405C4D shr  ecx, 2
.text:00405C50 rep  movsd             ; AV due to invalid
.text:00405C52 mov  ecx, eax          ; destination pointer.
.text:00405C54 and  ecx, 3

Dave asserts that publishing 16 commented assembly instructions makes this disclosure irresponsible. But look at the code — it’s completely generic, just a textbook example of what it looks like when you forget to check a return value after calling operator new. Sure, Core gives you the exact offsets into the executable, but so what? If I have the binary, then it’s not going to be too hard to find the vulnerability anyway. It’s not like Core is giving away a proof-of-concept exploit that generates the malformed registration packet required to trigger the DoS. What’s more, they provide a detailed timeline going back to January 30th of this year describing exactly how the disclosure process with the vendor transpired. This looks extremely responsible to me; I just can’t understand what is “not cool” here.

There’s another interesting angle to this, completely unrelated to Core’s disclosure process. The vulnerability itself is described in the advisory as follows:

Un-authenticated client programs connecting to the service can send a malformed packet that causes a memory allocation operation (a call to new() operator) to fail returning a NULL pointer. Due to a lack of error-checking for the result of the memory allocation operation, the program later tries to use the pointer as a destination for memory copy operation, triggering an access violation error and terminating the service.

This may bring to mind some recent discussions on whether callers of memory allocation functions should check the return value prior to use. To summarize, one camp says “caller should check”, the other camp says “callee should exit on allocation failure.” This is a gross oversimplification and if you want more detailed arguments, read the other blog posts that I linked to. In this case, if the “exit on failure” approach were taken, the DoS scenario might still happen, whereas if the caller were checking, the error could be handled more gracefully. More fuel for the debate!

BlackHat 2007 Materials

Finally getting around to posting our materials from the talk that Chris Wysopal and I gave at BlackHat this year entitled “Static Detection of Application Backdoors.” Here are the slide deck and the accompanying whitepaper:

Also, as a proof-of-concept, we had demonstrated using IDA Pro’s scripting framework to detect one of the backdoor examples that we discussed — suspicious cryptographic API calls. Specifically, it flags calls to known encryption, decryption, and/or key management functions where a constant value is passed to a specific argument position. This can help identify situations such as an application encrypting data with a hard-coded key. We had numerous requests to post the code, so here it is:

Cryptoconst IDC script (requires IDA Pro)

Veracode’s binary analysis technology uses similar (but more sophisticated) techniques. We build our own intermediate representation of the binary’s data flows, control flows, and range propagation which is not based on IDA Pro. We then scan that representation for backdoors in ways similar to the cryptoconst script. However, at BlackHat you’re not allowed to promote your own products/services, so it wasn’t appropriate for us to use it for demonstration purposes.

Backdoor Detection in the News

There has been some talk in the press lately about backdoors due to the recent court case where it was disclosed that federal agents planted a keystroke logger on a suspect’s computer using a trojan program. Many of the articles don’t report on the court case but raise the question as Declan McCullagh titles his article, “Will security firms detect police spyware?

You can see the security cat and mouse game playing out between the police and suspected criminals although the roles here are reversed. The criminals are trying to secure their communications and the police are trying to break it to collect evidence. At first the police could just tap the data as it moved from sender to receiver. In response criminals started using strong end to end encryption. To get around that the police compromised the endpoint system with a backdoor to get at the clear text of the messages or passwords to log into encrypted servers. The criminal’s obvious response to that is to secure his system and try and detect any backdoor code.

Real detection of backdoor code is a challenging computer security problem to solve. This article will discuss different methods of detection and the different classes of backdoors.

Spyware, trojan keystroke loggers, or remote access trojans are what I call system backdoors, since they compromise the integrity of the whole computer system. These are typically in programs that you don’t want on your system. They are often installed via social engineering, a vulnerability, or a combination of both.

There is a different, more subtle and insidious backdoor which I call an application backdoor. This is backdoor code that is planted in an application that you do want on your system such as Wordpress, Borland Interbase, or tcpdump. All of those programs had versions that contained backdoors at one point. An application backdoor allows the attacker to bypass the designed authentication or authorization functions of the application and access its data and transactions. Sometimes an application backdoor is also a system backdoor if it allows functionality such as system commands and the application is running in an environment where the OS doesn’t prevent this.

For both system and application backdoors, once you know the program contains a backdoor you can make a signature for the program and detect instances of the program by computing a signature and looking it up in a signature database. This is how many traditional AV products find backdoor programs. The backdoor is typically detected by someone noticing a program that wasn’t supposed to be running on their computer. Then after inspection they also realize it is performing behavior on their system that they don’t want and report it to an AV vendor.

This approach doesn’t work well for custom or low population backdoors such as those used by sophisticated attackers or the police. It also doesn’t work well for application backdoors which are typically planted in the source code of the application or in the binary at the legitimate distribution site. Remember that applications backdoors are in programs that are supposed to be on the system so they don’t stand out. We need better was to detect backdoors than signatures.

Another way to detect backdoors is by looking for backdoor behavior on the system. Is a program listening on the network that isn’t supposed to? Is a program hooking into system level calls to gather keystrokes? Is a program hooking into system level calls to hide its behavior from the system log and administration tools. This is a big step up from signatures because it can detect a backdoor that hasn’t been seen before.

There are limitations to the behavior detection approach. If a backdoor program has done a good job of hiding its behavior from the system you can’t detect it. If a program is supposed to be listening on the network, detecting that doesn’t help. Some behavior may occur on a timer so the behavior detection would have to catch it in the act perhaps within very small intervals of time. Behavior doesn’t do a very good job at application backdoors at all. How will behavior find a special password that bypasses normal authentication or special processing when a certain client IP address is used?

A better solution to finding backdoors that overcomes many of the behavior approach’s limitations is binary static analysis. Binary static analysis can look at all of the functionality of the program without having to wait for it to get into a particular state which is the bane of dynamic (behavioral) analysis.

Binary static analysis is adept at seeing “baked in” static passwords, keys, or IP addresses. It can detect if there are encrypted or self-modifying blocks of code which may mean someone is hiding something. It can detect functionality such as listing on the network or shimming system calls. It can also do this from a trusted clean computer whereas the behavioral analysis needs to run on the same computer that the program being analyzed is executing.

Veracode’s binary analysis technology has scans that look for backdoors in executables. Chris Eng and I are giving a presentation titled, “Static Detection of Application Backdoors” at Black Hat in Las Vegas on August 2. We will cover detection of 4 classes of application backdoors that have:

  1. Special credentials
  2. Hidden functionality
  3. Unintended network activity
  4. Manipulation of security critical parameters

We will be giving a demo of proof of concept detection using IDA Pro and even screening a famous clip from a movie concerning backdoors. I’ll give you a hint, “Backdoors are not secrets!”

A Security Issue with C++ Object Layouts

Type safety is a feature of numerous modern programming languages. C++ is not strict about type safety, and as a result, vulnerabilities may appear in programs in unexpected ways. Here’s an example I recently discovered.

Consider this structure:

typedef struct _NOTIFYICONDATAA {
    DWORD cbSize;
    HWND hWnd;
    UINT uID;
    UINT uFlags;
    UINT uCallbackMessage;
    HICON hIcon;

#if (_WIN32_IE < 0x0500)
    CHAR szTip[64];
#else
    CHAR szTip[128];
#endif

#if (_WIN32_IE >= 0x0500)
    DWORD dwState;
    DWORD dwStateMask;
    CHAR szInfo[256];
    union {
        UINT uTimeout;
        UINT uVersion;
    } DUMMYUNIONNAME;
    CHAR szInfoTitle[64];
    DWORD dwInfoFlags;
#endif

#if (_WIN32_IE >= 0x600)
    GUID guidItem;
#endif
} NOTIFYICONDATAA, *PNOTIFYICONDATAA;

Note all the _WIN32_IE preprocessor macros. Problem scenario is this: In one file, you create NOTIFYICONDATAA structure, fill in cbSize with sizeof(NOTIFYICONDATAA), and pass it to another routine in another translation unit/source file. In one source file, you have _WIN32_IE undefined, so it defaults to the latest version for your Platform SDK. In the other source file you #define _WIN32_IE to 0x0400 for backward compatibility purposes. Note that this creates a discrepancy in the structural layout, but if you only use the IE4 features of that structure, then you might think you’re okay.

This is all too common. We’ve analyzed a lot of binaries here over at Veracode and found that it is relatively common to have two versions of the same structure compiled with different #define settings and they end up with different lengths, easily leading to overflow conditions that are non-obvious to the casual analysis. In fact, if you only look at one source file at a time, you’ll always miss this case, because you need to look interprocedurally between the translation units to note that the types are different between the point of allocation and the point of use.

This underscores a fundamental issue of concern with C++ — that a type defined in one translation unit is considered equivalent to another type of the same name in another translation unit as long as their names are the same, regardless of their layout. The linker cares when comparing decorated/manged names, but nothing else does. This is usually mitigated by declaring your classes/structures in a header file that is uniformly #included everywhere. However, in the scenario outlined above, it is relatively easy to have things go wrong without hearing a peep from your compiler.

The security ramifications of this issue are clear, but we haven’t really been looking for them. I propose that for future correspondence, we refer to this issue as a ‘non-uniform layout’ bug. Privacy concerns prevent me from posting the examples that I have of this problem, but if anyone out there has good real-life examples of this issue they’d like to publish, I’d love to see them.

Next Page »
 

Powered by WordPress