1
2 /***************************************************************************
3 * Service.cc -- The "Service" class encapsulates every bit of information *
4 * about the associated target's (Target class) service. Service-specific *
5 * options, statistical and timing information as well as functions for *
6 * handling username/password list iteration all belong to this class. *
7 * *
8 ***********************IMPORTANT NMAP LICENSE TERMS************************
9 * *
10 * The Nmap Security Scanner is (C) 1996-2019 Insecure.Com LLC ("The Nmap *
11 * Project"). Nmap is also a registered trademark of the Nmap Project. *
12 * This program is free software; you may redistribute and/or modify it *
13 * under the terms of the GNU General Public License as published by the *
14 * Free Software Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE *
15 * CLARIFICATIONS AND EXCEPTIONS DESCRIBED HEREIN. This guarantees your *
16 * right to use, modify, and redistribute this software under certain *
17 * conditions. If you wish to embed Nmap technology into proprietary *
18 * software, we sell alternative licenses (contact sales@nmap.com). *
19 * Dozens of software vendors already license Nmap technology such as *
20 * host discovery, port scanning, OS detection, version detection, and *
21 * the Nmap Scripting Engine. *
22 * *
23 * Note that the GPL places important restrictions on "derivative works", *
24 * yet it does not provide a detailed definition of that term. To avoid *
25 * misunderstandings, we interpret that term as broadly as copyright law *
26 * allows. For example, we consider an application to constitute a *
27 * derivative work for the purpose of this license if it does any of the *
28 * following with any software or content covered by this license *
29 * ("Covered Software"): *
30 * *
31 * o Integrates source code from Covered Software. *
32 * *
33 * o Reads or includes copyrighted data files, such as Nmap's nmap-os-db *
34 * or nmap-service-probes. *
35 * *
36 * o Is designed specifically to execute Covered Software and parse the *
37 * results (as opposed to typical shell or execution-menu apps, which will *
38 * execute anything you tell them to). *
39 * *
40 * o Includes Covered Software in a proprietary executable installer. The *
41 * installers produced by InstallShield are an example of this. Including *
42 * Nmap with other software in compressed or archival form does not *
43 * trigger this provision, provided appropriate open source decompression *
44 * or de-archiving software is widely available for no charge. For the *
45 * purposes of this license, an installer is considered to include Covered *
46 * Software even if it actually retrieves a copy of Covered Software from *
47 * another source during runtime (such as by downloading it from the *
48 * Internet). *
49 * *
50 * o Links (statically or dynamically) to a library which does any of the *
51 * above. *
52 * *
53 * o Executes a helper program, module, or script to do any of the above. *
54 * *
55 * This list is not exclusive, but is meant to clarify our interpretation *
56 * of derived works with some common examples. Other people may interpret *
57 * the plain GPL differently, so we consider this a special exception to *
58 * the GPL that we apply to Covered Software. Works which meet any of *
59 * these conditions must conform to all of the terms of this license, *
60 * particularly including the GPL Section 3 requirements of providing *
61 * source code and allowing free redistribution of the work as a whole. *
62 * *
63 * As another special exception to the GPL terms, the Nmap Project grants *
64 * permission to link the code of this program with any version of the *
65 * OpenSSL library which is distributed under a license identical to that *
66 * listed in the included docs/licenses/OpenSSL.txt file, and distribute *
67 * linked combinations including the two. *
68 * *
69 * The Nmap Project has permission to redistribute Npcap, a packet *
70 * capturing driver and library for the Microsoft Windows platform. *
71 * Npcap is a separate work with it's own license rather than this Nmap *
72 * license. Since the Npcap license does not permit redistribution *
73 * without special permission, our Nmap Windows binary packages which *
74 * contain Npcap may not be redistributed without special permission. *
75 * *
76 * Any redistribution of Covered Software, including any derived works, *
77 * must obey and carry forward all of the terms of this license, including *
78 * obeying all GPL rules and restrictions. For example, source code of *
79 * the whole work must be provided and free redistribution must be *
80 * allowed. All GPL references to "this License", are to be treated as *
81 * including the terms and conditions of this license text as well. *
82 * *
83 * Because this license imposes special exceptions to the GPL, Covered *
84 * Work may not be combined (even as part of a larger work) with plain GPL *
85 * software. The terms, conditions, and exceptions of this license must *
86 * be included as well. This license is incompatible with some other open *
87 * source licenses as well. In some cases we can relicense portions of *
88 * Nmap or grant special permissions to use it in other open source *
89 * software. Please contact fyodor@nmap.org with any such requests. *
90 * Similarly, we don't incorporate incompatible open source software into *
91 * Covered Software without special permission from the copyright holders. *
92 * *
93 * If you have any questions about the licensing restrictions on using *
94 * Nmap in other works, we are happy to help. As mentioned above, we also *
95 * offer an alternative license to integrate Nmap into proprietary *
96 * applications and appliances. These contracts have been sold to dozens *
97 * of software vendors, and generally include a perpetual license as well *
98 * as providing support and updates. They also fund the continued *
99 * development of Nmap. Please email sales@nmap.com for further *
100 * information. *
101 * *
102 * If you have received a written license agreement or contract for *
103 * Covered Software stating terms other than these, you may choose to use *
104 * and redistribute Covered Software under those terms instead of these. *
105 * *
106 * Source is provided to this software because we believe users have a *
107 * right to know exactly what a program is going to do before they run it. *
108 * This also allows you to audit the software for security holes. *
109 * *
110 * Source code also allows you to port Nmap to new platforms, fix bugs, *
111 * and add new features. You are highly encouraged to send your changes *
112 * to the dev@nmap.org mailing list for possible incorporation into the *
113 * main distribution. By sending these changes to Fyodor or one of the *
114 * Insecure.Org development mailing lists, or checking them into the Nmap *
115 * source code repository, it is understood (unless you specify *
116 * otherwise) that you are offering the Nmap Project the unlimited, *
117 * non-exclusive right to reuse, modify, and relicense the code. Nmap *
118 * will always be available Open Source, but this is important because *
119 * the inability to relicense code has caused devastating problems for *
120 * other Free Software projects (such as KDE and NASM). We also *
121 * occasionally relicense the code to third parties as discussed above. *
122 * If you wish to specify special license conditions of your *
123 * contributions, just say so when you send them. *
124 * *
125 * This program is distributed in the hope that it will be useful, but *
126 * WITHOUT ANY WARRANTY; without even the implied warranty of *
127 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Nmap *
128 * license file for more details (it's in a COPYING file included with *
129 * Nmap, and also available from https://svn.nmap.org/nmap/COPYING) *
130 * *
131 ***************************************************************************/
132
133 #include "Service.h"
134 #include "NcrackOps.h"
135
136 extern NcrackOps o;
137
138
139 Service::
Service()140 Service()
141 {
142 static unsigned long id = 0;
143 name = NULL;
144 target = NULL;
145 proto = IPPROTO_TCP;
146 portno = 0;
147
148 uid = id++;
149
150 loginlist_fini = false;
151 list_active = true;
152 list_full = false;
153 list_wait = false;
154 list_pairfini = false;
155 list_finishing = false;
156 list_finished = false;
157 just_started = true;
158 more_rounds = false;
159 skip_username = false;
160
161 end.orly = false;
162 end.reason = NULL;
163
164 failed_connections = 0;
165 total_attempts = 0;
166 finished_attempts = 0;
167 supported_attempts = 0;
168 active_connections = 0;
169
170 min_connection_limit = -1;
171 max_connection_limit = -1;
172 ideal_parallelism = 1; /* we start with 1 connection exactly */
173 auth_tries = -1;
174 connection_delay = -1;
175 connection_retries = -1;
176 timeout = -1;
177 path = Strndup("/", 2); /* path is '/' by default */
178
179 db = Strndup("admin", 5); /* databse is 'admin' by default */
180 domain = Strndup("Workstation", 11); /* domain is 'Workstation' by default */
181
182 ssl = false;
183
184 module_data = NULL;
185 memset(&last, 0, sizeof(last));
186 UserArray = NULL;
187 PassArray = NULL;
188 hostinfo = NULL;
189 memset(&last_auth_rate, 0, sizeof(last_auth_rate));
190
191 htn.msecs_used = 0;
192 htn.toclock_running = false;
193 htn.host_start = htn.host_end = 0;
194
195 linear_state = LINEAR_INIT;
196 }
197
198 /* copy constructor */
199 Service::
Service(const Service & ref)200 Service(const Service& ref)
201 {
202 name = strdup(ref.name);
203 proto = ref.proto;
204 portno = ref.portno;
205
206 uid = ref.uid;
207
208 min_connection_limit = ref.min_connection_limit;
209 max_connection_limit = ref.max_connection_limit;
210 auth_tries = ref.auth_tries;
211 connection_delay = ref.connection_delay;
212 connection_retries = ref.connection_retries;
213 timeout = ref.timeout;
214 ssl = ref.ssl;
215 //if (path)
216 // free(path);
217 path = Strndup(ref.path, strlen(ref.path));
218
219 db = Strndup(ref.db, strlen(ref.db));
220
221 domain = Strndup(ref.domain, strlen(ref.domain));
222
223 ideal_parallelism = 1; /* we start with 1 connection exactly */
224
225 ssl = ref.ssl;
226 UserArray = ref.UserArray;
227 PassArray = ref.PassArray;
228 uservi = UserArray->begin();
229 passvi = PassArray->begin();
230
231 failed_connections = 0;
232 total_attempts = 0;
233 finished_attempts = 0;
234 supported_attempts = 0;
235 active_connections = 0;
236
237 loginlist_fini = false;
238 passlist_fini = false;
239 userlist_fini = false;
240 list_active = true;
241 list_full = false;
242 list_wait = false;
243 list_pairfini = false;
244 list_finishing = false;
245 list_finished = false;
246 just_started = true;
247 more_rounds = false;
248 skip_username = false;
249
250 end.orly = false;
251 end.reason = NULL;
252
253 module_data = NULL;
254 hostinfo = NULL;
255 memset(&last, 0, sizeof(last));
256 memset(&last_auth_rate, 0, sizeof(last_auth_rate));
257
258 htn.msecs_used = 0;
259 htn.toclock_running = false;
260 htn.host_start = htn.host_end = 0;
261
262 linear_state = ref.linear_state;
263 }
264
265 Service::
~Service()266 ~Service()
267 {
268 if (name)
269 free(name);
270 if (module_data)
271 free(module_data);
272 if (hostinfo)
273 free(hostinfo);
274 if (end.reason)
275 free(end.reason);
276 }
277
278 const char *Service::
HostInfo(void)279 HostInfo(void)
280 {
281 if (!hostinfo)
282 hostinfo = (char *) safe_malloc(MAX_HOSTINFO_LEN);
283
284 if (!target)
285 fatal("%s: tried to print hostinfo with uninitialized Target\n", __func__);
286
287 Snprintf(hostinfo, MAX_HOSTINFO_LEN, "%s://%s:%hu", name,
288 target->NameIP(), portno);
289 return hostinfo;
290 }
291
292
293 /* Add discovered credential to private list */
294 void Service::
addCredential(char * user,char * pass)295 addCredential(char *user, char *pass)
296 {
297 loginpair tmp;
298 tmp.user = user;
299 tmp.pass = pass;
300 credentials_found.push_back(tmp);
301 }
302
303 uint32_t Service::
getUserlistIndex(void)304 getUserlistIndex(void)
305 {
306 return std::distance(UserArray->begin(), uservi);
307 }
308
309 void Service::
setUserlistIndex(uint32_t index)310 setUserlistIndex(uint32_t index)
311 {
312 uservi = UserArray->begin() + index;
313 }
314
315 uint32_t Service::
getPasslistIndex(void)316 getPasslistIndex(void)
317 {
318 return std::distance(PassArray->begin(), passvi);
319 }
320
321 void Service::
setPasslistIndex(uint32_t index)322 setPasslistIndex(uint32_t index)
323 {
324 passvi = PassArray->begin() + index;
325 }
326
327
328 /*
329 * returns -1 for end of login list and empty pool
330 * 0 for successful retrieval through lists
331 * 1 for successful retrieval through pool
332 */
333 int Service::
getNextPair(char ** user,char ** pass)334 getNextPair(char **user, char **pass)
335 {
336 if (!UserArray)
337 fatal("%s: uninitialized UserArray\n", __func__);
338
339 if (!PassArray)
340 fatal("%s: uninitialized PassArray\n", __func__);
341
342 loginpair tmp;
343
344 /* If the login pair pool is not empty, then give priority to these
345 * pairs and extract the first one you find. */
346 if (!pair_pool.empty()) {
347
348 list <loginpair>::iterator pairli = pair_pool.begin();
349 tmp = pair_pool.front();
350 *user = tmp.user;
351 *pass = tmp.pass;
352 pair_pool.erase(pairli);
353 if (o.debugging > 8)
354 log_write(LOG_STDOUT, "%s Pool: extract '%s' '%s'\n", HostInfo(),
355 tmp.user, tmp.pass);
356 return 1;
357 }
358
359 if (loginlist_fini)
360 return -1;
361
362 if (!strcmp(name, "redis")) {
363 if (passvi == PassArray->end()) {
364 if (o.debugging > 8)
365 log_write(LOG_STDOUT, "%s Password list finished!\n", HostInfo());
366 loginlist_fini = true;
367 return -1;
368 }
369 *user = *uservi;
370 *pass = *passvi;
371 passvi++;
372 return 0;
373 }
374
375 if (!strcmp(name, "mongodb")) {
376 if (skip_username == true) {
377 uservi--;
378 if (o.debugging > 5)
379 log_write(LOG_STDOUT, "%s skipping username!!!! %s\n", HostInfo(), *(uservi));
380 uservi = UserArray->erase(uservi);
381 if (uservi == UserArray->end()) {
382 uservi = UserArray->begin();
383 passvi++;
384 if (passvi == PassArray->end()) {
385 if (o.debugging > 8)
386 log_write(LOG_STDOUT, "%s Password list finished!\n", HostInfo());
387 loginlist_fini = true;
388 return -1;
389 }
390 }
391 //printf("next user: %s\n", *uservi);
392 skip_username = false;
393 }
394 }
395
396 if (!strcmp(name, "ssh")) {
397
398 /* catches bug where ssh module crashed when user had specified correct username and
399 * password in the first attempt
400 */
401 if (just_started == false && PassArray->size() == 1 && UserArray->size() == 1) {
402 uservi = UserArray->end();
403 passvi = PassArray->end();
404 loginlist_fini = true;
405 return -1;
406 }
407
408 /* special case for ssh */
409 if (just_started == true) {
410
411 /* keep using same username for first timing probe */
412 if (passvi == PassArray->end()) {
413 passvi = PassArray->begin();
414 uservi++;
415 if (uservi == UserArray->end()) {
416 if (o.debugging > 8)
417 log_write(LOG_STDOUT, "%s Username list finished!\n", HostInfo());
418 loginlist_fini = true;
419 return -1;
420 }
421 }
422 *user = *uservi;
423 *pass = *passvi;
424 passvi++;
425
426 return 0;
427 }
428 }
429
430 if (o.pairwise && strcmp(name, "mongodb")) {
431
432 if (uservi == UserArray->end() && passvi == PassArray->end()) {
433 if (o.debugging > 8)
434 log_write(LOG_STDOUT, "%s Password list finished!\n", HostInfo());
435 loginlist_fini = true;
436 return -1;
437 }
438 if (uservi == UserArray->end()) {
439 uservi = UserArray->begin();
440 userlist_fini = true;
441 }
442 if (passvi == PassArray->end()) {
443 passvi = PassArray->begin();
444 passlist_fini = true;
445 }
446 if (userlist_fini == true && passlist_fini == true) {
447 if (o.debugging > 8)
448 log_write(LOG_STDOUT, "%s Password list finished!\n", HostInfo());
449 loginlist_fini = true;
450 return -1;
451 }
452 *pass = *passvi;
453 *user = *uservi;
454 uservi++;
455 passvi++;
456
457 } else if (o.passwords_first && strcmp(name, "mongodb")) {
458 /* Iteration of password list for each username. */
459 /* If password list finished one iteration then reset the password pointer
460 * to show at the beginning and get next username from username list. */
461 if (passvi == PassArray->end()) {
462 passvi = PassArray->begin();
463 uservi++;
464 if (uservi == UserArray->end()) {
465 if (o.debugging > 8)
466 log_write(LOG_STDOUT, "%s Username list finished!\n", HostInfo());
467 loginlist_fini = true;
468 return -1;
469 }
470 }
471 *user = *uservi;
472 *pass = *passvi;
473 passvi++;
474
475 } else if (!o.passwords_first || !strcmp(name, "mongodb")) {
476 /* Iteration of username list for each password (default). */
477 /* If username list finished one iteration then reset the username pointer
478 * to show at the beginning and get password from password list. */
479 if (uservi == UserArray->end()) {
480 uservi = UserArray->begin();
481 passvi++;
482 if (passvi == PassArray->end()) {
483 if (o.debugging > 8)
484 log_write(LOG_STDOUT, "%s Password list finished!\n", HostInfo());
485 loginlist_fini = true;
486 return -1;
487 }
488 }
489 *pass = *passvi;
490 *user = *uservi;
491 uservi++;
492 }
493
494
495 return 0;
496 }
497
498
499 void Service::
removeFromPool(char * user,char * pass)500 removeFromPool(char *user, char *pass)
501 {
502 loginpair tmp;
503 list <loginpair>::iterator li;
504
505 if (!user || !pass)
506 return;
507
508 tmp.user = user;
509 tmp.pass = pass;
510
511 for (li = mirror_pair_pool.begin(); li != mirror_pair_pool.end(); li++) {
512 if ((tmp.user == li->user) && (tmp.pass == li->pass))
513 break;
514 }
515 if (li != mirror_pair_pool.end()) {
516 if (o.debugging > 8) {
517 if (!strcmp(name, "redis"))
518 log_write(LOG_STDOUT, "%s Pool: Removed '%s' \n", HostInfo(), tmp.pass);
519 else
520 log_write(LOG_STDOUT, "%s Pool: Removed %s %s\n", HostInfo(),
521 tmp.user, tmp.pass);
522 }
523 mirror_pair_pool.erase(li);
524 }
525 }
526
527
528
529 void Service::
appendToPool(char * user,char * pass)530 appendToPool(char *user, char *pass)
531 {
532 loginpair tmp;
533 list <loginpair>::iterator li;
534
535 if (!user)
536 fatal("%s: tried to append NULL user into pair pool", __func__);
537 if (!pass)
538 fatal("%s: tried to append NULL password into pair pool", __func__);
539
540 tmp.user = user;
541 tmp.pass = pass;
542 pair_pool.push_back(tmp);
543
544 if (o.debugging > 8) {
545 if (!strcmp(name, "redis"))
546 log_write(LOG_STDOUT, "%s Pool: Append '%s' \n", HostInfo(), tmp.pass);
547 else
548 log_write(LOG_STDOUT, "%s Pool: Append '%s' '%s' \n", HostInfo(),
549 tmp.user, tmp.pass);
550 }
551
552 /*
553 * Try and see if login pair was already in our mirror pool. Only if
554 * it doesn't already exist, then append it to the list.
555 */
556 for (li = mirror_pair_pool.begin(); li != mirror_pair_pool.end(); li++) {
557 if ((tmp.user == li->user) && (tmp.pass == li->pass))
558 break;
559 }
560 if (li == mirror_pair_pool.end())
561 mirror_pair_pool.push_back(tmp);
562 }
563
564
565 bool Service::
isMirrorPoolEmpty(void)566 isMirrorPoolEmpty(void)
567 {
568 return mirror_pair_pool.empty();
569 }
570
571
572 bool Service::
isPoolEmpty(void)573 isPoolEmpty(void)
574 {
575 return pair_pool.empty();
576 }
577
578
579 double Service::
getPercDone(void)580 getPercDone(void)
581 {
582 double ret = 0.0;
583 vector <char *>::iterator usertmp = uservi;
584 vector <char *>::iterator passtmp = passvi;
585
586 if (!o.passwords_first) {
587 if (passtmp != PassArray->begin())
588 passtmp--;
589 if (uservi == UserArray->end()) {
590 ret = distance(PassArray->begin(), passtmp) * UserArray->size();
591 } else {
592 if (usertmp != UserArray->begin())
593 usertmp--;
594 ret = distance(PassArray->begin(), passtmp) * UserArray->size()
595 + distance(UserArray->begin(), usertmp);
596 }
597 } else {
598 if (usertmp != UserArray->begin())
599 usertmp--;
600 if (passvi == PassArray->end()) {
601 ret = distance(UserArray->begin(), usertmp) * PassArray->size();
602 } else {
603 if (passtmp != PassArray->begin())
604 passtmp--;
605 ret = distance(UserArray->begin(), usertmp) * PassArray->size()
606 + distance(PassArray->begin(), passtmp);
607 }
608 }
609
610 if (ret) {
611 ret /= (double) (UserArray->size() * PassArray->size());
612 if (ret >= 0.9999)
613 ret = 0.9999;
614 } else
615 ret = 0.0;
616
617 return ret;
618 }
619
620
621 /*
622 * Starts the timeout clock for the host running (e.g. you are
623 * beginning a scan). If you do not have the current time handy,
624 * you can pass in NULL. When done, call stopTimeOutClock (it will
625 * also automatically be stopped of timedOut() returns true)
626 */
627 void Service::
startTimeOutClock(const struct timeval * now)628 startTimeOutClock(const struct timeval *now) {
629 assert(htn.toclock_running == false);
630 htn.toclock_running = true;
631 if (now) htn.toclock_start = *now;
632 else gettimeofday(&htn.toclock_start, NULL);
633 if (!htn.host_start) htn.host_start = htn.toclock_start.tv_sec;
634 }
635
636
637 /* The complement to startTimeOutClock. */
638 void Service::
stopTimeOutClock(const struct timeval * now)639 stopTimeOutClock(const struct timeval *now) {
640 struct timeval tv;
641 assert(htn.toclock_running == true);
642 htn.toclock_running = false;
643 if (now) tv = *now;
644 else gettimeofday(&tv, NULL);
645 htn.msecs_used += timeval_msec_subtract(tv, htn.toclock_start);
646 htn.host_end = tv.tv_sec;
647 }
648
649 /*
650 * Returns whether the host is timedout. If the timeoutclock is
651 * running, counts elapsed time for that. Pass NULL if you don't have the
652 * current time handy. You might as well also pass NULL if the
653 * clock is not running, as the func won't need the time.
654 */
655 bool Service::
timedOut(const struct timeval * now)656 timedOut(const struct timeval *now) {
657 unsigned long used = htn.msecs_used;
658 struct timeval tv;
659
660 if (!timeout)
661 return false;
662 if (htn.toclock_running) {
663 if (now)
664 tv = *now;
665 else
666 gettimeofday(&tv, NULL);
667
668 used += timeval_msec_subtract(tv, htn.toclock_start);
669 }
670
671 return (used > (unsigned long)timeout)? true : false;
672 }
673
674 void Service::
setLinearState(size_t state)675 setLinearState(size_t state) {
676
677 linear_state = state;
678 }
679
680
681 size_t Service::
getLinearState(void)682 getLinearState(void) {
683
684 return linear_state;
685 }
686