1 /********************************************************************************
2  *                              Nepenthes
3  *                        - finest collection -
4  *
5  *
6  *
7  * Copyright (C) 2005  Paul Baecher & Markus Koetter
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
22  *
23  *
24  *             contact nepenthesdev@users.sourceforge.net
25  *
26  *******************************************************************************/
27 
28  /* $Id: CTRLDialogue.cpp 1493 2007-12-13 21:29:01Z rui $ */
29 
30 #include <sys/types.h>
31 #include <sys/param.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35 
36 #include "CTRLDialogue.hpp"
37 #include "FILEDialogue.hpp"
38 
39 #include "FTPContext.hpp"
40 
41 #include "download-ftp.hpp"
42 
43 #include "Message.hpp"
44 #include "Nepenthes.hpp"
45 #include "LogManager.hpp"
46 
47 #include "Download.hpp"
48 #include "Download.cpp"
49 #include "DownloadUrl.hpp"
50 #include "DownloadUrl.cpp"
51 
52 #include "DownloadBuffer.hpp"
53 #include "DownloadBuffer.cpp"
54 
55 
56 
57 #include "Buffer.hpp"
58 #include "Buffer.cpp"
59 
60 #ifdef STDTAGS
61 #undef STDTAGS
62 #endif
63 #define STDTAGS l_dl | l_dia | l_hlr
64 
65 using namespace nepenthes;
66 
67 /**
68  * Dialogue::Dialogue(Socket *)
69  * construktor for the CTRLDialogue, creates a new CTRLDialogue
70  *
71  * replies some crap to the socket
72  *
73  * @param socket the Socket the Dialogue has to use
74  */
CTRLDialogue(Socket * socket,Download * down)75 CTRLDialogue::CTRLDialogue(Socket *socket, Download *down)
76 {
77 	m_Socket = socket;
78     m_DialogueName = "CTRLDialogue";
79 	m_DialogueDescription = "eXample Dialogue";
80 
81 	m_ConsumeLevel = CL_ASSIGN;
82 
83 	m_State = FTP_CONNECTED;
84 	m_Download = down;
85 
86 	m_Buffer = new Buffer(128);
87 }
88 
~CTRLDialogue()89 CTRLDialogue::~CTRLDialogue()
90 {
91 	if (m_Download != NULL)
92 	{
93     	delete m_Download;
94 		m_Download = NULL;
95 	}
96 	delete m_Buffer;
97 
98 	g_FTPDownloadHandler->removeContext(m_Context);
99 }
100 
101 /**
102  * Dialogue::incomingData(Message *)
103  *
104  * a small and ugly shell where we can use
105  * "download protocol://localction:port/path/to/file
106  * to trigger a download
107  *
108  * @param msg the Message the Socker received.
109  *
110  *
111  * @return CL_ASSIGN
112  */
incomingData(Message * msg)113 ConsumeLevel CTRLDialogue::incomingData(Message *msg)
114 {
115 //	logDebug("RX:\n%.*s\n",msg->getSize(),msg->getMsg());
116 	if (m_Download == NULL && m_State < FTP_RETR)
117 	{
118 		logWarn("broken ftp daemon \n");
119 		return CL_DROP;
120 	}
121 
122 	m_Buffer->add(msg->getMsg(),msg->getSize());
123 
124 	uint32_t iStart=0;
125 	uint32_t iStopp=0;
126 	uint32_t endoflines=0;
127 	while ( iStopp<m_Buffer->getSize() )
128 	{
129 		if ( memcmp((char *)m_Buffer->getData()+iStopp,"\n",1) == 0 && iStopp < m_Buffer->getSize() )
130 		{
131 			logDebug("FTPLINE (%i %i %i): '%.*s' \n",iStart,iStopp,iStopp-iStart,iStopp-iStart,(char *)m_Buffer->getData()+iStart);
132 
133 
134 			// add ftp daemon fingerprinting here
135 
136 
137 
138 			switch (m_State)
139 			{
140 			case FTP_CONNECTED:
141 				if (strncmp((char *)m_Buffer->getData() + iStart,"220 ",4) == 0)
142 				{
143 					sendUser();
144 					m_State = FTP_USER;
145 				};
146 
147 			case FTP_USER:
148 				if (parseUser((char *)m_Buffer->getData() + iStart) == true)
149 				{
150 					sendPass();
151 					m_State = FTP_PASS;
152 				}
153 
154 				break;
155 
156 			case FTP_PASS:
157 				if (parsePass((char *)m_Buffer->getData() + iStart) == true)
158 				{
159 					if ( m_Download->getDownloadFlags() != 0 )
160 					{
161 						if ( m_Download->getDownloadFlags() & DF_TYPE_BINARY )
162 						{
163 							sendType();
164 							m_State = FTP_TYPE;
165 						}
166 					}else
167 					{
168 						sendPort();
169 						m_State = FTP_PORT;
170 					}
171 
172 				}
173 				break;
174 
175 
176 			case FTP_TYPE:
177 				if ( parseType((char *)m_Buffer->getData() + iStart)== true )
178 				{
179 					if ( m_Download->getDownloadUrl()->getDir() != "" )
180 					{
181 						sendCWD();
182 						m_State = FTP_CWD;
183 					} else
184 					{
185 						sendPort();
186 						m_State = FTP_PORT;
187 					}
188 				}
189 				break;
190 
191 			case FTP_CWD:
192 				if (parseCWD((char *)m_Buffer->getData() + iStart)== true)
193 				{
194 					sendPort();
195 					m_State = FTP_PORT;
196 				}
197 
198 
199 			case FTP_PORT:
200 				if (parsePort((char *)m_Buffer->getData() + iStart) == true)
201                 {
202 					sendRetr();
203 					m_State = FTP_RETR;
204 				}
205 				break;
206 
207 			case FTP_RETR:
208 				if (strncmp((char *)m_Buffer->getData() + iStart,"150 ",4) == 0)
209 				{
210 					logDebug("RETR accepted\n");
211 				}else
212 				if (strncmp((char *)m_Buffer->getData() + iStart,"226 ",4) == 0)
213 				{
214 					logDebug("Transferr finished\n");
215 					sendQuit();
216 					m_State = FTP_QUIT;
217 				}
218 				break;
219 
220 			case FTP_QUIT:
221 				if (parseQuit((char *)m_Buffer->getData() + iStart) == true)
222 				{
223 					return CL_DROP;
224 				}
225 				break;
226 
227 			default:
228 				break;
229 			}
230 
231 
232 
233 			iStopp++;
234 			iStart=iStopp;
235 			endoflines = iStopp;
236 
237 
238 		} else
239 			iStopp++;
240 	}
241 
242 	m_Buffer->cut(endoflines);
243 	return CL_ASSIGN;
244 }
245 
246 /**
247  * Dialogue::outgoingData(Message *)
248  * as we are not interested in these socket actions
249  * we simply return CL_DROP to show the socket
250  *
251  * @param msg
252  *
253  * @return CL_DROP
254  */
outgoingData(Message * msg)255 ConsumeLevel CTRLDialogue::outgoingData(Message *msg)
256 {
257 	return m_ConsumeLevel;
258 }
259 
260 /**
261  * Dialogue::handleTimeout(Message *)
262  * as we are not interested in these socket actions
263  * we simply return CL_DROP to show the socket
264  *
265  * @param msg
266  *
267  * @return CL_DROP
268  */
handleTimeout(Message * msg)269 ConsumeLevel CTRLDialogue::handleTimeout(Message *msg)
270 {
271 	if (m_State == FTP_RETR)
272 	{
273     	sendQuit();
274 		m_State = FTP_QUIT;
275 		return CL_ASSIGN;
276 	}else
277 	{
278 		return CL_DROP;
279 	}
280 
281 }
282 
283 /**
284  * Dialogue::connectionLost(Message *)
285  * as we are not interested in these socket actions
286  * we simply return CL_DROP to show the socket
287  *
288  * @param msg
289  *
290  * @return CL_DROP
291  */
connectionLost(Message * msg)292 ConsumeLevel CTRLDialogue::connectionLost(Message *msg)
293 {
294 	return CL_DROP;
295 }
296 
297 /**
298  * Dialogue::connectionShutdown(Message *)
299  * as we are not interested in these socket actions
300  * we simply return CL_DROP to show the socket
301  *
302  * @param msg
303  *
304  * @return CL_DROP
305  */
connectionShutdown(Message * msg)306 ConsumeLevel CTRLDialogue::connectionShutdown(Message *msg)
307 {
308 	return CL_DROP;
309 }
310 
setContext(FTPContext * context)311 void CTRLDialogue::setContext(FTPContext *context)
312 {
313 	m_Context = context;
314 }
315 
setDownload(Download * down)316 void CTRLDialogue::setDownload(Download *down)
317 {
318 	m_Download = down;
319 }
320 
321 
sendUser()322 void CTRLDialogue::sendUser()
323 {
324 	char *msg;
325 	asprintf(&msg,"USER %s\r\n",m_Download->getDownloadUrl()->getUser().c_str());
326 	logDebug("FTPSEND: '%s'\n",msg);
327 	m_Socket->doRespond(msg,strlen(msg));
328 	free(msg);
329 }
parseUser(char * msg)330 bool CTRLDialogue::parseUser(char *msg)
331 {
332 	if (strncmp(msg,"331 ",4) == 0)
333 	{
334 		logDebug("User accepted .. \n",m_Download->getDownloadUrl()->getPass().c_str());
335 		return true;
336 	}else
337 	{
338 		return false;
339 	}
340 }
341 
342 
sendPass()343 void CTRLDialogue::sendPass()
344 {
345 	char *nmsg;
346 	asprintf(&nmsg,"PASS %s\r\n",m_Download->getDownloadUrl()->getPass().c_str());
347 	logDebug("FTPSEND: '%s'\n",nmsg);
348 	m_Socket->doRespond(nmsg,strlen(nmsg));
349 	free(nmsg);
350 
351 }
parsePass(char * msg)352 bool CTRLDialogue::parsePass(char *msg)
353 {
354 	if (strncmp(msg,"230 ",4) == 0)
355 	{
356 		logDebug("Pass accepted, logged in \n");
357 		return true;
358 	}else
359 	{
360 		return false;
361 	}
362 
363 
364 }
365 
366 
367 
sendType()368 void CTRLDialogue::sendType()
369 {
370 	const char *nmsg = "TYPE I\r\n";
371 	m_Socket->doRespond(nmsg,strlen(nmsg));
372 	logDebug("FTPSEND: '%s'\n",nmsg);
373 }
374 
parseType(char * msg)375 bool CTRLDialogue::parseType(char *msg)
376 {
377 	if (strncmp(msg,"200 ",4) == 0)
378 	{
379 		logDebug("Type accepted \n");
380 		return true;
381 	}else
382 	{
383 		return false;
384 	}
385 }
386 
387 
388 
sendPort()389 void CTRLDialogue::sendPort()
390 {
391 	logDebug("System ... \n");
392 
393 	uint32_t ip;
394 	uint16_t minport;
395 	uint16_t maxport;
396 
397 	if ( g_FTPDownloadHandler->getRetrAddress() == 0 )
398 	{ // no NAT settings
399 		// get local ip
400 		int32_t sock = m_Socket->getSocket();
401 
402 		// get name
403 		socklen_t len = sizeof(struct sockaddr_in);
404 		sockaddr_in addr;
405 
406 		getsockname(sock, (struct sockaddr *)&addr,&len);
407 
408 		logDebug("local ip is %s \n",inet_ntoa(addr.sin_addr));
409 
410 		ip =  *(uint32_t *)&addr.sin_addr;
411 
412 		minport = rand()%40000+1024;
413 		maxport = minport + 1000;
414 	} else
415 	{	// nat settings, use external ip
416 		ip = g_FTPDownloadHandler->getRetrAddress();
417 		minport = g_FTPDownloadHandler->getMinPort();
418 		maxport = g_FTPDownloadHandler->getMaxPort();
419 
420 	}
421 
422 	uint16_t port = 0;
423 
424 	Socket *socket=NULL;
425 
426 
427 	for (uint16_t i =minport; i<maxport;i++)
428 	{
429 		/* workaround buggy PORT calculation in 'some' worm families */
430 		if ( ((i >> 4) & 0xf) == 0 )
431 			continue;
432 
433 		if ( (socket = g_Nepenthes->getSocketMgr()->bindTCPSocket(0,i,60,30)) != NULL )
434 		{
435 			if ( socket->getDialogst()->size() == 0 && socket->getFactories()->size() == 0 )
436 			{
437 				logInfo("Found unused bind socket on port %i\n",i);
438 				break;
439 			}
440 		}
441 
442 	}
443 
444 	if ( socket == NULL)
445 	{
446 		logCrit("Could not bind port in range %i -> %i \n",minport, maxport);
447 		return;
448 	}
449 
450 	port = socket->getLocalPort();
451 
452 	m_Context->setActiveFTPBindPort(port);
453 	socket->addDialogueFactory(g_FTPDownloadHandler);
454 
455 	char *nmsg;
456 
457 
458 	asprintf(&nmsg,"PORT %d,%d,%d,%d,%d,%d\r\n",
459 #if BYTE_ORDER == BIG_ENDIAN
460 			(int32_t)(ip >> 24) & 0xff,
461 			(int32_t)(ip >> 16) & 0xff,
462 			(int32_t)(ip >> 8) & 0xff,
463 			(int32_t)ip & 0xff,
464 #else
465 			(int32_t)ip & 0xff,
466 			(int32_t)(ip >> 8) & 0xff,
467 			(int32_t)(ip >> 16) & 0xff,
468 			(int32_t)(ip >> 24) & 0xff,
469 #endif
470 			(int32_t)(port >> 8) & 0xff,
471 			(int32_t)port & 0xff);
472 	logDebug("FTPSEND: '%s'\n",nmsg);
473 	m_Socket->doRespond(nmsg,strlen(nmsg));
474 	free(nmsg);
475 
476 }
477 
parsePort(char * msg)478 bool CTRLDialogue::parsePort(char *msg)
479 {
480 	if (strncmp(msg,"200 ",4) == 0)
481 	{
482 		logDebug("Port accepted\n");
483 		return true;
484 	}else
485 	{
486 		return false;
487 	}
488 
489 }
490 
491 
sendRetr()492 void CTRLDialogue::sendRetr()
493 {
494 
495 	char *nmsg;
496 	asprintf(&nmsg,"RETR %s\r\n",m_Download->getDownloadUrl()->getFile().c_str());
497 	logDebug("FTPSEND: '%s'\n",nmsg);
498 	m_Socket->doRespond(nmsg,strlen(nmsg));
499 	free(nmsg);
500 }
501 
parseRetr(char * msg)502 bool CTRLDialogue::parseRetr(char *msg)
503 {
504 	if (strncmp(msg,"150 ",4) == 0)
505 	{
506 		logDebug("Retr accepted\n");
507 		return true;
508 	}else
509 	{
510 		return false;
511 	}
512 }
513 
sendQuit()514 void CTRLDialogue::sendQuit()
515 {
516 
517 	const char *nmsg = "QUIT\r\n";
518 
519 	logDebug("FTPSEND: '%s'\n",nmsg);
520 	m_Socket->doRespond(nmsg,strlen(nmsg));
521 //	free(nmsg);
522 }
523 
parseQuit(char * msg)524 bool CTRLDialogue::parseQuit(char *msg)
525 {
526 	if (strncmp(msg,"221 ",4) == 0)
527 	{
528 		logDebug("Quit accepted\n");
529 		return true;
530 	}else
531 	{
532 		return false;
533 	}
534 }
535 
sendCWD()536 void CTRLDialogue::sendCWD()
537 {
538 	char *nmsg;
539 	asprintf(&nmsg,"CWD %s\r\n",m_Download->getDownloadUrl()->getDir().c_str());
540 	logDebug("FTPSEND: '%s'\n",nmsg);
541 	m_Socket->doRespond(nmsg,strlen(nmsg));
542 	free(nmsg);
543 }
544 
parseCWD(char * msg)545 bool CTRLDialogue::parseCWD(char *msg)
546 {
547 	if (strncmp(msg,"250 ",4) == 0)
548 	{
549 		logDebug("CWD accepted\n");
550 		return true;
551 	}else
552 	{
553 		return false;
554 	}
555 }
556 
557