Wednesday, 13 May 2009

CreateProcess vulnerabilities

A hacker may try to compromise a system for various reasons. He may simply be trying to access protected data or, more ambitiously, trying to control the system remotely to use it as a bot. The first step to taking control of a system is to get his code running on the targeted system with sufficient privileges. The simplest method a hacker can use to run his code on the target machine is by exploiting the CreateProces API. This article will focus on the various quirks of the CreateProcess API that makes it so interesting to a hacker and discuss ways to make sure that his interest remains just an interest.
A hacker will try to exploit any calls to CreateProcess made by the vulnerable application to make the API launch his code instead of the applications intended code. There are numerous ways in which he can do that and the approach he chooses will depend on how the application is calling the CreateProcess API. The signature for this API is:

BOOL WINAPI CreateProcess(
__in_opt LPCTSTR lpApplicationName,
__inout_opt LPTSTR lpCommandLine,
__in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes,
__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in BOOL bInheritHandles,
__in DWORD dwCreationFlags,
__in_opt LPVOID lpEnvironment,
__in_opt LPCTSTR lpCurrentDirectory,
__in LPSTARTUPINFO lpStartupInfo,
__out LPPROCESS_INFORMATION lpProcessInformation
);

All arguments are explained in detail on MSDN. I am just going to concentrate on the ways of using the API that render an application vulnerable.
The preferred method of using CreateProcess is to set lpApplicationName to the full path of the application to run and fill lpCommandLine with any optional arguments to the application. However, this method is not strictly enforced allowing developers to set any one of the two arguments to NULL.
In the first case, a developer may set lpApplicationName to NULL and set lpCommandLine to the string used to launch the application from the command prompt. In this case, if the absolute path to the application is not specified, the system attempts to look for it in a few known locations. This gives rise to a problem known as Search Path Injection. The order in which the system looks into the known folders is:
  1. The current directory of the application
  2. The directory of the parent process
  3. The Windows System directory
  4. The Windows directory
  5. All the other directories on the search path
For example, if lpCommandLine is set to:
         program -a -b

The system tries to locate the executable "program" in the above mentioned folders in that order. If the attacker manages to place another executable named "program" somewhere higher in the search path, that executable will be launched. The mitigation for this attack is to always use the full canonical (unambiguous) path to the application no matter whether it is being used as lpApplicationName or included in lpCommandLine.
Using the full path may however, lead to a second type of problem. This problem is caused by the way the system parses lpCommandLine string when lpApplicationName is NULL. The first white space–delimited token in the lpCommandLine string is taken to be the module name. If the token does not contain an extension, a ".exe" is appended to it. For example, consider the string "c:\program files\sub dir\program name". This string can be interpreted in a number of ways. The system tries to interpret the possibilities in the following order:

c:\program.exe files\sub dir\program name
c:\program files\sub.exe dir\program name
c:\program files\sub dir\program.exe name
c:\program files\sub dir\program name.exe
If the vulnerable application tries to launch an application located in some folder inside "C:\Program Files", all the hacker has to do is to name his executable program.exe and place it in "C:\".
The mitigation for this problem is to use quoted strings to indicate where the file name ends and the arguments begin; otherwise, the file name is ambiguous. Hence in the above example we would pass the literal string "\"C:\\program files\\sub dir\\program name\"" as lpCommandLine. Note however, the above mentioned problem does not arise if lpApplicationName is non-NULL.

To summarize, to avoid problems always use the full path of an application, do not use a NULL lpApplicationName and if you do, always quote the application path in lpCommandLine.

Friday, 3 April 2009

Format string vulnerabilities

I was thinking about what to write about in my next post when C (my friend "C", not the programming language) happened to read the previous post. He asked me why I had used printf("%s\n", "Hello World") to print the string instead of the simpler printf("Hello World\n"), does it make any difference which version you use? The answer to the first question is "old habit" and the answer to the second is "not in this case". The second answer is the cause of the second answer and that will be the topic of discussion in this post.

printf belongs to the class of functions that take a variable number of arguments. It is of the form printf(fmt_str, ...). The first argument fmt_str is called the control or format string. This string contains specifications for the number and type of the following arguments. printf scans the string from left to right printing on the output device any characters it encounters except when it reaches a '%' character. The '%' character is a signal that what follows it is a specification for how the next variable in the list of variables should be printed. printf uses this information to evaluate the corresponding argument and prints the result after suitable formatting before moving on to the next character. While all that is well and good, the problem arises because the varargs mechanism that allows printf to accept arbitrary numbers of arguments trusts the format string to correctly specify the number of arguments and their types. It does not do any type checking itself. This shortcoming can be used by malicious users to print data from the stack or other locations and even to write arbitray data to arbitrary locations. A combination of such operations can by used to overwrite the address of a legitimate function or the return address on the stack with the address of some malicious piece of code.

Format string vulnerabilities usually appear when printing unfiltered user supplied strings. For example, if char* buffer contains a user supplied string, using printf(buffer) rather than printf("%s", buffer) to print the string may cause a vulnerability. printf(buffer) treats buffer as a format string and parses any format specifiers it may contain where as printf("%s", buffer) treats buffer as a literal string.

To return to C's original question, printf("Hello World\n") is as safe as printf("%s", "Hello World") because it is a literal string which is known beforehand. But, I have become so used to using printf("%s", string) to print any string that I automatically go for this form irrespective of the source of the data to be printed.

Thursday, 1 January 2009

ITtionary

A list of terms and concepts that every developer should know but most don't.

Attack Vector:
An attack vector is a path or means by which a hacker (or cracker) can gain access to a computer or network server in order to deliver a payload or malicious outcome.

HeisenBug:
A HeisenBug is a bug whose presence is affected by act of observing it. For example, a bug which disappears in debug mode.

Thursday, 4 December 2008

Hello World

I have decided to start this blog with a "Hello World" post in keeping with the tradition of introducing a new language to a reader with a "Hello World" program. So here it is in my favourite language:

#include <stdio.h>

int main()
{
    printf("%s\n", "Hello World");
    return 0;
}