root/capture-mod/trunk/CaptureClient.cpp

Revision 1766, 15.4 kB (checked in by xkovah, 3 months ago)

Added handlers to the soap code for the other event types. Now they just need to shove the data into ns_*Event_t structs in individual vectors, and it will be ready for simple send back to a soap client like Manager

Line 
1 #include <iostream>
2 #include <boost/signal.hpp>
3 #include <boost/bind.hpp>
4 #include "Server.h"
5 #include "Visitor.h"
6 #include "Analyzer.h"
7 #include "ProcessManager.h"
8 #include "shellapi.h"
9 #include "CaptureSoapServer.h"
10 using namespace std;
11
12 /* Initialise static variables. These are all singletons */
13 /* Process manager which keeps track of opened processes and their paths */
14 bool ProcessManager::instanceCreated = false;
15 ProcessManager* ProcessManager::processManager = NULL;
16
17 /* Objects listen for internal events from this controller */
18 bool EventController::instanceCreated = false;
19 EventController* EventController::pEventController = NULL;
20
21 /* Logging capabilities that either writes to a file or console */
22 bool Logger::instanceCreated = false;
23 Logger* Logger::logger = NULL;
24
25 /* Global options available to all objects */
26 bool OptionsManager::instanceCreated = false;
27 OptionsManager* OptionsManager::optionsManager = NULL;
28
29 class CaptureClient : public Runnable
30 {
31 public:
32     CaptureClient()
33     {
34         /* Capture needs the SeDriverLoadPrivilege and SeDebugPrivilege to correctly run.
35            If it doesn't acquire these privileges it exits. DebugPrivilege is used in the
36            ProcessManager to open handles to existing process. DriverLoadPrivilege allows
37            Capture to load the kernel drivers. */
38         if(!obtainDebugPrivilege() || !obtainDriverLoadPrivilege())
39         {   
40             printf("\n\nCould not acquire privileges. Make sure you are running Capture with Administrator rights\n");
41             exit(1);
42         }
43
44         /* Create the log directories */
45         CreateDirectory(L"logs",NULL);
46
47         /* If logging to a file has been specified open the file for write access */
48         if(OptionsManager::getInstance()->getOption(L"log-system-events-file") != L"")
49             Logger::getInstance()->openLogFile(OptionsManager::getInstance()->getOption(L"log-system-events-file"));
50
51         hStopRunning = CreateEvent(NULL, FALSE, FALSE, NULL);
52
53         wstring serverIp = OptionsManager::getInstance()->getOption(L"server");
54         server = new Server(serverIp, 7070);
55         server->onConnectionStatusChanged(boost::bind(&CaptureClient::onConnectionStatusChanged, this, _1));
56
57         /* Listen for events from the EventController. These are messages passed from the server */
58         onServerConnectEventConnection = EventController::getInstance()->connect_onServerEvent(L"connect", boost::bind(&CaptureClient::onServerConnectEvent, this, _1));
59         onServerPingEventConnection = EventController::getInstance()->connect_onServerEvent(L"ping", boost::bind(&CaptureClient::onServerPingEvent, this, _1));
60
61         /* Start running the Capture Client */
62         visitor = new Visitor();
63         //Moved these out of Analyzer, so that the soap server could access the same ones.
64         ProcessMonitor * p = new ProcessMonitor();
65         RegistryMonitor * r = new RegistryMonitor();
66         FileMonitor * f = new FileMonitor();
67         //Set up the standalone SOAP server
68         soapSrv = new CaptureSoapServer(visitor, r, f, p);
69         analyzer = new Analyzer(visitor, server, r, f, p);
70         Thread* captureClientThread = new Thread(this);
71         captureClientThread->start("CaptureClient");
72     }
73    
74     ~CaptureClient()
75     {
76         onServerConnectEventConnection.disconnect();
77         onServerPingEventConnection.disconnect();
78         CloseHandle(hStopRunning);
79         delete analyzer;
80         delete visitor;
81         delete server;
82         delete soapSrv;
83        
84         Logger::getInstance()->closeLogFile();
85         delete Logger::getInstance();
86         delete ProcessManager::getInstance();
87         delete OptionsManager::getInstance();
88         delete EventController::getInstance();
89     }
90
91     void run()
92     {       
93         if((OptionsManager::getInstance()->getOption(L"server") == L"") ||
94             server->connectToServer())
95         {
96             /* If Capture is being run in standalone mode start the analyzer now */
97             /* Send file test */
98             printf("---------------------------------------------------------\n");
99             if((OptionsManager::getInstance()->getOption(L"server") == L""))
100             {
101                 analyzer->start();
102             }
103             /* Wait till a user presses a key then exit */
104             /*Xeno - changed to make it only quit with a q*/
105             DWORD c;
106             while(1){
107                 c = getchar();
108                 if(c == 'q'){
109                     break;
110                 }
111                 else{
112                     Sleep(99999999);
113                 }
114             }
115             if((OptionsManager::getInstance()->getOption(L"server") == L""))
116             {
117                 analyzer->stop();
118             }
119         }
120         SetEvent(hStopRunning);
121     }
122
123     /* Event passed when the state of the connection between the server is changed.
124        When capture becomes disconnected from the server the client exits */
125     void onConnectionStatusChanged(bool connectionStatus)
126     {
127         printf("Got connect status changed\n");
128         if(!connectionStatus)
129         {
130             if(OptionsManager::getInstance()->getOption(L"server") != L"")
131                 printf("Disconnected from server: Exiting client\n");
132             SetEvent(hStopRunning);
133         }
134     }
135
136     /* Responds to a connect event from the server. It sends the virtual machine
137        server id and virtual machine id this client is hosted on back to the server */
138     void onServerConnectEvent(Element* pElement)
139     {
140         printf("Got connect event\n");
141         if(pElement->name == L"connect")
142         {
143             Attribute att;
144             queue<Attribute> vAttributes;
145             att.name = L"vm-server-id";
146             att.value = OptionsManager::getInstance()->getOption(L"vm-server-id");
147             vAttributes.push(att);
148             att.name = L"vm-id";
149             att.value = OptionsManager::getInstance()->getOption(L"vm-id");
150             vAttributes.push(att);
151             server->sendXML(L"connect", &vAttributes);
152         }
153     }
154
155     /* Sends a pong message back to the server when a ping is received */
156     void onServerPingEvent(Element* pElement)
157     {
158         if(pElement->name == L"ping")
159         {
160             queue<Attribute> vAttributes;
161             server->sendXML(L"pong", &vAttributes);
162         }
163     }
164
165     /* Get the driver load privilege so that the kernel drivers can be loaded */
166     bool obtainDriverLoadPrivilege()
167     {
168         HANDLE hToken;
169         if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,&hToken))
170         {
171             TOKEN_PRIVILEGES tp;
172             LUID luid;
173             LPCTSTR lpszPrivilege = L"SeLoadDriverPrivilege";
174
175             if ( !LookupPrivilegeValue(
176                     NULL,            // lookup privilege on local system
177                     lpszPrivilege,   // privilege to lookup
178                     &luid ) )        // receives LUID of privilege
179             {
180                 printf("LookupPrivilegeValue error: %u\n", GetLastError() );
181                 return false;
182             }
183
184             tp.PrivilegeCount = 1;
185             tp.Privileges[0].Luid = luid;
186             tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
187
188             // Enable the privilege or disable all privileges.
189             if ( !AdjustTokenPrivileges(
190                 hToken,
191                 FALSE,
192                 &tp,
193                 sizeof(TOKEN_PRIVILEGES),
194                 (PTOKEN_PRIVILEGES) NULL,
195                 (PDWORD) NULL) )
196             {
197               printf("AdjustTokenPrivileges error: %u\n", GetLastError() );
198               return false;
199             }
200
201             if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
202             {   
203                 printf("The token does not have the specified privilege. \n");
204                 return false;
205             }
206         }
207         CloseHandle(hToken);
208         return true;
209
210     }
211
212     /* Get the debug privilege so that we can get process information for all process
213        except for the system process */
214     bool obtainDebugPrivilege()
215     {
216         HANDLE hToken;
217         if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,&hToken))
218         {
219             TOKEN_PRIVILEGES tp;
220             LUID luid;
221             LPCTSTR lpszPrivilege = L"SeDebugPrivilege";
222
223             if ( !LookupPrivilegeValue(
224                     NULL,            // lookup privilege on local system
225                     lpszPrivilege,   // privilege to lookup
226                     &luid ) )        // receives LUID of privilege
227             {
228                 printf("LookupPrivilegeValue error: %u\n", GetLastError() );
229                 return false;
230             }
231
232             tp.PrivilegeCount = 1;
233             tp.Privileges[0].Luid = luid;
234             tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
235
236             // Enable the privilege or disable all privileges.
237             if ( !AdjustTokenPrivileges(
238                 hToken,
239                 FALSE,
240                 &tp,
241                 sizeof(TOKEN_PRIVILEGES),
242                 (PTOKEN_PRIVILEGES) NULL,
243                 (PDWORD) NULL) )
244             {
245               printf("AdjustTokenPrivileges error: %u\n", GetLastError() );
246               return false;
247             }
248
249             if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
250             {   
251                 printf("The token does not have the specified privilege. \n");
252                 return false;
253             }
254         }
255         CloseHandle(hToken);
256         return true;
257     }
258
259     HANDLE hStopRunning;
260 private:
261     Server* server;
262     Visitor* visitor;
263     Analyzer* analyzer;
264     CaptureSoapServer * soapSrv;
265
266     boost::signals::connection onServerConnectEventConnection;
267     boost::signals::connection onServerPingEventConnection;
268    
269 };
270
271 int _tmain(int argc, WCHAR* argv[])
272 {
273     /* Set the current directory to the where the CaptureClient.exe is found */
274     /* This is a bug fix for the VIX library as the runProgramInGuest function
275        opens the client from within c:\windows\system32 so nothing will load
276        properly during execution */
277     wchar_t* szFullPath = new wchar_t[4096];
278     GetFullPathName(argv[0], 4096, szFullPath, NULL);
279     DebugPrint(L"Capture: Argv[0] -> %s\n", argv[0]);
280     DebugPrint(L"Capture: GetFullPathName -> %ls\n", szFullPath);
281     wstring dir = szFullPath;
282     dir = dir.substr(0, dir.find_last_of(L"\\")+1);
283     SetCurrentDirectory(dir.c_str());
284     DebugPrint(L"Capture: Dir -> %ls\n", dir.c_str());
285     GetCurrentDirectory(4096, szFullPath);
286
287     DebugPrint(L"Capture: Current directory set -> %ls\n", szFullPath);
288    
289     /* Delete the log directory */
290     /*
291     GetFullPathName(L"logs", 4096, szFullPath, NULL);
292     SHFILEOPSTRUCT deleteLogDirectory;
293     deleteLogDirectory.wFunc = FO_DELETE;
294     deleteLogDirectory.pFrom = szFullPath;
295     deleteLogDirectory.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
296     SHFileOperation(&deleteLogDirectory);
297 */
298     delete [] szFullPath;
299    
300     wstring serverIp = L"";
301     wstring vmServerId = L"";
302     wstring vmId = L"";
303     wstring logSystemEventsFile = L"";
304     wstring collectModifiedFiles = L"false";
305     wstring captureNetworkPackets = L"false";
306
307     for(int i = 1; i < argc; i++)
308     {
309         wstring option = argv[i];
310         if(option == L"--help" || option == L"-h") {
311             printf("\nCapture client is a high interaction client honeypot which using event monitoring can monitor the state of the system it is being run on. ");
312             printf("Capture can monitor processes, files, and the registry at the moment and classifies an event as being malicious by checking exclusion lists. ");
313             printf("\nThese exclusion lists are regular expressions which can either allow or deny a particular event from a process in the system. Because of the fact ");
314             printf("that it uses regular expressions, creating these list can be very simple but can also provide very fine grained exclusion if needed.\nThe client ");
315             printf("can also copy all modified and deleted files to a temporary directory as well as capture all incoming and outgoing packets on the network adapters ");
316             printf("on the system.\nThe client can be run in the following two modes:\n");
317             printf("\n\nClient<->Server\n\n");
318             printf("The client connects to a central Capture server where the client can be sent urls to visit. These urls can contain other information which tell ");
319             printf("the client which program to use, for example www.google.com could be visited with either Internet Explorer or Mozilla Firefox and how long to visit the ");
320             printf("url. While the url is being visited the state of the system is monitored and if anything malicious occurs during the visitation period the event ");
321             printf("is passed back to the server. In this mode the client is run inside of a virtual machine so that when a malicious event occurs the server can revert ");
322             printf("the virtual machine to a clean state\n\n");
323             printf("To use this mode the options -s, -a, -b must be set so the client knows how to connect and authenticate with the server. To configure the ");
324             printf("programs that are available to visit a url edit the clients.conf file. If -cn are set then the log directory will be sent to the server once ");
325             printf("a malicious url is visited. For this to work tar.exe and gzip.exe must be included in the Capture Client folder.\n");
326             printf("\n\nStandalone\n\n");
327             printf("In this mode the client runs in the background of a system and monitors the state of it. Rather than being controlled by a remote server, in standalone mode ");
328             printf("the user has control over the system. Malicious events can either be stored in a file or outputted to stdout.");
329             printf("\n\nUsage: CaptureClient.exe [-chn] [-s server address -a vm server id -b vm id] [-l file]\n");
330             printf("\n  -h\t\tPrint this help message");
331             printf("\n  -s address\tAddress of the server the client connects up to. NOTE -a & -b\n\t\tmust be defined when using this option");
332             printf("\n  -a server id\tUnique id of the virtual machine server that hosts the client");
333             printf("\n  -b vm id\tUnique id of the virtual machine that this client is run on");
334             printf("\n  -l file\tOutput system events to a file rather than stdout\n");
335             printf("\n  -c\t\tCopy files into the log directory when they are modified or\n\t\tdeleted");
336             printf("\n  -n\t\tCapture all incoming and outgoing network packets from the\n\t\tnetwork adapters on the system and store them in .pcap files in\n\t\tthe log directory");
337             printf("\n\nIf -s is not set the client will operate in standalone mode");
338             exit(1);
339         } else if(option == L"-s") {
340             if((i+1 < argc) && (argv[i+1][0] != '-')) {
341                 serverIp = argv[++i];
342                 printf("Option: Connect to server: %ls\n", serverIp.c_str());
343             }
344         } else if(option == L"-a") {
345             if((i+1 < argc) && (argv[i+1][0] != '-')) {
346                 vmServerId = argv[++i];
347             }
348         } else if(option == L"-b") {
349             if((i+1 < argc) && (argv[i+1][0] != '-')) {
350                 vmId = argv[++i];
351             }
352         } else if(option == L"-l") {
353             if((i+1 < argc) && (argv[i+1][0] != '-')) {         
354                 logSystemEventsFile = argv[++i];
355                 printf("Option: Logging system events to %ls\n", logSystemEventsFile.c_str());
356             }
357         } else {
358             if(argv[i][0] == '-')
359             {
360                 for(UINT k = 1; k < option.length(); k++)
361                 {
362                     if(argv[i][k] == 'c') {
363                         printf("Option: Collecting modified files\n");
364                         collectModifiedFiles = L"true";
365                     } else if(argv[i][k] == 'n') {
366                         HMODULE hModWinPcap = LoadLibrary(L"wpcap.dll");
367                         if(hModWinPcap == NULL)
368                         {
369                             printf("NetworkPacketDumper: ERROR - wpcap.dll not found. Check that winpcap is installed on this system\n");
370                             printf("Cannot use -n option if winpcap is not installed ... exiting\n");
371                             exit(1);
372                         } else {
373                             printf("Option: Capturing network packets\n");
374                             captureNetworkPackets = L"true";
375                             FreeLibrary(hModWinPcap);
376                         }
377                     }
378                 }
379             }
380         }
381     }
382
383     OptionsManager::getInstance()->addOption(L"server", serverIp);
384     OptionsManager::getInstance()->addOption(L"vm-server-id", vmServerId);
385     OptionsManager::getInstance()->addOption(L"vm-id", vmId);
386     OptionsManager::getInstance()->addOption(L"log-system-events-file", logSystemEventsFile);
387     OptionsManager::getInstance()->addOption(L"collect-modified-files", collectModifiedFiles);
388     OptionsManager::getInstance()->addOption(L"capture-network-packets", captureNetworkPackets);
389
390     if(collectModifiedFiles == L"true")
391     {
392         if(serverIp != L"")
393         {
394             WIN32_FIND_DATA FindFileData;
395             HANDLE hFind;
396
397             hFind = FindFirstFile(L"7za.exe",&FindFileData);
398             if(hFind == INVALID_HANDLE_VALUE)
399             {
400                 printf("Analyzer: ERROR - Could not find 7za.exe (http://www.7-zip.org/) - Not collecting modified files\n");
401                 printf("Cannot use -c option if 7za.exe is not in the current directory ... exiting\n");
402                 exit(1);
403             }
404         }
405     }
406
407     CaptureClient* cp = new CaptureClient();
408     WaitForSingleObject(cp->hStopRunning, INFINITE);
409     delete cp;
410     return 0;
411 }
Note: See TracBrowser for help on using the browser.