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