1 
2 /***************************************************************************
3  * ncrack.cc -- ncrack's core engine along with all nsock callback         *
4  * handlers reside in here. Simple options' (not host or service-options   *
5  * specification handling) parsing also happens in main() here.            *
6  *                                                                         *
7  ***********************IMPORTANT NMAP LICENSE TERMS************************
8  *                                                                         *
9  * The Nmap Security Scanner is (C) 1996-2019 Insecure.Com LLC ("The Nmap  *
10  * Project"). Nmap is also a registered trademark of the Nmap Project.     *
11  * This program is free software; you may redistribute and/or modify it    *
12  * under the terms of the GNU General Public License as published by the   *
13  * Free Software Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE   *
14  * CLARIFICATIONS AND EXCEPTIONS DESCRIBED HEREIN.  This guarantees your   *
15  * right to use, modify, and redistribute this software under certain      *
16  * conditions.  If you wish to embed Nmap technology into proprietary      *
17  * software, we sell alternative licenses (contact sales@nmap.com).        *
18  * Dozens of software vendors already license Nmap technology such as      *
19  * host discovery, port scanning, OS detection, version detection, and     *
20  * the Nmap Scripting Engine.                                              *
21  *                                                                         *
22  * Note that the GPL places important restrictions on "derivative works",  *
23  * yet it does not provide a detailed definition of that term.  To avoid   *
24  * misunderstandings, we interpret that term as broadly as copyright law   *
25  * allows.  For example, we consider an application to constitute a        *
26  * derivative work for the purpose of this license if it does any of the   *
27  * following with any software or content covered by this license          *
28  * ("Covered Software"):                                                   *
29  *                                                                         *
30  * o Integrates source code from Covered Software.                         *
31  *                                                                         *
32  * o Reads or includes copyrighted data files, such as Nmap's nmap-os-db   *
33  * or nmap-service-probes.                                                 *
34  *                                                                         *
35  * o Is designed specifically to execute Covered Software and parse the    *
36  * results (as opposed to typical shell or execution-menu apps, which will *
37  * execute anything you tell them to).                                     *
38  *                                                                         *
39  * o Includes Covered Software in a proprietary executable installer.  The *
40  * installers produced by InstallShield are an example of this.  Including *
41  * Nmap with other software in compressed or archival form does not        *
42  * trigger this provision, provided appropriate open source decompression  *
43  * or de-archiving software is widely available for no charge.  For the    *
44  * purposes of this license, an installer is considered to include Covered *
45  * Software even if it actually retrieves a copy of Covered Software from  *
46  * another source during runtime (such as by downloading it from the       *
47  * Internet).                                                              *
48  *                                                                         *
49  * o Links (statically or dynamically) to a library which does any of the  *
50  * above.                                                                  *
51  *                                                                         *
52  * o Executes a helper program, module, or script to do any of the above.  *
53  *                                                                         *
54  * This list is not exclusive, but is meant to clarify our interpretation  *
55  * of derived works with some common examples.  Other people may interpret *
56  * the plain GPL differently, so we consider this a special exception to   *
57  * the GPL that we apply to Covered Software.  Works which meet any of     *
58  * these conditions must conform to all of the terms of this license,      *
59  * particularly including the GPL Section 3 requirements of providing      *
60  * source code and allowing free redistribution of the work as a whole.    *
61  *                                                                         *
62  * As another special exception to the GPL terms, the Nmap Project grants  *
63  * permission to link the code of this program with any version of the     *
64  * OpenSSL library which is distributed under a license identical to that  *
65  * listed in the included docs/licenses/OpenSSL.txt file, and distribute   *
66  * linked combinations including the two.                                  *
67  *                                                                         *
68  * The Nmap Project has permission to redistribute Npcap, a packet         *
69  * capturing driver and library for the Microsoft Windows platform.        *
70  * Npcap is a separate work with it's own license rather than this Nmap    *
71  * license.  Since the Npcap license does not permit redistribution        *
72  * without special permission, our Nmap Windows binary packages which      *
73  * contain Npcap may not be redistributed without special permission.      *
74  *                                                                         *
75  * Any redistribution of Covered Software, including any derived works,    *
76  * must obey and carry forward all of the terms of this license, including *
77  * obeying all GPL rules and restrictions.  For example, source code of    *
78  * the whole work must be provided and free redistribution must be         *
79  * allowed.  All GPL references to "this License", are to be treated as    *
80  * including the terms and conditions of this license text as well.        *
81  *                                                                         *
82  * Because this license imposes special exceptions to the GPL, Covered     *
83  * Work may not be combined (even as part of a larger work) with plain GPL *
84  * software.  The terms, conditions, and exceptions of this license must   *
85  * be included as well.  This license is incompatible with some other open *
86  * source licenses as well.  In some cases we can relicense portions of    *
87  * Nmap or grant special permissions to use it in other open source        *
88  * software.  Please contact fyodor@nmap.org with any such requests.       *
89  * Similarly, we don't incorporate incompatible open source software into  *
90  * Covered Software without special permission from the copyright holders. *
91  *                                                                         *
92  * If you have any questions about the licensing restrictions on using     *
93  * Nmap in other works, we are happy to help.  As mentioned above, we also *
94  * offer an alternative license to integrate Nmap into proprietary         *
95  * applications and appliances.  These contracts have been sold to dozens  *
96  * of software vendors, and generally include a perpetual license as well  *
97  * as providing support and updates.  They also fund the continued         *
98  * development of Nmap.  Please email sales@nmap.com for further           *
99  * information.                                                            *
100  *                                                                         *
101  * If you have received a written license agreement or contract for        *
102  * Covered Software stating terms other than these, you may choose to use  *
103  * and redistribute Covered Software under those terms instead of these.   *
104  *                                                                         *
105  * Source is provided to this software because we believe users have a     *
106  * right to know exactly what a program is going to do before they run it. *
107  * This also allows you to audit the software for security holes.          *
108  *                                                                         *
109  * Source code also allows you to port Nmap to new platforms, fix bugs,    *
110  * and add new features.  You are highly encouraged to send your changes   *
111  * to the dev@nmap.org mailing list for possible incorporation into the    *
112  * main distribution.  By sending these changes to Fyodor or one of the    *
113  * Insecure.Org development mailing lists, or checking them into the Nmap  *
114  * source code repository, it is understood (unless you specify            *
115  * otherwise) that you are offering the Nmap Project the unlimited,        *
116  * non-exclusive right to reuse, modify, and relicense the code.  Nmap     *
117  * will always be available Open Source, but this is important because     *
118  * the inability to relicense code has caused devastating problems for     *
119  * other Free Software projects (such as KDE and NASM).  We also           *
120  * occasionally relicense the code to third parties as discussed above.    *
121  * If you wish to specify special license conditions of your               *
122  * contributions, just say so when you send them.                          *
123  *                                                                         *
124  * This program is distributed in the hope that it will be useful, but     *
125  * WITHOUT ANY WARRANTY; without even the implied warranty of              *
126  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the Nmap      *
127  * license file for more details (it's in a COPYING file included with     *
128  * Nmap, and also available from https://svn.nmap.org/nmap/COPYING)        *
129  *                                                                         *
130  ***************************************************************************/
131 
132 
133 #include "ncrack.h"
134 #include "NcrackOps.h"
135 #include "utils.h"
136 #include "services.h"
137 #include "targets.h"
138 #include "TargetGroup.h"
139 #include "ServiceGroup.h"
140 #include "nsock.h"
141 #include "global_structures.h"
142 #include "NcrackOutputTable.h"
143 #include "modules.h"
144 #include "ncrack_error.h"
145 #include "output.h"
146 #include "ncrack_tty.h"
147 #include "ncrack_input.h"
148 #include "ncrack_resume.h"
149 #include "xml.h"
150 #include <time.h>
151 #include <vector>
152 
153 #if HAVE_SIGNAL
154   #include <signal.h>
155 #endif
156 
157 #if HAVE_OPENSSL
158   #include <openssl/ssl.h>
159 #endif
160 
161 #ifdef WIN32
162   #include "winfix.h"
163 #endif
164 
165 #define DEFAULT_CONNECT_TIMEOUT 5000
166 /* includes connect() + ssl negotiation */
167 #define DEFAULT_CONNECT_SSL_TIMEOUT 8000
168 #define DEFAULT_USERNAME_FILE "default.usr"
169 #define DEFAULT_PASSWORD_FILE "default.pwd"
170 
171 /* (in milliseconds) every such interval we poll for interactive user input */
172 #define KEYPRESSED_INTERVAL 500
173 
174 /* (in milliseconds) every such interval check for pending signals */
175 #define SIGNAL_CHECK_INTERVAL 1000
176 
177 #define SERVICE_TIMEDOUT "Service timed-out as specified by user option."
178 
179 extern NcrackOps o;
180 using namespace std;
181 
182 /* global lookup table for available services */
183 vector <global_service> ServicesTable;
184 /* global login and pass array */
185 vector <char *> UserArray;
186 vector <char *> PassArray;
187 
188 
189 /* schedule additional connections */
190 static void ncrack_probes(nsock_pool nsp, ServiceGroup *SG);
191 /* ncrack initialization */
192 static int ncrack(ServiceGroup *SG);
193 /* Poll for interactive user input every time this timer is called. */
194 static void status_timer_handler(nsock_pool nsp, nsock_event nse,
195     void *mydata);
196 static void signal_timer_handler(nsock_pool nsp, nsock_event nse,
197     void *mydata);
198 
199 /* module name demultiplexor */
200 static void call_module(nsock_pool nsp, Connection* con);
201 
202 static void parse_login_list(char *const arg, int mode);
203 static void load_login_file(const char *filename, int mode);
204 enum mode { USER, PASS };
205 
206 
207 static void print_usage(void);
208 static void lookup_init(const char *const filename);
209 static int file_readable(const char *pathname);
210 static int ncrack_fetchfile(char *filename_returned, int bufferlen,
211   const char *file, int useroption = 0);
212 static char *grab_next_host_spec(FILE *inputfd, int argc, char **argv);
213 static void startTimeOutClocks(ServiceGroup *SG);
214 static void sigcatch(int signo);
215 static void sigcheck(ServiceGroup *SG);
216 static int ncrack_main(int argc, char **argv);
217 
218 
219 static void
print_usage(void)220 print_usage(void)
221 {
222   log_write(LOG_STDOUT, "%s %s ( %s )\n"
223       "Usage: ncrack [Options] {target and service specification}\n"
224       "TARGET SPECIFICATION:\n"
225       "  Can pass hostnames, IP addresses, networks, etc.\n"
226       "  Ex: scanme.nmap.org, microsoft.com/24, 192.168.0.1; "
227          "10.0.0-255.1-254\n"
228       "  -iX <inputfilename>: Input from Nmap's -oX XML output format\n"
229       "  -iN <inputfilename>: Input from Nmap's -oN Normal output format\n"
230       "  -iL <inputfilename>: Input from list of hosts/networks\n"
231       "  --exclude <host1[,host2][,host3],...>: Exclude hosts/networks\n"
232       "  --excludefile <exclude_file>: Exclude list from file\n"
233       "SERVICE SPECIFICATION:\n"
234       "  Can pass target specific services in <service>://target (standard) "
235          "notation or\n"
236       "  using -p which will be applied to all hosts in non-standard "
237          "notation.\n"
238       "  Service arguments can be specified to be host-specific, type of "
239          "service-specific\n"
240       "  (-m) or global (-g). Ex: ssh://10.0.0.10,at=10,cl=30 -m ssh:at=50 "
241          "-g cd=3000\n"
242       "  Ex2: ncrack -p ssh,ftp:3500,25 10.0.0.10 scanme.nmap.org "
243          "google.com:80,ssl\n"
244       "  -p <service-list>: services will be applied to all non-standard "
245          "notation hosts\n"
246       "  -m <service>:<options>: options will be applied to all services "
247          "of this type\n"
248       "  -g <options>: options will be applied to every service globally\n"
249       "  Misc options:\n"
250       "    ssl: enable SSL over this service\n"
251       "    path <name>: used in modules like HTTP ('=' needs escaping if "
252            "used)\n"
253       "    db <name>: used in modules like MongoDB to specify the database\n"
254       "    domain <name>: used in modules like WinRM to specify the domain\n"
255       "TIMING AND PERFORMANCE:\n"
256       "  Options which take <time> are in seconds, unless you append 'ms'\n"
257       "  (miliseconds), 'm' (minutes), or 'h' (hours) to the value (e.g. 30m)."
258       "\n"
259       "  Service-specific options:\n"
260       "    cl (min connection limit): minimum number of concurrent parallel "
261            "connections\n"
262       "    CL (max connection limit): maximum number of concurrent parallel "
263            "connections\n"
264       "    at (authentication tries): authentication attempts per connection\n"
265       "    cd (connection delay): delay <time> between each connection "
266            "initiation\n"
267       "    cr (connection retries): caps number of service connection "
268            "attempts\n"
269       "    to (time-out): maximum cracking <time> for service, regardless "
270            "of success so far\n"
271       "  -T<0-5>: Set timing template (higher is faster)\n"
272       "  --connection-limit <number>: threshold for total concurrent "
273         "connections\n"
274       "  --stealthy-linear: try credentials using only one connection against "
275         "each specified host \n    until you hit the same host again. "
276         "Overrides all other timing options.\n"
277       "AUTHENTICATION:\n"
278       "  -U <filename>: username file\n"
279       "  -P <filename>: password file\n"
280       "  --user <username_list>: comma-separated username list\n"
281       "  --pass <password_list>: comma-separated password list\n"
282       "  --passwords-first: Iterate password list for each username. "
283         "Default is opposite.\n"
284       "  --pairwise: Choose usernames and passwords in pairs.\n"
285       "OUTPUT:\n"
286       "  -oN/-oX <file>: Output scan in normal and XML format, respectively, "
287          "to the given filename.\n"
288       "  -oA <basename>: Output in the two major formats at once\n"
289       "  -v: Increase verbosity level (use twice or more for greater effect)\n"
290       "  -d[level]: Set or increase debugging level (Up to 10 is meaningful)\n"
291       "  --nsock-trace <level>: Set nsock trace level (Valid range: 0 - 10)\n"
292       "  --log-errors: Log errors/warnings to the normal-format output file\n"
293       "  --append-output: Append to rather than clobber specified output "
294          "files\n"
295       "MISC:\n"
296       "  --resume <file>: Continue previously saved session\n"
297       "  --save <file>: Save restoration file with specific filename\n"
298       "  -f: quit cracking service after one found credential\n"
299       "  -6: Enable IPv6 cracking\n"
300       "  -sL or --list: only list hosts and services\n"
301       "  --datadir <dirname>: Specify custom Ncrack data file location\n"
302       "  --proxy <type://proxy:port>: Make connections via socks4, 4a, http.\n"
303       "  -V: Print version number\n"
304       "  -h: Print this help summary page.\n"
305       "MODULES:\n"
306       "  SSH, RDP, FTP, Telnet, HTTP(S), Wordpress, POP3(S), IMAP, CVS, SMB, VNC, SIP, Redis, "
307       "PostgreSQL, MQTT, MySQL, MSSQL, MongoDB, Cassandra, WinRM, OWA, DICOM\n"
308       "EXAMPLES:\n"
309       "  ncrack -v --user root localhost:22\n"
310       "  ncrack -v -T5 https://192.168.0.1\n"
311       "  ncrack -v -iX ~/nmap.xml -g CL=5,to=1h\n"
312       "SEE THE MAN PAGE (http://nmap.org/ncrack/man.html) FOR MORE OPTIONS "
313       "AND EXAMPLES\n",
314       NCRACK_NAME, NCRACK_VERSION, NCRACK_URL);
315   exit(EXIT_FAILURE);
316 }
317 
318 
319 static void
lookup_init(const char * const filename)320 lookup_init(const char *const filename)
321 {
322   char line[1024];
323   char servicename[128], proto[16];
324   u16 portno;
325   FILE *fp;
326   vector <global_service>::iterator vi;
327   global_service temp;
328 
329   memset(&temp, 0, sizeof(temp));
330   temp.timing.min_connection_limit = -1;
331   temp.timing.max_connection_limit = -1;
332   temp.timing.auth_tries = -1;
333   temp.timing.connection_delay = -1;
334   temp.timing.connection_retries = -1;
335   temp.timing.timeout = -1;
336 
337   fp = fopen(filename, "r");
338   if (!fp)
339     fatal("%s: failed to open file %s for reading!", __func__, filename);
340 
341   while (fgets(line, sizeof(line), fp)) {
342     if (*line == '\n' || *line == '#')
343       continue;
344 
345     temp.misc.ssl = false;
346     temp.misc.db = NULL;
347     temp.misc.domain = NULL;
348 
349     if (sscanf(line, "%127s %hu/%15s", servicename, &portno, proto) != 3)
350       fatal("invalid ncrack-services file: %s", filename);
351 
352     temp.lookup.portno = portno;
353     temp.lookup.proto = str2proto(proto);
354     temp.lookup.name = strdup(servicename);
355     /*
356      * When more ssl-services are going to be added, this will probably
357      * need a more generic scheme
358      */
359     if (!strncmp(servicename, "https", sizeof("https"))
360       || !strncmp(servicename, "pop3s", sizeof("pop3s"))
361       || !strncmp(servicename, "owa", sizeof("owa"))
362       || !strncmp(servicename, "wordpress-tls", sizeof("wordpress-tls"))
363       || !strncmp(servicename, "wp-tls", sizeof("wp-tls")))
364       temp.misc.ssl = true;
365 
366     if (!strncmp(servicename, "mongodb", sizeof("mongodb")))
367         temp.misc.db = Strndup("admin", sizeof("admin"));
368 
369     if (!strncmp(servicename, "winrm", sizeof("winrm")))
370         temp.misc.domain = Strndup("Workstation", sizeof("Workstation"));
371 
372     for (vi = ServicesTable.begin(); vi != ServicesTable.end(); vi++) {
373       if ((vi->lookup.portno == temp.lookup.portno)
374           && (vi->lookup.proto == temp.lookup.proto)
375           && !(strcmp(vi->lookup.name, temp.lookup.name))) {
376         if (o.debugging)
377           error("Port %d proto %s is duplicated in services file %s",
378               portno, proto, filename);
379         continue;
380       }
381     }
382 
383     ServicesTable.push_back(temp);
384   }
385 
386   fclose(fp);
387 }
388 
389 
390 /* Returns one if the file pathname given exists, is not a directory and
391  * is readable by the executing process.  Returns two if it is readable
392  * and is a directory.  Otherwise returns 0.
393  */
394 static int
file_readable(const char * pathname)395 file_readable(const char *pathname) {
396   char *pathname_buf = strdup(pathname);
397   int status = 0;
398 
399 #ifdef WIN32
400   /* stat on windows only works for "dir_name" not for "dir_name/"
401    * or "dir_name\\"
402    */
403   int pathname_len = strlen(pathname_buf);
404   char last_char = pathname_buf[pathname_len - 1];
405 
406   if( last_char == '/'
407     || last_char == '\\')
408     pathname_buf[pathname_len - 1] = '\0';
409 
410 #endif
411 
412   struct stat st;
413 
414   if (stat(pathname_buf, &st) == -1)
415     status = 0;
416   else if (access(pathname_buf, R_OK) != -1)
417     status = S_ISDIR(st.st_mode) ? 2 : 1;
418 
419   free(pathname_buf);
420   return status;
421 }
422 
423 /*
424  * useroption should be 1 if either -U or -P has been specified.
425  * by default it is 0
426  */
427 int
ncrack_fetchfile(char * filename_returned,int bufferlen,const char * file,int useroption)428 ncrack_fetchfile(char *filename_returned, int bufferlen, const char *file,
429     int useroption) {
430   char *dirptr;
431   int res;
432   int foundsomething = 0;
433   struct passwd *pw;
434   static int warningcount = 0;
435   char dot_buffer[512];
436 
437   /* -U or -P has been specified */
438   if (useroption) {
439     res = Snprintf(filename_returned, bufferlen, "%s", file);
440     if (res > 0 && res < bufferlen) {
441       foundsomething = file_readable(filename_returned);
442     }
443   }
444 
445 
446   /* First, check the map of requested data file names. If there's an entry for
447      file, use it and return.
448      Otherwise, we try [--datadir]/file, then $NCRACKDIR/file
449      next we try ~user/.ncrack/file
450      then we try NCRACKDATADIR/file <--NCRACKDATADIR
451      finally we try ./file
452 
453      -- or on Windows --
454 
455      --datadir -> $NCRACKDIR -> ncrack.exe directory -> NCRACKDATADIR -> .
456   */
457 
458   if (o.datadir && !foundsomething) {
459     res = Snprintf(filename_returned, bufferlen, "%s/%s", o.datadir, file);
460     if (res > 0 && res < bufferlen) {
461       foundsomething = file_readable(filename_returned);
462     }
463   }
464 
465   if (!foundsomething && (dirptr = getenv("NCRACKDIR"))) {
466     res = Snprintf(filename_returned, bufferlen, "%s/%s", dirptr, file);
467     if (res > 0 && res < bufferlen) {
468       foundsomething = file_readable(filename_returned);
469     }
470   }
471 
472 #ifndef WIN32
473   if (!foundsomething) {
474     pw = getpwuid(getuid());
475     if (pw) {
476       res = Snprintf(filename_returned, bufferlen, "%s/.ncrack/%s",
477           pw->pw_dir, file);
478       if (res > 0 && res < bufferlen) {
479         foundsomething = file_readable(filename_returned);
480       }
481     }
482     if (!foundsomething && getuid() != geteuid()) {
483       pw = getpwuid(geteuid());
484       if (pw) {
485         res = Snprintf(filename_returned, bufferlen, "%s/.ncrack/%s",
486             pw->pw_dir, file);
487         if (res > 0 && res < bufferlen) {
488           foundsomething = file_readable(filename_returned);
489         }
490       }
491     }
492   }
493 #else
494   if (!foundsomething) { /* Try the Ncrack directory */
495     char fnbuf[MAX_PATH];
496     int i;
497     res = GetModuleFileName(GetModuleHandle(0), fnbuf, 1024);
498     if(!res) fatal("GetModuleFileName failed (!)\n");
499 
500     /*  Strip it */
501     for(i = res - 1; i >= 0 && fnbuf[i] != '/' && fnbuf[i] != '\\'; i--);
502     if(i >= 0) /* we found it */
503       fnbuf[i] = 0;
504     res = Snprintf(filename_returned, bufferlen, "%s\\%s", fnbuf, file);
505     if(res > 0 && res < bufferlen)
506       foundsomething = file_readable(filename_returned);
507 
508     /* Now try under 'lists' for the installed directory */
509     if (!foundsomething) {
510     res = Snprintf(filename_returned, bufferlen, "%s\\lists\\%s", fnbuf, file);
511     if(res > 0 && res < bufferlen)
512       foundsomething = file_readable(filename_returned);
513     }
514   }
515 #endif
516 
517   if (!foundsomething) {
518     res = Snprintf(filename_returned, bufferlen, "%s/%s", NCRACKDATADIR, file);
519     if (res > 0 && res < bufferlen) {
520       foundsomething = file_readable(filename_returned);
521     }
522   }
523 
524   if (foundsomething && (*filename_returned != '.') && !useroption) {
525     res = Snprintf(dot_buffer, sizeof(dot_buffer), "./%s", file);
526     if (res > 0 && res < bufferlen) {
527       if (file_readable(dot_buffer)) {
528 #ifdef WIN32
529         if (warningcount++ < 1 && o.debugging)
530 #else
531           if(warningcount++ < 1)
532 #endif
533             error("Warning: File %s exists, but Ncrack is using %s for "
534                 "security and consistency reasons. Set NCRACKDIR=. to give "
535                 "priority to files in your local directory (may affect the "
536                 "other data files too).", dot_buffer, filename_returned);
537       }
538     }
539   }
540 
541   if (!foundsomething) {
542     res = Snprintf(filename_returned, bufferlen, "./%s", file);
543     if (res > 0 && res < bufferlen)
544       foundsomething = file_readable(filename_returned);
545   }
546 
547   /* For username/password lists also search ./lists */
548   if (!foundsomething) {
549     res = Snprintf(filename_returned, bufferlen, "./lists/%s", file);
550     if (res > 0 && res < bufferlen)
551       foundsomething = file_readable(filename_returned);
552   }
553 
554   if (!foundsomething) {
555     Snprintf(filename_returned, bufferlen, "%s", file);
556   }
557 
558   if (foundsomething && o.debugging > 1)
559     log_write(LOG_PLAIN, "Fetchfile found %s\n", filename_returned);
560 
561   return foundsomething;
562 
563 }
564 
565 /*
566  * The only thing that a safe and generic signal handler should do, is to set a
567  * flag that will be later checked by the main program. Ncrack will
568  * periodically check this variable, and take appropriate action to exit
569  * cleanly and also possibly save the current state into a file that can be
570  * used later with --resume.
571  */
572 static void
sigcatch(int signo)573 sigcatch(int signo)
574 {
575   o.saved_signal = signo;
576   return;
577 }
578 
579 static void
sigcheck(ServiceGroup * SG)580 sigcheck(ServiceGroup *SG)
581 {
582   if (o.saved_signal == -1)
583     return;
584 
585   fflush(stdout);
586   switch (o.saved_signal) {
587     case SIGINT:
588       error("caught SIGINT signal, cleaning up");
589       break;
590 
591 #ifdef SIGTERM
592     case SIGTERM:
593       error("caught SIGTERM signal, cleaning up");
594       break;
595 #endif
596 
597 #ifdef SIGHUP
598     case SIGHUP:
599       error("caught SIGHUP signal, cleaning up");
600       break;
601 #endif
602 
603 #ifdef SIGBUS
604     case SIGBUS:
605       error("caught SIGBUS signal, cleaning up");
606       break;
607 #endif
608 
609     default:
610       error("caught signal %d, cleaning up", o.saved_signal);
611       break;
612   }
613 
614   log_close(LOG_NORMAL);
615   /* Now try and save available information into a file that might be later
616    * recalled with --resume.
617    */
618   ncrack_save(SG);
619 
620   exit(1);
621 }
622 
623 
624 static char *
grab_next_host_spec(FILE * inputfd,int argc,char ** argv)625 grab_next_host_spec(FILE *inputfd, int argc, char **argv)
626 {
627   static char host_spec[1024];
628   unsigned int host_spec_index;
629   int ch;
630 
631   if (!inputfd) {
632     return ((optind < argc) ? argv[optind++] : NULL);
633   } else {
634     if (o.nmap_input_xml) {
635       if (xml_input(inputfd, host_spec) < 0)
636         return NULL;
637     } else if (o.nmap_input_normal) {
638       if (normal_input(inputfd, host_spec) < 0)
639         return NULL;
640     } else {
641       host_spec_index = 0;
642       while((ch = getc(inputfd)) != EOF) {
643         if (ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t' || ch == '\0') {
644           if (host_spec_index == 0)
645             continue;
646           host_spec[host_spec_index] = '\0';
647           return host_spec;
648         } else if (host_spec_index < sizeof(host_spec) / sizeof(char) -1) {
649           host_spec[host_spec_index++] = (char) ch;
650         } else fatal("One of the host_specifications from your input file "
651             "is too long (> %d chars)", (int) sizeof(host_spec));
652       }
653       host_spec[host_spec_index] = '\0';
654     }
655   }
656   if (!*host_spec)
657     return NULL;
658   return host_spec;
659 }
660 
661 
662 /*
663  * Parses the username and password list that has been specified from the
664  * command line through the --user and --pass options. The argument must be a
665  * comma separated list of words for each case.
666  */
667 static void
parse_login_list(char * const arg,int mode)668 parse_login_list(char *const arg, int mode)
669 {
670   vector <char *> *p = NULL;
671   size_t i, j, arg_len;
672   char *word;
673 
674   if (mode == USER)
675     p = &UserArray;
676   else if (mode == PASS)
677     p = &PassArray;
678   else
679     fatal("%s invalid mode specified!", __func__);
680 
681   arg_len = strlen(arg);
682   j = i = 0;
683   while (i < arg_len) {
684     if (arg[i] == ',') {
685       word = Strndup(&arg[j], i - j);
686       p->push_back(word);
687       j = i + 1;
688     }
689 
690     i++;
691  }
692 
693   /* In case, user just typed --user "," or --pass "," don't add two blank
694    * passwords as there is no point in that.
695    */
696   if (arg[0] == ',' && arg_len == 1)
697     return;
698 
699   word = Strndup(&arg[j], i - j);
700   p->push_back(word);
701 
702 }
703 
704 
705 static void
load_login_file(const char * filename,int mode)706 load_login_file(const char *filename, int mode)
707 {
708   char line[1024];
709   char *tmp;
710   FILE *fd;
711   vector <char *> *p = NULL;
712 
713   if (!strcmp(filename, "-"))
714     fd = stdin;
715   else {
716     fd = fopen(filename, "r");
717     if (!fd)
718       fatal("Failed to open input file %s for reading!", filename);
719   }
720 
721   if (mode == USER)
722     p = &UserArray;
723   else if (mode == PASS)
724     p = &PassArray;
725   else
726     fatal("%s invalid mode specified!", __func__);
727 
728   while (fgets(line, sizeof(line), fd)) {
729     /* Note that supporting comment lines starting with '#' automatically
730      * entails not being able to get passwords that start with '#'.
731      */
732     if (*line == '#')
733       continue;
734 
735     /* A blank line (just the '\n' char) in a wordlist file means that a
736      * blank entry will be tested. Strndup allocates an entry that is at least
737      * of 1 size ('\0'), so supplying it with the length of each line minus the
738      * '\n' character of the line will universally work in all cases.
739      * However, we need to take into account the possibility that the user
740      * supplies Windows-derived wordlists which use CRLF termination.
741      * In that case, just drop the 1 extra character.
742      */
743     if (strlen(line) == 2 && !strncmp(line, "\r\n", 2))
744       line[1] = '\0';
745 
746     tmp = Strndup(line, strlen(line) - 1);
747     p->push_back(tmp);
748   }
749 }
750 
751 
752 
753 static void
call_module(nsock_pool nsp,Connection * con)754 call_module(nsock_pool nsp, Connection *con)
755 {
756   char *name = con->service->name;
757 
758   /* initialize connection state variables */
759   con->auth_success = false;
760   con->check_closed = false;
761   con->auth_complete = false;
762   con->peer_alive = false;
763   con->finished_normally = false;
764   con->close_reason = -1;
765   con->force_close = false;
766 
767 
768   if (!strcmp(name, "ftp"))
769     ncrack_ftp(nsp, con);
770   else if (!strcmp(name, "telnet"))
771     ncrack_telnet(nsp, con);
772   else if (!strcmp(name, "http"))
773     ncrack_http(nsp, con);
774   else if (!strcmp(name, "pop3"))
775     ncrack_pop3(nsp, con);
776   else if (!strcmp(name, "vnc"))
777     ncrack_vnc(nsp, con);
778   else if (!strcmp(name, "redis"))
779     ncrack_redis(nsp, con);
780   else if (!strcmp(name, "mqtt"))
781     ncrack_mqtt(nsp, con);
782   else if (!strcmp(name, "imap"))
783     ncrack_imap(nsp, con);
784   else if (!strcmp(name, "cassandra"))
785     ncrack_cassandra(nsp, con);
786   else if (!strcmp(name,"cvs"))
787     ncrack_cvs(nsp,con);
788   else if (!strcmp(name, "joomla"))
789     ncrack_joomla(nsp, con);
790   else if (!strcmp(name, "dicom"))
791     ncrack_dicom(nsp, con);
792   else if (!strcmp(name, "wordpress") || !strcmp(name, "wp"))
793     ncrack_wordpress(nsp, con);
794 #if HAVE_OPENSSL
795   else if (!strcmp(name, "wordpress-tls") || !strcmp(name, "wp-tls"))
796     ncrack_wordpress(nsp, con);
797   else if (!strcmp(name, "winrm"))
798     ncrack_winrm(nsp, con);
799   else if (!strcmp(name, "mongodb"))
800     ncrack_mongodb(nsp, con);
801   else if (!strcmp(name, "pop3s"))
802     ncrack_pop3(nsp, con);
803   else if (!strcmp(name, "mysql"))
804     ncrack_mysql(nsp, con);
805   else if (!strcmp(name, "psql"))
806     ncrack_psql(nsp, con);
807   else if (!strcmp(name, "mssql"))
808     ncrack_mssql(nsp, con);
809   else if (!strcmp(name, "ssh"))
810     ncrack_ssh(nsp, con);
811   else if (!strcmp(name, "owa"))
812     ncrack_owa(nsp, con);
813   else if (!strcmp(name, "https"))
814     ncrack_http(nsp, con);
815   else if (!strcmp(name, "sip"))
816     ncrack_sip(nsp, con);
817   else if (!strcmp(name, "rdp") || !strcmp(name, "ms-wbt-server"))
818     ncrack_rdp(nsp, con);
819   else if (!strcmp(name, "smb") || !strcmp(name, "netbios-ssn"))
820     ncrack_smb(nsp, con);
821   else if (!strcmp(name, "smb2"))
822     ncrack_smb2(nsp, con);
823 
824 #endif
825   else
826     fatal("Invalid service module: %s", name);
827 }
828 
829 
830 int
main(int argc,char ** argv)831 main(int argc, char **argv)
832 {
833   char **myargv = NULL;
834   int myargc = 0;
835 
836   if (argc == 3 && strcmp("--resume", argv[1]) == 0) {
837     if (ncrack_resume(argv[2], &myargc, &myargv) == -1) {
838       fatal("Cannot resume from (supposed) log file %s", argv[2]);
839     }
840     o.resume = true;
841     return ncrack_main(myargc, myargv);
842   }
843 
844   return ncrack_main(argc, argv);
845 }
846 
847 
848 
849 
850 static int
ncrack_main(int argc,char ** argv)851 ncrack_main(int argc, char **argv)
852 {
853   ts_spec spec;
854 
855   FILE *inputfd = NULL;
856   char *normalfilename = NULL;
857   char *xmlfilename = NULL;
858   time_t timep;
859   unsigned int i; /* iteration var */
860   char services_file[256]; /* path name for "ncrack-services" file */
861   char username_file[256];
862   char password_file[256];
863   /* strtok changes the first argument and we don't want to mess with
864    * the argv stuff, as they hold important info for later. For this reason,
865    * we copy optarg to tmp each time a function that calls strtok is going to
866    * be invoked.
867    */
868   char *tmp = NULL;
869 
870   char *host_spec = NULL;
871   Target *currenths = NULL;
872   vector <Target *> Targets;        /* targets to be ncracked */
873   vector <Target *>::iterator Tvi;
874 
875   ServiceGroup *SG;                 /* all services to be ncracked */
876   list <Service *>::iterator li;
877 
878   vector <Service *>Services;       /* temporary services vector */
879   vector <Service *>::iterator Svi; /* iterator for services vector */
880   Service *service;
881 
882   vector <service_lookup *> services_cmd;
883   vector <service_lookup *>::iterator SCvi;
884 
885   char *glob_options = NULL;  /* for -g option */
886   timing_options timing;      /* for -T option */
887 
888   /* time variables */
889   struct tm *tm;
890   time_t now;
891   char tbuf[128];
892   char mytime[128];
893 
894   /* exclude-specific variables */
895   FILE *excludefd = NULL;
896   char *exclude_spec = NULL;
897   TargetGroup *exclude_group = NULL;
898 
899 
900   /* getopt-specific */
901   int arg;
902   int option_index;
903   extern char *optarg;
904   extern int optind;
905   struct option long_options[] =
906   {
907     {"resume", required_argument, 0, 0},
908     {"save", required_argument, 0, 0},
909     {"list", no_argument, 0, 0},
910     {"services", required_argument, 0, 'p'},
911     {"version", no_argument, 0, 'V'},
912     {"verbose", no_argument, 0, 'v'},
913     {"datadir", required_argument, 0, 0},
914     {"debug", optional_argument, 0, 'd'},
915     {"help", no_argument, 0, 'h'},
916     {"timing", required_argument, 0, 'T'},
917     {"excludefile", required_argument, 0, 0},
918     {"exclude", required_argument, 0, 0},
919     {"iL", required_argument, 0, 0},
920     {"iX", required_argument, 0, 0},
921     {"iN", required_argument, 0, 0},
922     {"oA", required_argument, 0, 0},
923     {"oN", required_argument, 0, 0},
924     {"oX", required_argument, 0, 0},
925     {"append_output", no_argument, 0, 0},
926     {"append-output", no_argument, 0, 0},
927     {"log_errors", no_argument, 0, 0},
928     {"log-errors", no_argument, 0, 0},
929     {"stealthy_linear", no_argument, 0, 0},
930     {"stealthy-linear", no_argument, 0, 0},
931     {"connection_limit", required_argument, 0, 0},
932     {"connection-limit", required_argument, 0, 0},
933     {"passwords_first", no_argument, 0, 0},
934     {"passwords-first", no_argument, 0, 0},
935     {"pairwise", no_argument, 0, 0},
936     {"user", required_argument, 0, 0},
937     {"pass", required_argument, 0, 0},
938     {"nsock-trace", required_argument, 0, 0},
939     {"nsock_trace", required_argument, 0, 0},
940     {"proxy", required_argument, 0, 0},
941     {"proxies", required_argument, 0, 0},
942     {0, 0, 0, 0}
943   };
944 
945   if (argc < 2)
946     print_usage();
947 
948   ncrack_fetchfile(services_file, sizeof(services_file), "ncrack-services");
949   /* Initialize available services' lookup table */
950   lookup_init(services_file);
951 
952 #if WIN32
953   win_init();
954 #endif
955 
956 
957   now = time(NULL);
958   tm = localtime(&now);
959 
960   /* Argument parsing */
961   optind = 1;
962   while((arg = getopt_long_only(argc, argv, "6d::f::g:hU:P:m:o:p:s:T:v::V",
963           long_options, &option_index)) != EOF) {
964     switch(arg) {
965       case 0:
966         if (!strcmp(long_options[option_index].name, "excludefile")) {
967           if (exclude_spec)
968             fatal("--excludefile and --exclude options are mutually "
969                 "exclusive.");
970           excludefd = fopen(optarg, "r");
971           if (!excludefd)
972             fatal("Failed to open exclude file %s for reading", optarg);
973         } else if (!strcmp(long_options[option_index].name, "exclude")) {
974           if (excludefd)
975             fatal("--excludefile and --exclude options are mutually "
976                 "exclusive.");
977           exclude_spec = strdup(optarg);
978 
979         } else if (!strcmp(long_options[option_index].name, "services")) {
980           parse_services(optarg, services_cmd);
981         } else if (!strcmp(long_options[option_index].name, "list")) {
982           o.list_only = true;
983         } else if (!optcmp(long_options[option_index].name,
984               "connection-limit")) {
985           o.connection_limit = atoi(optarg);
986         } else if (!optcmp(long_options[option_index].name,
987               "passwords-first")) {
988           o.passwords_first = true;
989         } else if (!optcmp(long_options[option_index].name,
990               "pairwise")) {
991           o.pairwise = true;
992         } else if (!optcmp(long_options[option_index].name,
993               "nsock-trace")) {
994           int lvl;
995 
996           lvl = atoi(optarg);
997 
998           if (lvl >= 7)
999             o.nsock_loglevel = NSOCK_LOG_DBG_ALL;
1000           else if (lvl >= 4)
1001             o.nsock_loglevel = NSOCK_LOG_DBG;
1002           else if (lvl >= 2)
1003             o.nsock_loglevel = NSOCK_LOG_INFO;
1004           else
1005             o.nsock_loglevel = NSOCK_LOG_ERROR;
1006         } else if (!optcmp(long_options[option_index].name, "proxy") ||
1007                    !optcmp(long_options[option_index].name, "proxies")) {
1008           if (nsock_proxychain_new(optarg, &o.proxychain, NULL) < 0)
1009             fatal("Invalid proxy chain specification.");
1010           if (strlen(optarg) >= 7 && !(strncmp(optarg, "socks4a", 7)))
1011             o.socks4a = true;
1012         } else if (!optcmp(long_options[option_index].name, "log-errors")) {
1013           o.log_errors = true;
1014         } else if (!optcmp(long_options[option_index].name, "stealthy-linear")) {
1015           o.stealthy_linear = true;
1016         } else if (!optcmp(long_options[option_index].name, "append-output")) {
1017           o.append_output = true;
1018         } else if (strcmp(long_options[option_index].name, "datadir") == 0) {
1019           o.datadir = strdup(optarg);
1020         } else if (strcmp(long_options[option_index].name, "iX") == 0) {
1021           if (inputfd)
1022             fatal("Only one input filename allowed");
1023           o.nmap_input_xml = true;
1024           inputfd = fopen(strdup(optarg), "r");
1025           if (!inputfd)
1026             fatal("Failed to open input file %s for reading", optarg);
1027         } else if (strcmp(long_options[option_index].name, "iN") == 0) {
1028           if (inputfd)
1029             fatal("Only one input filename allowed");
1030           o.nmap_input_normal = true;
1031           inputfd = fopen(strdup(optarg), "r");
1032           if (!inputfd)
1033             fatal("Failed to open input file %s for reading", optarg);
1034         } else if (strcmp(long_options[option_index].name, "iL") == 0) {
1035           if (inputfd)
1036             fatal("Only one input filename allowed");
1037           inputfd = fopen(strdup(optarg), "r");
1038           if (!inputfd)
1039             fatal("Failed to open input file %s for reading", optarg);
1040         } else if (strcmp(long_options[option_index].name, "oN") == 0) {
1041           normalfilename = logfilename(optarg, tm);
1042         } else if (strcmp(long_options[option_index].name, "oX") == 0) {
1043           xmlfilename = logfilename(optarg, tm);
1044         } else if (strcmp(long_options[option_index].name, "oA") == 0) {
1045           char buf[MAXPATHLEN];
1046           Snprintf(buf, sizeof(buf), "%s.ncrack", logfilename(optarg, tm));
1047           normalfilename = strdup(buf);
1048           Snprintf(buf, sizeof(buf), "%s.xml", logfilename(optarg, tm));
1049           xmlfilename = strdup(buf);
1050         } else if (strcmp(long_options[option_index].name, "user") == 0) {
1051           if (o.userlist_src)
1052             fatal("You have already specified the username list source!\n");
1053           o.userlist_src = 1;
1054 
1055           tmp = Strndup(optarg, strlen(optarg));
1056           parse_login_list(tmp, USER);
1057           free(tmp);
1058         } else if (strcmp(long_options[option_index].name, "pass") == 0) {
1059           if (o.passlist_src)
1060             fatal("You have already specified the password list source!\n");
1061           o.passlist_src = 1;
1062           tmp = Strndup(optarg, strlen(optarg));
1063           parse_login_list(tmp, PASS);
1064           free(tmp);
1065         } else if (strcmp(long_options[option_index].name, "resume") == 0) {
1066           fatal("--resume <file> can only be used as sole command-line "
1067               "option to Ncrack! Invoke Ncrack without any other "
1068               "arguments.\n");
1069         } else if (strcmp(long_options[option_index].name, "vv") == 0) {
1070           /* Compatability hack ... ugly */
1071           o.verbose += 2;
1072         } else if (strcmp(long_options[option_index].name, "save") == 0) {
1073           o.save_file = logfilename(optarg, tm);
1074         }
1075         break;
1076       case '6':
1077 #if !HAVE_IPV6
1078         fatal("I am afraid IPv6 is not available because your host doesn't "
1079             "support it or you chose to compile Ncrack w/o IPv6 support.");
1080 #else
1081         o.setaf(AF_INET6);
1082 #endif /* !HAVE_IPV6 */
1083         break;
1084       case 'd':
1085         if (optarg && isdigit(optarg[0])) {
1086           o.debugging = o.verbose = atoi(optarg);
1087         } else {
1088           const char *p;
1089           o.debugging++;
1090           o.verbose++;
1091           for (p = optarg != NULL ? optarg : ""; *p == 'd'; p++) {
1092             o.debugging++;
1093             o.verbose++;
1094           }
1095           if (*p != '\0')
1096             fatal("Invalid argument to -d: \"%s\".", optarg);
1097         }
1098         break;
1099       case 'f':
1100         if (optarg && isdigit(optarg[0])) {
1101           o.finish = atoi(optarg);
1102         } else {
1103           const char *p;
1104           o.finish++;
1105           for (p = optarg != NULL ? optarg : ""; *p == 'd'; p++) {
1106             o.finish++;
1107           }
1108           if (*p != '\0')
1109             fatal("Invalid argument to -f: \"%s\".", optarg);
1110         }
1111         break;
1112       case 'g':
1113         glob_options = strdup(optarg);
1114         o.global_options = true;
1115         break;
1116       case 'h':   /* help */
1117         print_usage();
1118         break;
1119 #if 0
1120       case 'i':
1121         if (inputfd)
1122           fatal("Only one input filename allowed");
1123         if (!strcmp(optarg, "-"))
1124           inputfd = stdin;
1125         else
1126           fatal("You have to specify a specific input format for -i option: "
1127               "-iL, -iN or -iX\n");
1128         break;
1129 #endif
1130       case 'U':
1131         if (o.userlist_src)
1132           fatal("You have already specified the username list source!\n");
1133         o.userlist_src = 2;
1134         ncrack_fetchfile(username_file, sizeof(username_file),
1135             optarg, 1);
1136         load_login_file(username_file, USER);
1137         break;
1138       case 'P':
1139         if (o.passlist_src)
1140           fatal("You have already specified the password list source!\n");
1141         o.passlist_src = 2;
1142         ncrack_fetchfile(password_file, sizeof(password_file),
1143             optarg, 1);
1144         load_login_file(password_file, PASS);
1145         break;
1146       case 'm':
1147         tmp = Strndup(optarg, strlen(optarg));
1148         parse_module_options(tmp);
1149         free(tmp);
1150         break;
1151       case 'o':
1152         normalfilename = logfilename(optarg, tm);
1153         break;
1154       case 'p':   /* services */
1155         tmp = Strndup(optarg, strlen(optarg));
1156         parse_services(tmp, services_cmd);
1157         free(tmp);
1158         break;
1159       case 's': /* only list hosts */
1160         if (*optarg == 'L')
1161           o.list_only = true;
1162         else
1163           fatal("Illegal argument for option '-s' Did you mean -sL?");
1164         break;
1165       case 'T': /* timing template */
1166         if (*optarg == '0' || (strcasecmp(optarg, "Paranoid") == 0)) {
1167           o.timing_level = 0;
1168         } else if (*optarg == '1' || (strcasecmp(optarg, "Sneaky") == 0)) {
1169           o.timing_level = 1;
1170         } else if (*optarg == '2' || (strcasecmp(optarg, "Polite") == 0)) {
1171           o.timing_level = 2;
1172         } else if (*optarg == '3' || (strcasecmp(optarg, "Normal") == 0)) {
1173           o.timing_level = 3;
1174         } else if (*optarg == '4' || (strcasecmp(optarg, "Aggressive") == 0)) {
1175           o.timing_level = 4;
1176         } else if (*optarg == '5' || (strcasecmp(optarg, "Insane") == 0)) {
1177           o.timing_level = 5;
1178         } else {
1179           fatal("Unknown timing mode (-T argument). Use either \"Paranoid\", "
1180               "\"Sneaky\", \"Polite\", \"Normal\", \"Aggressive\", "
1181               "\"Insane\" or a number from 0 (Paranoid) to 5 (Insane)");
1182         }
1183         break;
1184       case 'V':
1185         log_write(LOG_STDOUT, "\n%s version %s ( %s )\n",
1186             NCRACK_NAME, NCRACK_VERSION, NCRACK_URL);
1187         log_write(LOG_STDOUT, "Modules: SSH, RDP, FTP, Telnet, HTTP(S), Wordpress, POP3(S), IMAP, CVS, "
1188             "SMB, VNC, SIP, Redis, PostgreSQL, MQTT, MySQL, MSSQL, MongoDB, Cassandra, WinRM, OWA, DICOM\n");
1189         exit(EXIT_SUCCESS);
1190         break;
1191       case 'v':
1192         if (optarg && isdigit(optarg[0])) {
1193           o.verbose = atoi(optarg);
1194         } else {
1195           const char *p;
1196           o.verbose++;
1197           for (p = optarg != NULL ? optarg : ""; *p == 'v'; p++)
1198             o.verbose++;
1199           if (*p != '\0')
1200             fatal("Invalid argument to -v: \"%s\".", optarg);
1201         }
1202         break;
1203       case '?':   /* error */
1204         print_usage();
1205     }
1206   }
1207 
1208   /* Initialize tty for interactive output */
1209   tty_init();
1210 
1211   /* Open the log files, now that we know whether the user wants them appended
1212      or overwritten */
1213   if (normalfilename) {
1214     log_open(LOG_NORMAL, normalfilename);
1215     free(normalfilename);
1216   }
1217   if (xmlfilename) {
1218     log_open(LOG_XML, xmlfilename);
1219     free(xmlfilename);
1220   }
1221 
1222   if (UserArray.empty()) {
1223     ncrack_fetchfile(username_file, sizeof(username_file),
1224         DEFAULT_USERNAME_FILE);
1225     load_login_file(username_file, USER);
1226   }
1227   if (PassArray.empty()) {
1228     ncrack_fetchfile(password_file, sizeof(password_file),
1229         DEFAULT_PASSWORD_FILE);
1230     load_login_file(password_file, PASS);
1231   }
1232 
1233 
1234   /* Now handle signals */
1235 
1236 #if defined(HAVE_SIGNAL) && defined(SIGPIPE)
1237   signal(SIGPIPE, SIG_IGN);
1238   /* ignore SIGPIPE so our program doesn't crash because
1239    * of it, but we really shouldn't get an unsuspected SIGPIPE
1240    */
1241 #endif
1242 
1243   /* The handler for the rest of the signals will be established after
1244    * ServiceGroup has been initialized, since the saved state that is going to
1245    * be written into the file used for --resume option, requires that
1246    * information. There is no point in catching the signals before, because
1247    * there is no benefit in doing anything special then (can't save the state
1248    * yet that is). The default actions are enough.
1249    */
1250 
1251 
1252   /* Prepare -T option (3 is default) */
1253   prepare_timing_template(&timing);
1254 
1255   if (strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M %Z", tm) <= 0)
1256     fatal("Unable to properly format time");
1257   log_write(LOG_STDOUT, "\nStarting %s %s ( %s ) at %s\n",
1258       NCRACK_NAME, NCRACK_VERSION, NCRACK_URL, tbuf);
1259 
1260 
1261   /* lets load our exclude list */
1262   if ((NULL != excludefd) || (NULL != exclude_spec)) {
1263     exclude_group = load_exclude(excludefd, exclude_spec);
1264 
1265     if (o.debugging > 3)
1266       dumpExclude(exclude_group);
1267 
1268     if ((FILE *)NULL != excludefd)
1269       fclose(excludefd);
1270     if ((char *)NULL != exclude_spec)
1271       free(exclude_spec);
1272   }
1273 
1274   /* Brief info incase they forget what was scanned */
1275   timep = time(NULL);
1276   Strncpy(mytime, ctime(&now), sizeof(mytime));
1277   chomp(mytime);
1278 
1279   //char *xslfname = o.XSLStyleSheet();
1280   char *xslfname = NULL; // no stylesheet for now
1281 
1282   xml_start_document("ncrackrun");
1283   if (xslfname) {
1284     xml_open_pi("xml-stylesheet");
1285     xml_attribute("href", "%s", xslfname);
1286     xml_attribute("type", "text/xsl");
1287     xml_close_pi();
1288     xml_newline();
1289   }
1290 
1291   xml_start_comment();
1292   xml_write_escaped(" %s %s scan initiated %s as: %s ", NCRACK_NAME, NCRACK_VERSION, mytime, join_quoted(argv, argc).c_str());
1293   xml_end_comment();
1294   xml_newline();
1295 
1296   xml_open_start_tag("ncrackrun");
1297   xml_attribute("scanner", "ncrack");
1298   xml_attribute("args", "%s", join_quoted(argv, argc).c_str());
1299   xml_attribute("start", "%lu", (unsigned long) timep);
1300   xml_attribute("startstr", "%s", mytime);
1301   xml_attribute("version", "%s", NCRACK_VERSION);
1302   xml_attribute("xmloutputversion", NCRACK_XMLOUTPUTVERSION);
1303   xml_close_start_tag();
1304   xml_newline();
1305 
1306   xml_open_start_tag("verbose");
1307   xml_attribute("level", "%d", o.verbose);
1308   xml_close_empty_tag();
1309   xml_newline();
1310   xml_open_start_tag("debugging");
1311   xml_attribute("level", "%d", o.debugging);
1312   xml_close_empty_tag();
1313   xml_newline();
1314 
1315   std::string command;
1316   if (argc > 0)
1317     command += argv[0];
1318   for (i = 1; i < (unsigned int)argc; i++) {
1319     command += " ";
1320     command += argv[i];
1321   }
1322 
1323   log_write(LOG_NORMAL, "# ");
1324   log_write(LOG_NORMAL, "%s %s scan initiated %s as: ", NCRACK_NAME, NCRACK_VERSION, mytime);
1325   log_write(LOG_NORMAL, "%s", command.c_str());
1326   log_write(LOG_NORMAL, "\n");
1327 
1328   /*
1329    * These will later be used by ncrack_save() to write the way Ncrack was
1330    * called to the restore file.
1331    */
1332   o.saved_argv = argv;
1333   o.saved_argc = argc;
1334 
1335 
1336   SG = new ServiceGroup();
1337   SG->connection_limit = o.connection_limit;
1338 
1339 
1340   while ((host_spec = grab_next_host_spec(inputfd, argc, argv))) {
1341 
1342     /* preparse and separate host - service */
1343     spec = parse_services_target(host_spec);
1344     if (spec.error)
1345       continue;
1346 
1347     // log_write(LOG_STDOUT,"%s://%s:%s?%s\n",spec.service_name,
1348     // spec.host_expr, spec.portno, spec.service_options);
1349 
1350     if (spec.service_name) {
1351       service = new Service();
1352       service->name = strdup(spec.service_name);
1353       service->UserArray = &UserArray;
1354       service->PassArray = &PassArray;
1355       Services.push_back(service);
1356     } else {  /* -p option */
1357       for (SCvi = services_cmd.begin(); SCvi != services_cmd.end(); SCvi++) {
1358         service = new Service();
1359         service->name = (*SCvi)->name;
1360         service->portno = (*SCvi)->portno;
1361         service->proto = (*SCvi)->proto;
1362         service->UserArray = &UserArray;
1363         service->PassArray = &PassArray;
1364         Services.push_back(service);
1365       }
1366     }
1367 
1368     Svi = Services.begin();
1369     while (Svi != Services.end()) {
1370       /* first apply timing template */
1371       apply_timing_template(*Svi, &timing);
1372       /* then apply global options -g if they exist */
1373       if (o.global_options)
1374         apply_host_options(*Svi, glob_options);
1375       /* then apply options from ServiceTable (-m option) */
1376       if (apply_service_options(*Svi) < 0) {
1377         /* If service is not supported, remove it from list */
1378         Svi = Services.erase(Svi);
1379       } else
1380         Svi++;
1381     }
1382 
1383     /* finally, if they have been specified, apply options from host */
1384     if (spec.service_options)
1385       apply_host_options(Services[0], spec.service_options);
1386     if (spec.portno)
1387       Services[0]->portno = str2port(spec.portno);
1388 
1389 
1390     while ((currenths = nexthost(spec.host_expr, exclude_group))) {
1391       for (Tvi = Targets.begin(); Tvi != Targets.end(); Tvi++) {
1392         if (!(strcmp((*Tvi)->NameIP(), currenths->NameIP())))
1393           break;
1394       }
1395       if (Tvi == Targets.end())
1396         Targets.push_back(currenths);
1397       else
1398         currenths = *Tvi;
1399 
1400       for (Svi = Services.begin(); Svi != Services.end(); Svi++) {
1401         service = new Service(**Svi);
1402 
1403         service->target = currenths;
1404         /* check for duplicates */
1405         for (li = SG->services_all.begin(); li != SG->services_all.end();
1406             li++) {
1407           if (!strcmp((*li)->target->NameIP(), currenths->NameIP())
1408               && (!strcmp((*li)->name, service->name))
1409               && ((*li)->portno == service->portno))
1410             fatal("Duplicate service %s for target %s !",
1411                 service->name, currenths->NameIP());
1412         }
1413 
1414         /*
1415          * Push service to both 'services_all' (every service resides there)
1416          * and to 'services_active' list (every service starts with
1417          * 1 connection)
1418          */
1419         SG->services_all.push_back(service);
1420         SG->services_active.push_back(service);
1421         SG->total_services++;
1422       }
1423     }
1424     Services.clear();
1425     clean_spec(&spec);
1426   }
1427 
1428   if (o.list_only) {
1429     if (o.debugging) {
1430       log_write(LOG_PLAIN, "----- [ Timing Template ] -----\n");
1431       log_write(LOG_PLAIN, "cl=%ld, CL=%ld, at=%ld, cd=%ld, cr=%ld, to=%lld\n",
1432           timing.min_connection_limit, timing.max_connection_limit,
1433           timing.auth_tries, timing.connection_delay,
1434           timing.connection_retries, timing.timeout);
1435 
1436       log_write(LOG_PLAIN, "\n----- [ ServicesTable ] -----\n");
1437 
1438       int colno = 0;
1439       int col_port = colno++;
1440       int col_cl = colno++;
1441       int col_CL = colno++;
1442       int col_at = colno++;
1443       int col_cd = colno++;
1444       int col_cr = colno++;
1445       int col_to = colno++;
1446       int col_ssl = colno++;
1447       int col_path = colno++;
1448       int col_db = colno++;
1449       int col_domain = colno++;
1450       int numrows = ServicesTable.size() + 1;
1451       NcrackOutputTable *Tbl = new NcrackOutputTable(numrows, colno);
1452 
1453       Tbl->addItem(0, col_port, false, "SERVICE", sizeof("SERVICE") - 1);
1454       Tbl->addItem(0, col_cl, false, "cl", sizeof("cl") - 1);
1455       Tbl->addItem(0, col_CL, false, "CL", sizeof("CL") - 1);
1456       Tbl->addItem(0, col_at, false, "at", sizeof("at") - 1);
1457       Tbl->addItem(0, col_cd, false, "cd", sizeof("cd") - 1);
1458       Tbl->addItem(0, col_cr, false, "cr", sizeof("cr") - 1);
1459       Tbl->addItem(0, col_to, false, "to", sizeof("to") - 1);
1460       Tbl->addItem(0, col_ssl, false, "ssl", sizeof("ssl") - 1);
1461       Tbl->addItem(0, col_path, false, "path", sizeof("path") - 1);
1462       Tbl->addItem(0, col_db, false, "db", sizeof("db") - 1);
1463       Tbl->addItem(0, col_domain, false, "domain", sizeof("domain") - 1);
1464 
1465       int rowno = 1;
1466 
1467       for (i = 0; i < ServicesTable.size(); i++) {
1468 
1469         Tbl->addItemFormatted(rowno, col_port, false, "%s:%hu",
1470             ServicesTable[i].lookup.name, ServicesTable[i].lookup.portno);
1471 
1472         if (ServicesTable[i].timing.min_connection_limit != NOT_ASSIGNED)
1473           Tbl->addItemFormatted(rowno, col_cl, false, "%ld",
1474               ServicesTable[i].timing.min_connection_limit);
1475         else
1476           Tbl->addItem(rowno, col_cl, false, "N/A");
1477 
1478         if (ServicesTable[i].timing.max_connection_limit != NOT_ASSIGNED)
1479           Tbl->addItemFormatted(rowno, col_CL, false, "%ld",
1480               ServicesTable[i].timing.max_connection_limit);
1481         else
1482           Tbl->addItem(rowno, col_CL, false, "N/A");
1483 
1484         if (ServicesTable[i].timing.auth_tries != NOT_ASSIGNED)
1485           Tbl->addItemFormatted(rowno, col_at, false, "%ld",
1486               ServicesTable[i].timing.auth_tries);
1487         else
1488           Tbl->addItem(rowno, col_at, false, "N/A");
1489 
1490         if (ServicesTable[i].timing.connection_delay != NOT_ASSIGNED)
1491           Tbl->addItemFormatted(rowno, col_cd, false, "%ld",
1492               ServicesTable[i].timing.connection_delay);
1493         else
1494           Tbl->addItem(rowno, col_cd, false, "N/A");
1495 
1496         if (ServicesTable[i].timing.connection_retries != NOT_ASSIGNED)
1497           Tbl->addItemFormatted(rowno, col_cr, false, "%ld",
1498               ServicesTable[i].timing.connection_retries);
1499         else
1500           Tbl->addItem(rowno, col_cr, false, "N/A");
1501 
1502         if (ServicesTable[i].timing.timeout != NOT_ASSIGNED)
1503           Tbl->addItemFormatted(rowno, col_to, false, "%ld",
1504               ServicesTable[i].timing.timeout);
1505         else
1506           Tbl->addItem(rowno, col_to, false, "N/A");
1507 
1508         Tbl->addItem(rowno, col_ssl, false,
1509             ServicesTable[i].misc.ssl ? "yes" : "no");
1510 
1511         Tbl->addItem(rowno, col_path, false, ServicesTable[i].misc.path ?
1512             ServicesTable[i].misc.path : "null");
1513 
1514         Tbl->addItem(rowno, col_db, false, ServicesTable[i].misc.db ?
1515             ServicesTable[i].misc.db : "null");
1516 
1517         Tbl->addItem(rowno, col_domain, false, ServicesTable[i].misc.domain ?
1518             ServicesTable[i].misc.domain : "null");
1519 
1520         rowno++;
1521       }
1522       log_write(LOG_PLAIN, "%s", Tbl->printableTable(NULL));
1523       delete Tbl;
1524 
1525     }
1526     log_write(LOG_PLAIN, "\n----- [ Targets ] -----\n");
1527     for (i = 0; i < Targets.size(); i++) {
1528       log_write(LOG_PLAIN, "Host: %s", Targets[i]->NameIP());
1529       if (Targets[i]->targetname)
1530         log_write(LOG_PLAIN, " ( %s ) ", Targets[i]->targetname);
1531       log_write(LOG_PLAIN, "\n");
1532       for (li = SG->services_all.begin(); li != SG->services_all.end(); li++) {
1533         if ((*li)->target == Targets[i])
1534           log_write(LOG_PLAIN, "  %s:%hu cl=%ld, CL=%ld, at=%ld, cd=%ld, "
1535               "cr=%ld, to=%lldms, ssl=%s, path=%s, db=%s, domain=%s\n",
1536               (*li)->name, (*li)->portno, (*li)->min_connection_limit,
1537               (*li)->max_connection_limit, (*li)->auth_tries,
1538               (*li)->connection_delay, (*li)->connection_retries,
1539               (*li)->timeout, (*li)->ssl ? "yes" : "no", (*li)->path,
1540               (*li)->db, (*li)->domain);
1541       }
1542     }
1543   } else {
1544     if (!SG->total_services)
1545       fatal("No services specified!");
1546 
1547     /* If --resume had been specified, it is time to copy the saved session
1548      * info into our ServiceGroup.
1549      */
1550     if (o.resume) {
1551 
1552       map<uint32_t, struct saved_info>::iterator mi;
1553       list <Service *>::iterator li;
1554       vector <loginpair>::iterator vi;
1555 
1556       for (mi = o.resume_map.begin(); mi != o.resume_map.end(); mi++) {
1557 
1558         for (li = SG->services_all.begin(); li != SG->services_all.end();
1559             li++) {
1560           if ((*li)->uid == mi->first)
1561             break;
1562         }
1563 
1564         (*li)->setUserlistIndex(mi->second.user_index);
1565         (*li)->setPasslistIndex(mi->second.pass_index);
1566 
1567         for (vi = mi->second.credentials_found.begin();
1568             vi != mi->second.credentials_found.end(); vi++) {
1569           (*li)->addCredential(vi->user, vi->pass);
1570         }
1571 
1572       }
1573     }
1574 
1575     /* Now is the right time to establish the signal handlers, since
1576      * ServiceGroup has been initialized */
1577 #if HAVE_SIGNAL
1578     signal(SIGINT, sigcatch);
1579     signal(SIGTERM, sigcatch);
1580 #ifndef WIN32
1581     signal(SIGHUP, sigcatch);
1582 #endif
1583 #endif
1584 
1585     if (o.stealthy_linear)
1586       SG->connection_limit = SG->services_all.size();
1587 
1588 
1589     SG->last_accessed = SG->services_active.end();
1590     SG->prev_modified = SG->services_active.end();
1591     /* Ncrack 'em all! */
1592     ncrack(SG);
1593   }
1594 
1595 
1596   log_write(LOG_STDOUT, "\n");
1597   /* Now print the final results for each service
1598    * In addition, check if any of the services timed out so that
1599    * we can save a .restore file in case the user needs to resume the session
1600    * another time.
1601    */
1602   bool save_state = false;
1603   for (li = SG->services_all.begin(); li != SG->services_all.end(); li++) {
1604 
1605      xml_open_start_tag("service");
1606      xml_attribute("starttime", "%lu", (unsigned long) (*li)->StartTime());
1607      xml_attribute("endtime", "%lu", (unsigned long) (*li)->EndTime());
1608      xml_close_start_tag();
1609      xml_newline();
1610 
1611      xml_open_start_tag("address");
1612      xml_attribute("addr", "%s", (*li)->target->NameIP());
1613      xml_attribute("addrtype", "%s", (o.af() == AF_INET) ? "ipv4" : "ipv6");
1614      xml_close_empty_tag();
1615      xml_newline();
1616 
1617      xml_open_start_tag("port");
1618      xml_attribute("protocol", IPPROTO2STR((*li)->proto));
1619      xml_attribute("portid", "%d", (*li)->portno);
1620      xml_attribute("name", (*li)->name);
1621      xml_close_start_tag();
1622      xml_end_tag(); /* </port> */
1623      xml_newline();
1624 
1625     if ((*li)->end.reason != NULL && !strncmp((*li)->end.reason, SERVICE_TIMEDOUT, sizeof(SERVICE_TIMEDOUT)))
1626       save_state = true;
1627 
1628     if ((*li)->credentials_found.size() != 0)
1629       print_service_output(*li);
1630 
1631     xml_end_tag(); /* </service> */
1632     xml_newline();
1633   }
1634 
1635   /* Print final output information */
1636   print_final_output(SG);
1637   log_flush_all();
1638 
1639   /* If any service timed out, then save a .restore file */
1640   if (save_state)
1641     ncrack_save(SG);
1642 
1643   /* Free all of the Targets */
1644   while(!Targets.empty()) {
1645     currenths = Targets.back();
1646     delete currenths;
1647     Targets.pop_back();
1648   }
1649   delete SG;
1650 
1651   log_write(LOG_STDOUT, "\nNcrack finished.\n");
1652   exit(EXIT_SUCCESS);
1653 }
1654 
1655 
1656 /* Start the timeout clocks of any targets that aren't already timedout */
1657 static void
startTimeOutClocks(ServiceGroup * SG)1658 startTimeOutClocks(ServiceGroup *SG)
1659 {
1660   struct timeval tv;
1661   list<Service *>::iterator li;
1662 
1663   gettimeofday(&tv, NULL);
1664   for (li = SG->services_all.begin(); li != SG->services_all.end(); li++) {
1665     if (!(*li)->timedOut(NULL))
1666       (*li)->startTimeOutClock(&tv);
1667   }
1668 }
1669 
1670 
1671 /*
1672  * It handles module endings
1673  */
1674 void
ncrack_module_end(nsock_pool nsp,void * mydata)1675 ncrack_module_end(nsock_pool nsp, void *mydata)
1676 {
1677   Connection *con = (Connection *) mydata;
1678   ServiceGroup *SG = (ServiceGroup *) nsock_pool_get_udata(nsp);
1679   Service *serv = con->service;
1680   nsock_iod nsi = con->niod;
1681   struct timeval now;
1682   int pair_ret;
1683   const char *hostinfo = serv->HostInfo();
1684 
1685   con->login_attempts++;
1686   con->auth_complete = true;
1687   serv->total_attempts++;
1688   serv->finished_attempts++;
1689 
1690   /* First check if the module reported that it can no longer continue to
1691    * crack the assigned service, in which case we should place it in the
1692    * finished services.
1693    */
1694   if (serv->end.orly) {
1695     if (o.debugging) {
1696       if (serv->end.reason) {
1697         chomp(serv->end.reason);
1698         log_write(LOG_STDOUT, "%s will no longer be cracked because module "
1699             "reported that:\n %s\n", hostinfo, serv->end.reason);
1700       } else {
1701         log_write(LOG_STDOUT, "%s will no longer be cracked. No reason was "
1702             "reported from module.\n", hostinfo);
1703       }
1704     }
1705     SG->pushServiceToList(serv, &SG->services_finished);
1706     if (o.verbose)
1707       log_write(LOG_STDOUT, "%s finished.\n", hostinfo);
1708     return ncrack_connection_end(nsp, con);
1709   }
1710 
1711   if (con->auth_success) {
1712     serv->addCredential(con->user, con->pass);
1713     SG->credentials_found++;
1714 
1715     if (o.verbose)
1716       log_write(LOG_PLAIN, "Discovered credentials on %s '%s' '%s'\n",
1717           hostinfo, con->user, con->pass);
1718 
1719     /* Quit cracking service if '-f' has been specified. */
1720     if (o.finish == 1) {
1721 
1722       SG->pushServiceToList(serv, &SG->services_finished);
1723       if (o.verbose)
1724         log_write(LOG_STDOUT, "%s finished.\n", hostinfo);
1725       return ncrack_connection_end(nsp, con);
1726 
1727     } else if (o.finish > 1) {
1728       /* Quit cracking every service if '-f -f' or greater has been
1729        * specified.
1730        */
1731       list <Service *>::iterator li;
1732       for (li = SG->services_all.begin(); li != SG->services_all.end(); li++) {
1733         SG->pushServiceToList(*li, &SG->services_finished);
1734         if (o.verbose)
1735           log_write(LOG_STDOUT, "%s finished.\n", hostinfo);
1736       }
1737       /* Now quit nsock_loop */
1738       nsock_loop_quit(nsp);
1739       return ncrack_connection_end(nsp, con);
1740     }
1741 
1742   } else {
1743     if (!serv->more_rounds) {
1744       if (o.debugging > 6) {
1745         if (!strcmp(serv->name, "redis"))
1746           log_write(LOG_STDOUT, "%s (EID %li) Login failed: '%s'\n",
1747               hostinfo, nsock_iod_id(con->niod), con->pass);
1748         else
1749           log_write(LOG_STDOUT, "%s (EID %li) Login failed: '%s' '%s'\n",
1750               hostinfo, nsock_iod_id(con->niod), con->user, con->pass);
1751       }
1752     } else {
1753       serv->appendToPool(con->user, con->pass);
1754     }
1755   }
1756 
1757   if (serv->just_started && !serv->more_rounds
1758       && con->close_reason != MODULE_ERR) {
1759     serv->supported_attempts++;
1760     serv->auth_rate_meter.update(1, NULL);
1761   }
1762 
1763   gettimeofday(&now, NULL);
1764   if (!serv->just_started && !serv->more_rounds
1765       && timeval_msec_subtract(now, serv->last_auth_rate.time) >= 500) {
1766     double current_rate = serv->auth_rate_meter.getCurrentRate();
1767     if (o.debugging)
1768       log_write(LOG_STDOUT, "%s last: %.2f current %.2f parallelism %ld\n",
1769           hostinfo, serv->last_auth_rate.rate, current_rate,
1770           serv->ideal_parallelism);
1771     if (current_rate < serv->last_auth_rate.rate + 3) {
1772       if (serv->ideal_parallelism + 3 < serv->max_connection_limit)
1773         serv->ideal_parallelism += 3;
1774       else
1775         serv->ideal_parallelism = serv->max_connection_limit;
1776       if (o.debugging)
1777         log_write(LOG_STDOUT, "%s Increasing connection limit to: %ld\n",
1778             hostinfo, serv->ideal_parallelism);
1779     }
1780     serv->last_auth_rate.time = now;
1781     serv->last_auth_rate.rate = current_rate;
1782   }
1783 
1784   /* If login pair was extracted from pool, permanently remove it from it. */
1785   if (con->from_pool && !serv->isMirrorPoolEmpty()) {
1786     serv->removeFromPool(con->user, con->pass);
1787     con->from_pool = false;
1788   }
1789 
1790   if (serv->isMirrorPoolEmpty() && !serv->active_connections
1791       && serv->getListFinishing()) {
1792     SG->pushServiceToList(serv, &SG->services_finished);
1793     if (o.verbose)
1794       log_write(LOG_STDOUT, "%s finished.\n", hostinfo);
1795     return ncrack_connection_end(nsp, con);
1796   }
1797 
1798   /*
1799    * Check if we had previously surpassed imposed connection limit so that
1800    * we remove service from 'services_full' list
1801    */
1802   if (serv->getListFull()
1803       && serv->active_connections < serv->ideal_parallelism)
1804     SG->popServiceFromList(serv, &SG->services_full);
1805 
1806   /* Initiate new connections if service gets active again */
1807   if (serv->getListActive())
1808     ncrack_probes(nsp, SG);
1809 
1810   /* If module itself reported an error in the connection, then mark the flag
1811    * auth_complete as false.
1812    */
1813   if (con->close_reason == MODULE_ERR)
1814     con->auth_complete = false;
1815 
1816   /* If module instructed to close the connection by force, then do so
1817    * here.
1818    */
1819   if (con->force_close)
1820     return ncrack_connection_end(nsp, con);
1821 
1822   /*
1823    * If we need to check whether peer is alive or not we do the following:
1824    * Since there is no portable way to check if the peer has closed the
1825    * connection or not (hence we are in CLOSE_WAIT state), issue a read call
1826    * with a very small timeout and check if nsock timed out (host hasn't closed
1827    * connection yet) or returned an EOF (host sent FIN making active close)
1828    * Note, however that the connection might have already indicated that the
1829    * peer is alive (for example telnetd sends the next login prompt along with
1830    * the authentication results, denoting that it immediately expects another
1831    * authentication attempt), so in that case we need to get the next login
1832    * pair only and make no additional check.
1833    */
1834   if (con->peer_alive) {
1835     if ((!serv->auth_tries
1836           || con->login_attempts < (unsigned long)serv->auth_tries)
1837         && (pair_ret = serv->getNextPair(&con->user, &con->pass)) != -1) {
1838       if (pair_ret == 1)
1839         con->from_pool = true;
1840       nsock_timer_create(nsp, ncrack_timer_handler, 0, con);
1841     } else
1842       return ncrack_connection_end(nsp, con);
1843   } else {
1844     /*
1845      * We need to check if host is alive only on first timing
1846      * probe. Thereafter we can use the 'supported_attempts'.
1847      */
1848     if (serv->just_started && serv->more_rounds) {
1849       ncrack_connection_end(nsp, con);
1850     } else if (serv->just_started) {
1851       con->check_closed = true;
1852       nsock_read(nsp, nsi, ncrack_read_handler, 10, con);
1853     } else if ((!serv->auth_tries
1854           || con->login_attempts < (unsigned long)serv->auth_tries)
1855         && con->login_attempts < serv->supported_attempts
1856         && (pair_ret = serv->getNextPair(&con->user, &con->pass)) != -1) {
1857       if (pair_ret == 1)
1858         con->from_pool = true;
1859 
1860 
1861       call_module(nsp, con);
1862     } else {
1863       /* We end the connection if:
1864        * (we are not the first timing probe) AND
1865        * (we are either at the server's imposed authentication limit OR
1866        * we are at the user's imposed authentication limit)
1867        */
1868       ncrack_connection_end(nsp, con);
1869     }
1870   }
1871   return;
1872 }
1873 
1874 
1875 void
ncrack_connection_end(nsock_pool nsp,void * mydata)1876 ncrack_connection_end(nsock_pool nsp, void *mydata)
1877 {
1878   Connection *con = (Connection *) mydata;
1879   Service *serv = con->service;
1880   nsock_iod nsi = con->niod;
1881   ServiceGroup *SG = (ServiceGroup *) nsock_pool_get_udata(nsp);
1882   list <Connection *>::iterator li;
1883   const char *hostinfo = serv->HostInfo();
1884   unsigned long eid = nsock_iod_id(con->niod);
1885 
1886 
1887   if (con->close_reason == CON_ERR)
1888     SG->connections_timedout++;
1889 
1890   if (con->close_reason == READ_TIMEOUT) {
1891 
1892     if (!con->auth_complete) {
1893       serv->appendToPool(con->user, con->pass);
1894     }
1895 
1896     if (serv->getListPairfini())
1897       SG->popServiceFromList(serv, &SG->services_pairfini);
1898     if (o.debugging)
1899       error("%s (EID %li) nsock READ timeout!", hostinfo, eid);
1900 
1901   } else if (con->close_reason == READ_EOF || con->close_reason == MODULE_ERR) {
1902     /*
1903      * Check if we are on the point where peer might close at any moment
1904      * (usually we set 'peer_might_close' after writing the password on the
1905      * network and before issuing the next read call), so that this connection
1906      * ending was actually expected.
1907      */
1908     if (con->peer_might_close) {
1909       /* If we are the first special timing probe, then increment the number of
1910        * server-allowed authentication attempts per connection.
1911        */
1912       if (serv->just_started)
1913         serv->supported_attempts++;
1914 
1915       serv->total_attempts++;
1916       serv->finished_attempts++;
1917 
1918       if (o.debugging > 6)
1919         log_write(LOG_STDOUT, "%s (EID %li) Failed '%s' '%s'\n", hostinfo, eid,
1920             con->user, con->pass);
1921 
1922     } else if (serv->more_rounds) {
1923       /* We are still checking timing of the host, so don't do anything yet. */
1924 
1925     } else if (!con->auth_complete) {
1926       serv->appendToPool(con->user, con->pass);
1927       if (serv->getListPairfini())
1928         SG->popServiceFromList(serv, &SG->services_pairfini);
1929 
1930       /* Now this is strange: peer closed on us in the middle of
1931        * authentication. This shouldn't happen, unless extreme network
1932        * conditions are happening!
1933        */
1934       if (!serv->just_started
1935           && con->login_attempts < serv->supported_attempts) {
1936         if (o.debugging > 3)
1937           error("%s (EID %li) closed on us in the middle of authentication!", hostinfo, eid);
1938         SG->connections_closed++;
1939       }
1940     }
1941     if (o.debugging > 5)
1942       error("%s (EID %li) Connection closed by peer", hostinfo, eid);
1943   }
1944   con->close_reason = -1;
1945 
1946 
1947   /*
1948    * If we are not the first timing probe and the authentication wasn't
1949    * completed (we double check that by seeing if we are inside the supported
1950    * -by the server- threshold of authentication attempts per connection), then
1951    *  we take drastic action and drop the connection limit.
1952    */
1953   if (!serv->just_started && !serv->more_rounds && !con->auth_complete
1954       && !con->peer_might_close
1955       && con->login_attempts < serv->supported_attempts) {
1956     serv->total_attempts++;
1957     // TODO:perhaps here we might want to differentiate between the two errors:
1958     // timeout and premature close, giving a unique drop value to each
1959     if (serv->ideal_parallelism - 5 >= serv->min_connection_limit)
1960       serv->ideal_parallelism -= 5;
1961     else
1962       serv->ideal_parallelism = serv->min_connection_limit;
1963 
1964     if (o.debugging)
1965       log_write(LOG_STDOUT, "%s (EID %li) Dropping connection limit due to connection "
1966           "error to: %ld\n", hostinfo, eid, serv->ideal_parallelism);
1967   }
1968 
1969 
1970   /*
1971    * If that was our first connection, then calculate initial ideal_parallelism
1972    * (which was 1 previously) based on the box of min_connection_limit,
1973    * max_connection_limit and a default desired parallelism for each timing
1974    * template.
1975    */
1976   if (serv->just_started == true && !serv->more_rounds) {
1977     serv->just_started = false;
1978     long desired_par = 1;
1979     if (o.timing_level == 0)
1980       desired_par = 1;
1981     else if (o.timing_level == 1)
1982       desired_par = 1;
1983     else if (o.timing_level == 2)
1984       desired_par = 4;
1985     else if (o.timing_level == 3)
1986       desired_par = 10;
1987     else if (o.timing_level == 4)
1988       desired_par = 30;
1989     else if (o.timing_level == 5)
1990       desired_par = 50;
1991 
1992     serv->ideal_parallelism = box(serv->min_connection_limit,
1993         serv->max_connection_limit, desired_par);
1994   }
1995 
1996 
1997   for (li = serv->connections.begin(); li != serv->connections.end(); li++) {
1998     if ((*li)->niod == nsi)
1999       break;
2000   }
2001   if (li == serv->connections.end()) /* this shouldn't happen */
2002     fatal("%s: invalid niod!", __func__);
2003 
2004   SG->auth_rate_meter.update(con->login_attempts, NULL);
2005 
2006   nsock_iod_delete(nsi, NSOCK_PENDING_SILENT);
2007   serv->connections.erase(li);
2008   delete con;
2009 
2010   serv->active_connections--;
2011   SG->active_connections--;
2012 
2013 
2014   /*
2015    * Check if we had previously surpassed imposed connection limit so that
2016    * we remove service from 'services_full' list
2017    */
2018   if (serv->getListFull()
2019       && serv->active_connections < serv->ideal_parallelism)
2020     SG->popServiceFromList(serv, &SG->services_full);
2021 
2022 
2023   /*
2024    * If linear stealthy mode is enabled, then mark the corresponding state as DONE
2025    * since the connection just ended. If all connections from all services are done,
2026    * then the next active connection can start.
2027    */
2028   if (serv->getLinearState() == LINEAR_ACTIVE) {
2029     serv->setLinearState(LINEAR_DONE);
2030     serv->ideal_parallelism = 1;
2031   }
2032 
2033 
2034   /*
2035    * If service was on 'services_finishing' (credential list finished, pool
2036    * empty but still pending connections) then:
2037    * - if new pairs arrived into pool, remove from 'services_finishing'
2038    * - else if no more connections are pending, move to 'services_finished'
2039    */
2040   if (serv->getListFinishing()) {
2041     if (!serv->isMirrorPoolEmpty())
2042       SG->popServiceFromList(serv, &SG->services_finishing);
2043     else if (!serv->active_connections) {
2044       SG->pushServiceToList(serv, &SG->services_finished);
2045       if (o.verbose)
2046         log_write(LOG_STDOUT, "%s finished.\n", hostinfo);
2047     }
2048   }
2049 
2050   if (o.debugging)
2051     log_write(LOG_STDOUT, "%s (EID %li) Attempts: total %lu completed %lu supported %lu "
2052         "--- rate %.2f \n", hostinfo, eid, serv->total_attempts,
2053         serv->finished_attempts, serv->supported_attempts,
2054         SG->auth_rate_meter.getCurrentRate());
2055 
2056   /* Check if service finished for good. */
2057   if (serv->loginlist_fini && serv->isMirrorPoolEmpty()
2058       && !serv->active_connections && !serv->getListFinished()) {
2059     SG->pushServiceToList(serv, &SG->services_finished);
2060     if (o.verbose)
2061       log_write(LOG_STDOUT, "%s finished.\n", hostinfo);
2062   }
2063 
2064 
2065   /* see if we can initiate some more connections */
2066   if (serv->getListActive())
2067     return ncrack_probes(nsp, SG);
2068 
2069   return;
2070 }
2071 
2072 
2073 void
ncrack_read_handler(nsock_pool nsp,nsock_event nse,void * mydata)2074 ncrack_read_handler(nsock_pool nsp, nsock_event nse, void *mydata)
2075 {
2076   enum nse_status status = nse_status(nse);
2077   enum nse_type type = nse_type(nse);
2078   ServiceGroup *SG = (ServiceGroup *) nsock_pool_get_udata(nsp);
2079   Connection *con = (Connection *) mydata;
2080   Service *serv = con->service;
2081   int pair_ret;
2082   int nbytes;
2083   int err;
2084   char *str;
2085   const char *hostinfo = serv->HostInfo();
2086   unsigned long eid = nsock_iod_id(con->niod);
2087 
2088   assert(type == NSE_TYPE_READ);
2089 
2090 
2091   /* If service has already finished (probably due to the -f option), then
2092    * cancel this event and return immediately. The same happens with the rest
2093    * of the event handlers.
2094    */
2095   if (serv->getListFinished()) {
2096     nsock_event_cancel(nsp, nse_id(nse), 0);
2097     return;
2098   }
2099 
2100   if (serv->timedOut(NULL)) {
2101     serv->end.reason = Strndup(SERVICE_TIMEDOUT, sizeof(SERVICE_TIMEDOUT));
2102     SG->pushServiceToList(serv, &SG->services_finished);
2103     if (o.verbose)
2104       log_write(LOG_STDOUT, "%s finished.\n", hostinfo);
2105     return ncrack_connection_end(nsp, con);
2106 
2107   } else if (status == NSE_STATUS_SUCCESS) {
2108 
2109     str = nse_readbuf(nse, &nbytes);
2110 
2111     if (con->inbuf == NULL)
2112       con->inbuf = new Buf();
2113 
2114     con->inbuf->append(str, nbytes);
2115 
2116     return call_module(nsp, con);
2117 
2118   } else if (status == NSE_STATUS_TIMEOUT) {
2119 
2120     /* First check if we are just making sure the host hasn't closed
2121      * on us, and so we are still in ESTABLISHED state, instead of
2122      * CLOSE_WAIT - we do this by issuing a read call with a tiny timeout.
2123      * If we are still connected, then we can go on checking if we can make
2124      * another authentication attempt in this particular connection.
2125      */
2126     if (con->check_closed) {
2127       /* Make another authentication attempt only if:
2128        * 1. we hanen't surpassed the authentication limit per connection for
2129        *    this service
2130        * 2. we still have enough login pairs from the pool
2131        */
2132       if ((!serv->auth_tries
2133             || con->login_attempts < (unsigned long)serv->auth_tries)
2134           && (pair_ret = serv->getNextPair(&con->user, &con->pass)) != -1) {
2135         if (pair_ret == 1)
2136           con->from_pool = true;
2137         return call_module(nsp, con);
2138       } else {
2139         con->close_reason = READ_EOF;
2140       }
2141     } else {
2142       /* This is a normal timeout */
2143       con->close_reason = READ_TIMEOUT;
2144     }
2145 
2146   } else if (status == NSE_STATUS_EOF) {
2147     con->close_reason = READ_EOF;
2148 
2149   } else if (status == NSE_STATUS_ERROR || status == NSE_STATUS_PROXYERROR) {
2150 
2151     err = nse_errorcode(nse);
2152     if (o.debugging > 2)
2153       error("%s (EID %li) nsock READ error #%d (%s)", hostinfo, eid, err, strerror(err));
2154     serv->appendToPool(con->user, con->pass);
2155     if (serv->getListPairfini())
2156       SG->popServiceFromList(serv, &SG->services_pairfini);
2157 
2158   } else if (status == NSE_STATUS_KILL) {
2159     if (o.debugging > 2)
2160       error("%s (EID %li) nsock READ nse_status_kill", hostinfo, eid);
2161 
2162   } else
2163     if (o.debugging > 2)
2164       error("%s (EID %li) WARNING: nsock READ unexpected status %d", hostinfo,
2165           eid, (int) status);
2166 
2167   return ncrack_connection_end(nsp, con);
2168 }
2169 
2170 
2171 
2172 
2173 void
ncrack_write_handler(nsock_pool nsp,nsock_event nse,void * mydata)2174 ncrack_write_handler(nsock_pool nsp, nsock_event nse, void *mydata)
2175 {
2176   enum nse_status status = nse_status(nse);
2177   Connection *con = (Connection *) mydata;
2178   ServiceGroup *SG = (ServiceGroup *) nsock_pool_get_udata(nsp);
2179   Service *serv = con->service;
2180   const char *hostinfo = serv->HostInfo();
2181   int err;
2182   unsigned long eid = nsock_iod_id(con->niod);
2183 
2184   if (serv->getListFinished()) {
2185     nsock_event_cancel(nsp, nse_id(nse), 0);
2186     return;
2187   }
2188 
2189   if (serv->timedOut(NULL)) {
2190     serv->end.reason = Strndup(SERVICE_TIMEDOUT, sizeof(SERVICE_TIMEDOUT));
2191     SG->pushServiceToList(serv, &SG->services_finished);
2192     if (o.verbose)
2193       log_write(LOG_STDOUT, "%s finished.\n", hostinfo);
2194     return ncrack_connection_end(nsp, con);
2195 
2196   } else if (status == NSE_STATUS_SUCCESS)
2197     call_module(nsp, con);
2198   else if (status == NSE_STATUS_ERROR || status == NSE_STATUS_PROXYERROR) {
2199     err = nse_errorcode(nse);
2200     if (o.debugging > 2)
2201       error("%s (EID %li) nsock WRITE error #%d (%s)", hostinfo, eid, err, strerror(err));
2202   } else if (status == NSE_STATUS_KILL) {
2203     error("%s (EID %li) nsock WRITE nse_status_kill\n", hostinfo, eid);
2204   } else
2205     error("%s (EID %li) WARNING: nsock WRITE unexpected status %d",
2206         hostinfo, eid, (int) (status));
2207 
2208   return;
2209 }
2210 
2211 
2212 void
ncrack_timer_handler(nsock_pool nsp,nsock_event nse,void * mydata)2213 ncrack_timer_handler(nsock_pool nsp, nsock_event nse, void *mydata)
2214 {
2215   enum nse_status status = nse_status(nse);
2216   Connection *con = (Connection *) mydata;
2217   Service *serv = con->service;
2218   const char *hostinfo = serv->HostInfo();
2219 
2220   if (serv->getListFinished()) {
2221     nsock_event_cancel(nsp, nse_id(nse), 0);
2222     return;
2223   }
2224 
2225   if (status == NSE_STATUS_SUCCESS) {
2226     call_module(nsp, con);
2227   }
2228   else
2229     error("%s nsock Timer handler error!", hostinfo);
2230 
2231   return;
2232 }
2233 
2234 
2235 
2236 
2237 void
ncrack_connect_handler(nsock_pool nsp,nsock_event nse,void * mydata)2238 ncrack_connect_handler(nsock_pool nsp, nsock_event nse, void *mydata)
2239 {
2240   nsock_iod nsi = nse_iod(nse);
2241   enum nse_status status = nse_status(nse);
2242   enum nse_type type = nse_type(nse);
2243   ServiceGroup *SG = (ServiceGroup *) nsock_pool_get_udata(nsp);
2244   Connection *con = (Connection *) mydata;
2245   Service *serv = con->service;
2246   const char *hostinfo = serv->HostInfo();
2247   int err;
2248   unsigned long eid = nsock_iod_id(con->niod);
2249 
2250   assert(type == NSE_TYPE_CONNECT || type == NSE_TYPE_CONNECT_SSL);
2251 
2252   if (serv->getListFinished()) {
2253     nsock_event_cancel(nsp, nse_id(nse), 0);
2254     return;
2255   }
2256 
2257   if (serv->timedOut(NULL)) {
2258     serv->end.reason = Strndup(SERVICE_TIMEDOUT, sizeof(SERVICE_TIMEDOUT));
2259     SG->pushServiceToList(serv, &SG->services_finished);
2260     if (o.verbose)
2261       log_write(LOG_STDOUT, "%s finished.\n", hostinfo);
2262     return ncrack_connection_end(nsp, con);
2263 
2264   } else if (status == NSE_STATUS_SUCCESS) {
2265 
2266     serv->failed_connections = 0;
2267 
2268 #if HAVE_OPENSSL
2269     // Snag our SSL_SESSION from the nsi for use in subsequent connections.
2270     if (nsock_iod_check_ssl(nsi)) {
2271       if (con->ssl_session) {
2272         if (con->ssl_session == (SSL_SESSION *)(nsock_iod_get_ssl_session(nsi, 0))) {
2273           //nada
2274         } else {
2275           SSL_SESSION_free((SSL_SESSION*)con->ssl_session);
2276           con->ssl_session = (SSL_SESSION *)(nsock_iod_get_ssl_session(nsi, 1));
2277         }
2278       } else {
2279         con->ssl_session = (SSL_SESSION *)(nsock_iod_get_ssl_session(nsi, 1));
2280       }
2281     }
2282 #endif
2283 
2284     return call_module(nsp, con);
2285 
2286   } else if (status == NSE_STATUS_TIMEOUT || status == NSE_STATUS_ERROR
2287       || status == NSE_STATUS_PROXYERROR) {
2288 
2289     /* This is not good. connect() really shouldn't generally be timing out. */
2290     if (o.debugging > 2) {
2291       err = nse_errorcode(nse);
2292       error("%s (EID %li) nsock CONNECT response with status %s error: %s", hostinfo,
2293           eid, nse_status2str(status), strerror(err));
2294     }
2295     serv->failed_connections++;
2296     serv->appendToPool(con->user, con->pass);
2297 
2298     if (serv->failed_connections > serv->connection_retries) {
2299       SG->pushServiceToList(serv, &SG->services_finished);
2300       if (o.verbose)
2301         log_write(LOG_STDOUT, "%s finished. Too many failed attemps. \n", hostinfo);
2302     }
2303     /* Failure of connecting on first attempt means we should probably drop
2304      * the service for good. */
2305     if (serv->just_started) {
2306       SG->pushServiceToList(serv, &SG->services_finished);
2307       if (o.verbose)
2308         log_write(LOG_STDOUT, "%s finished.\n", hostinfo);
2309     }
2310     if (serv->getListPairfini())
2311       SG->popServiceFromList(serv, &SG->services_pairfini);
2312 
2313     con->close_reason = CON_ERR;
2314 
2315   } else if (status == NSE_STATUS_KILL) {
2316 
2317     if (o.debugging)
2318       error("%s (EID %li) nsock CONNECT nse_status_kill", hostinfo, eid);
2319     serv->appendToPool(con->user, con->pass);
2320     if (serv->getListPairfini())
2321       SG->popServiceFromList(serv, &SG->services_pairfini);
2322 
2323   } else
2324     error("%s (EID %li) WARNING: nsock CONNECT unexpected status %d",
2325         hostinfo, eid, (int) status);
2326 
2327   return ncrack_connection_end(nsp, con);
2328 }
2329 
2330 
2331 /*
2332  * Poll for interactive user input every time this timer is called.
2333  */
2334 static void
status_timer_handler(nsock_pool nsp,nsock_event nse,void * mydata)2335 status_timer_handler(nsock_pool nsp, nsock_event nse, void *mydata)
2336 {
2337   int key_ret;
2338   enum nse_status status = nse_status(nse);
2339   ServiceGroup *SG = (ServiceGroup *) nsock_pool_get_udata(nsp);
2340   mydata = NULL; /* nothing in there */
2341 
2342   key_ret = keyWasPressed();
2343   if (key_ret == KEYPRESS_STATUS)
2344     printStatusMessage(SG);
2345   else if (key_ret == KEYPRESS_CREDS)
2346     print_creds(SG);
2347 
2348   if (status != NSE_STATUS_SUCCESS) {
2349     /* Don't reschedule timer again, since nsp seems to have been
2350      * deleted (NSE_STATUS_KILL sent) and we are done. */
2351     if (status == NSE_STATUS_KILL)
2352       return;
2353     else
2354       error("Nsock status timer handler error: %s\n", nse_status2str(status));
2355   }
2356 
2357   /* Reschedule timer for the next polling. */
2358   nsock_timer_create(nsp, status_timer_handler, KEYPRESSED_INTERVAL, NULL);
2359 
2360 }
2361 
2362 static void
signal_timer_handler(nsock_pool nsp,nsock_event nse,void * mydata)2363 signal_timer_handler(nsock_pool nsp, nsock_event nse, void *mydata)
2364 {
2365   enum nse_status status = nse_status(nse);
2366   ServiceGroup *SG = (ServiceGroup *) nsock_pool_get_udata(nsp);
2367   mydata = NULL; /* nothing in there */
2368 
2369   if (status != NSE_STATUS_SUCCESS) {
2370     /* Don't reschedule timer again, since nsp seems to have been
2371      * deleted (NSE_STATUS_KILL sent) and we are done. */
2372     if (status == NSE_STATUS_KILL) {
2373       sigcheck(SG);
2374       return;
2375     }
2376     else
2377       error("Nsock status timer handler error: %s\n", nse_status2str(status));
2378   }
2379 
2380   /* Reschedule timer for the next polling. */
2381   nsock_timer_create(nsp, signal_timer_handler, SIGNAL_CHECK_INTERVAL, NULL);
2382 
2383   /* Check for pending signals */
2384   sigcheck(SG);
2385 }
2386 
2387 
2388 static void
ncrack_probes(nsock_pool nsp,ServiceGroup * SG)2389 ncrack_probes(nsock_pool nsp, ServiceGroup *SG)
2390 {
2391   Service *serv;
2392   Connection *con;
2393   struct sockaddr_storage ss;
2394   size_t ss_len;
2395   list <Service *>::iterator li;
2396   struct timeval now;
2397   int pair_ret;
2398   char *login, *pass;
2399   const char *hostinfo;
2400   size_t i = 0;
2401 
2402 
2403   /* First check for every service if connection_delay time has already
2404    * passed since its last connection and move them back to 'services_active'
2405    * list if it has.
2406    */
2407   gettimeofday(&now, NULL);
2408   for (li = SG->services_wait.begin(); li != SG->services_wait.end(); li++) {
2409     if (timeval_msec_subtract(now, (*li)->last)
2410         >= (long long)(*li)->connection_delay) {
2411       li = SG->popServiceFromList(*li, &SG->services_wait);
2412     }
2413   }
2414 
2415   if (SG->last_accessed == SG->services_active.end()) {
2416     li = SG->services_active.begin();
2417   } else {
2418     li = SG->last_accessed++;
2419   }
2420 
2421 
2422 
2423   while (SG->active_connections < SG->connection_limit
2424       && SG->services_finished.size() != SG->total_services
2425       && SG->services_active.size() != 0) {
2426 
2427     serv = *li;
2428     hostinfo = serv->HostInfo();
2429 
2430     if (serv->timedOut(NULL)) {
2431       serv->end.reason = Strndup(SERVICE_TIMEDOUT, sizeof(SERVICE_TIMEDOUT));
2432       SG->pushServiceToList(serv, &SG->services_finished);
2433       if (o.verbose)
2434         log_write(LOG_STDOUT, "%s finished.\n", hostinfo);
2435       goto next;
2436     }
2437 
2438     /*
2439      * If the service's last connection was earlier than 'connection_delay'
2440      * milliseconds ago, then temporarily move service to 'services_wait' list
2441      */
2442     gettimeofday(&now, NULL);
2443     if (timeval_msec_subtract(now, serv->last)
2444         < (long long)serv->connection_delay) {
2445       li = SG->pushServiceToList(serv, &SG->services_wait);
2446       goto next;
2447     }
2448 
2449 
2450     /* If the service's active connections surpass its imposed connection limit
2451      * then don't initiate any more connections for it and also move service in
2452      * the services_full list so that it won't be reaccessed in this loop.
2453      */
2454     if (serv->active_connections >= serv->ideal_parallelism) {
2455       li = SG->pushServiceToList(serv, &SG->services_full);
2456       goto next;
2457     }
2458 
2459 
2460     /*
2461      * To mark a service as completely  finished, first make sure:
2462      * a) that the username list has finished being iterated through once
2463      * b) that the mirror pair pool, which holds temporary login pairs which
2464      *    are currently being used, is empty
2465      * c) that no pending connections are left
2466      * d) that the service hasn't already finished
2467      */
2468     if (serv->loginlist_fini && serv->isMirrorPoolEmpty()
2469         && !serv->getListFinished()) {
2470       if (!serv->active_connections) {
2471         li = SG->pushServiceToList(serv, &SG->services_finished);
2472         if (o.verbose)
2473           log_write(LOG_STDOUT, "%s finished.\n", hostinfo);
2474         goto next;
2475       } else {
2476         li = SG->pushServiceToList(serv, &SG->services_finishing);
2477         goto next;
2478       }
2479     }
2480 
2481     /*
2482      * If the username list iteration has finished, then don't initiate another
2483      * connection until our pair_pool has at least one element to grab another
2484      * pair from.
2485      */
2486     if (serv->loginlist_fini && serv->isPoolEmpty()
2487         && !serv->isMirrorPoolEmpty()) {
2488       li = SG->pushServiceToList(serv, &SG->services_pairfini);
2489       goto next;
2490     }
2491 
2492     if ((pair_ret = serv->getNextPair(&login, &pass)) == -1)
2493       goto next;
2494 
2495 
2496     /*
2497      * If service belongs to list linear, then we have to wait until all others have
2498      * first iterated.
2499      */
2500     if ((serv->getLinearState() != LINEAR_INIT)
2501         && (serv->getLinearState() == LINEAR_ACTIVE || SG->checkLinearPending() == true)) {
2502       goto next;
2503     }
2504 
2505     /* Schedule 1 connection for this service */
2506     con = new Connection(serv);
2507     SG->connections_total++;
2508 
2509     if (o.stealthy_linear) {
2510       serv->setLinearState(LINEAR_ACTIVE);
2511     }
2512 
2513     if (pair_ret == 1)
2514       con->from_pool = true;
2515     con->user = login;
2516     con->pass = pass;
2517 
2518     if ((con->niod = nsock_iod_new(nsp, serv)) == NULL) {
2519       fatal("Failed to allocate Nsock I/O descriptor in %s()", __func__);
2520     }
2521 
2522     if (o.debugging > 8)
2523       log_write(LOG_STDOUT, "%s (EID %li) Initiating new Connection\n", hostinfo, nsock_iod_id(con->niod));
2524 
2525     gettimeofday(&now, NULL);
2526     serv->last = now;
2527     serv->connections.push_back(con);
2528     serv->active_connections++;
2529     SG->active_connections++;
2530 
2531     serv->target->TargetSockAddr(&ss, &ss_len);
2532     if (serv->proto == IPPROTO_TCP) {
2533       if (!serv->ssl) {
2534         if (o.proxychain && o.socks4a) {
2535           if (!serv->target->targetname)
2536             fatal("Socks4a requires a hostname. Use socks4 for IPv4.");
2537           nsock_connect_tcp_socks4a(nsp, con->niod, ncrack_connect_handler,
2538               DEFAULT_CONNECT_TIMEOUT, con, serv->target->targetname,
2539               serv->portno);
2540         } else {
2541           nsock_connect_tcp(nsp, con->niod, ncrack_connect_handler,
2542               DEFAULT_CONNECT_TIMEOUT, con,
2543               (struct sockaddr *)&ss, ss_len,
2544               serv->portno);
2545         }
2546       } else {
2547         nsock_connect_ssl(nsp, con->niod, ncrack_connect_handler,
2548             DEFAULT_CONNECT_SSL_TIMEOUT, con,
2549             (struct sockaddr *) &ss, ss_len, serv->proto,
2550             serv->portno, con->ssl_session);
2551       }
2552     } else {
2553       assert(serv->proto == IPPROTO_UDP);
2554       nsock_connect_udp(nsp, con->niod, ncrack_connect_handler,
2555           serv, (struct sockaddr *) &ss, ss_len,
2556           serv->portno);
2557     }
2558 
2559 next:
2560 
2561     /*
2562      * this will take care of the case where the state of the services_active list
2563      * has been modified in the meantime by any pushToList or popFromList without
2564      * saving the state to the current li iterator thus showing to a non-valid
2565      * service
2566      */
2567     if (SG->prev_modified != li) {
2568       li = SG->services_active.end();
2569     }
2570 
2571     SG->last_accessed = li;
2572     if (li == SG->services_active.end() || ++li == SG->services_active.end()) {
2573       li = SG->services_active.begin();
2574     }
2575 
2576 
2577     i++;
2578     if (o.stealthy_linear && i == SG->services_all.size())
2579       return;
2580 
2581   }
2582 
2583   return;
2584 }
2585 
2586 
2587 
2588 static int
ncrack(ServiceGroup * SG)2589 ncrack(ServiceGroup *SG)
2590 {
2591   /* nsock variables */
2592   struct timeval now;
2593   enum nsock_loopstatus loopret;
2594   list <Service *>::iterator li;
2595   nsock_pool nsp;
2596   int nsock_timeout = 3000;
2597   int err;
2598 
2599   /* create nsock p00l */
2600   if (!(nsp = nsock_pool_new(SG)))
2601     fatal("Can't create nsock pool.");
2602 
2603   if (o.proxychain) {
2604     if (nsock_pool_set_proxychain(nsp, o.proxychain) == -1)
2605       fatal("Unable to set proxychain for nsock pool");
2606   }
2607 
2608   gettimeofday(&now, NULL);
2609   nsock_set_loglevel(o.nsock_loglevel);
2610 
2611 #if HAVE_OPENSSL
2612   /* We don't care about connection security, so cast Haste */
2613   nsock_pool_ssl_init(nsp, NSOCK_SSL_MAX_SPEED);
2614 #endif
2615 
2616   SG->findMinDelay();
2617   /* We have to set the nsock_loop timeout to the minimum of the connection
2618    * delay, since we have to check every that time period for potential new
2619    * connection initiations. If the minimum connection delay is 0 however, we
2620    * don't need to do it, since that would make nsock_loop return immediately
2621    * and consume a lot of CPU.
2622    */
2623   if (SG->min_connection_delay != 0)
2624     nsock_timeout = SG->min_connection_delay;
2625 
2626   /* Initiate time-out clocks */
2627   startTimeOutClocks(SG);
2628 
2629   /* initiate all authentication rate meters */
2630   SG->auth_rate_meter.start();
2631   for (li = SG->services_all.begin(); li != SG->services_all.end(); li++)
2632     (*li)->auth_rate_meter.start();
2633 
2634   /*
2635    * Since nsock can delay between each event due to the targets being really
2636    * slow,  we need a way to make sure that we always poll for interactive user
2637    * input regardless of the above case. Thus we schedule a special timer event
2638    * that happens every KEYPRESSED_INTERVAL milliseconds and which reschedules
2639    * itself every time its handler is called.
2640    */
2641   nsock_timer_create(nsp, status_timer_handler, KEYPRESSED_INTERVAL, NULL);
2642 
2643   /*
2644    * We do the same for checking pending signals every SIGNAL_CHECK_INTERVAL
2645    */
2646   nsock_timer_create(nsp, signal_timer_handler, SIGNAL_CHECK_INTERVAL, NULL);
2647 
2648   ncrack_probes(nsp, SG);
2649 
2650   /* nsock loop */
2651   do {
2652 
2653     loopret = nsock_loop(nsp, nsock_timeout);
2654 
2655     if (loopret == NSOCK_LOOP_ERROR) {
2656       err = nsock_pool_get_error(nsp);
2657       fatal("Unexpected nsock_loop error. Error code %d (%s)",
2658           err, strerror(err));
2659     }
2660 
2661     ncrack_probes(nsp, SG);
2662 
2663   } while (SG->services_finished.size() != SG->total_services);
2664 
2665   nsock_pool_delete(nsp);
2666 
2667   if (o.debugging > 4)
2668     log_write(LOG_STDOUT, "nsock_loop returned %d\n", loopret);
2669 
2670   return 0;
2671 }
2672 
2673