diff -urN dsniff-2.3/ChangeLog.ggsniff dsniff-2.3-gg/ChangeLog.ggsniff --- dsniff-2.3/ChangeLog.ggsniff Thu Jan 1 01:00:00 1970 +++ dsniff-2.3-gg/ChangeLog.ggsniff Mon Sep 16 14:18:54 2002 @@ -0,0 +1,24 @@ +2002.09.13 v1.1c + - fixed silly "cut&paste" error + +2002.09.12 v1.1b + - fixed silly segfault in process_gg() + +2002.09.11 v1.1 + - added printing remote GG user's IP (if available) + +2002.09.03 v1.1-beta + - fixed segfault in process_msn() [dsniff-2.3-segfault.patch] + - added switch -d for debugging info + - added switch -p for disabling promiscous mode (useful on routers) +[dsniff-2.3-promisc.patch] + - sniffer recognizes data direction + - different connections from single IP do not share client_info + - sniffing GG connections to port 443 + - support for extension in new GG protocol (client version 4.9.3+) + +2002.04.26 v1.01 + - added printing local GG user's IP + +2002.03.20 v1.0 + - first release diff -urN dsniff-2.3/msgsnarf.8 dsniff-2.3-gg/msgsnarf.8 --- dsniff-2.3/msgsnarf.8 Sun Nov 19 07:10:50 2000 +++ dsniff-2.3-gg/msgsnarf.8 Fri Aug 30 15:15:23 2002 @@ -14,7 +14,7 @@ .ad .fi \fBmsgsnarf\fR records selected messages from AOL Instant -Messenger, ICQ 2000, IRC, MSN Messenger, or Yahoo Messenger chat +Messenger, ICQ 2000, IRC, MSN Messenger, Gadu-Gadu, or Yahoo Messenger chat sessions. .SH OPTIONS .IP "\fB-i \fIinterface\fR" diff -urN dsniff-2.3/msgsnarf.c dsniff-2.3-gg/msgsnarf.c --- dsniff-2.3/msgsnarf.c Fri Dec 15 21:12:19 2000 +++ dsniff-2.3-gg/msgsnarf.c Fri Sep 13 16:24:00 2002 @@ -1,10 +1,10 @@ /* msgsnarf.c - Sniff chat messages (AIM, ICQ, IRC, MSN, Yahoo) on a network. + Sniff chat messages (AIM, ICQ, IRC, MSN, Yahoo, Gadu-Gadu) on a network. Copyright (c) 1999 Dug Song - + $Id: msgsnarf.c,v 1.9 2000/12/15 20:12:19 dugsong Exp $ */ @@ -25,23 +25,30 @@ #include "decode.h" #include "version.h" +#define TO_CLIENT 0 +#define TO_SERVER 1 +#define PACKED __attribute__ ((packed)) + struct client_info { char *nick; char *peer; char *type; in_addr_t ip; + unsigned short port; + in_addr_t local_ip; SLIST_ENTRY(client_info) next; }; SLIST_HEAD(, client_info) client_list; int Opt_invert = 0; regex_t *pregex = NULL; +int Opt_debug = 0; void usage(void) { fprintf(stderr, "Version: " VERSION "\n" - "Usage: msgsnarf [-i interface] [[-v] pattern [expression]]\n"); + "Usage: msgsnarf [-d] [-p] [-i interface] [[-v] pattern [expression]]\n"); exit(1); } @@ -81,7 +88,7 @@ }; int -process_aim(struct client_info *info, u_char *data, int len) +process_aim(struct client_info *info, u_char *data, int len, int dir) { struct buf *msg, *word, buf; struct flap *flap; @@ -215,7 +222,7 @@ } int -process_irc(struct client_info *info, u_char *data, int len) +process_irc(struct client_info *info, u_char *data, int len, int dir) { struct buf *line, *word, *prefix, buf; char *p; @@ -336,7 +343,7 @@ } int -process_msn(struct client_info *info, u_char *data, int len) +process_msn(struct client_info *info, u_char *data, int len, int dir) { struct buf *word, *line, buf; char *p; @@ -442,7 +449,7 @@ }; int -process_yahoo(struct client_info *info, u_char *data, int len) +process_yahoo(struct client_info *info, u_char *data, int len, int dir) { struct yhoo *yhoo; struct ymsg *ymsg; @@ -544,11 +551,266 @@ return (len - buf_len(&buf)); } + +/* + Support for GG messages added by Ryba + v1.1b + + Protocol description taken from EKG (http://dev.null.pl/ekg/) + by , and others. + Thanks to all of them! + + Gadu-Gadu (http://www.gadu-gadu.pl) is a Polish communicator. + I believe it is a most popular instant messenger in Poland. +*/ + +struct remote_client_info { + int uin; + char *nick; + in_addr_t ip; + unsigned short port; + SLIST_ENTRY(remote_client_info) next; +}; + +SLIST_HEAD(, remote_client_info) remote_client_list; + +#define GG_NETWORK "217.17.41.80" +#define GG_NETMASK "255.255.255.248" +unsigned int gg_network; +unsigned int gg_netmask; + +#define GG_LOGIN 0x000c +#define GG_LOGIN_EXT 0x0013 +#define GG_SEND_MSG 0x000b +#define GG_RECV_MSG 0x000a +#define GG_NOTIFY_REPLY 0x000c +#define GG_NOTIFY 0x0010 + +#define GG_STATUS_NOT_AVAIL_DESCR 0x0015 +#define GG_STATUS_AVAIL_DESCR 0x0004 +#define GG_STATUS_BUSY_DESCR 0x0005 + +struct gg_header { + int type; + int length; +}; + +struct gg_send_msg { + int recipient; + int seq; + int class; +// char message[]; +}; + +struct gg_recv_msg { + int sender; + int seq; + int time; + int class; +// char message[]; +}; + +struct gg_login { + int uin; + int hash; + int status; + int version; + int local_ip; + u_short local_port; +} PACKED; + +struct gg_login_ext { + int uin; + int hash; + int status; + int version; + int local_ip; + short local_port; + int external_ip; + short external_port; +} PACKED; + +struct gg_notify_reply { + int uin; + int status; + int remote_ip; + short remote_port; + int version; + short unknown1; +} PACKED; + +struct in_addr int2in_addr(u_int i) { + struct in_addr ia; + ia.s_addr = i; + return ia; +} + +struct remote_client_info *find_remote_client(int uin) { + int i; + struct remote_client_info *rc; + + i = 0; + SLIST_FOREACH(rc, &remote_client_list, next) { + if (rc->uin == uin) { + i = 1; break; + } + } + + if (i == 0) { + return NULL; + } else { + return rc; + } +} + +struct remote_client_info *add_remote_client(struct remote_client_info newrc) { + struct remote_client_info *rc; + + if ((rc = malloc(sizeof(*rc))) == NULL) + nids_params.no_mem("sniff_msgs"); + memset(rc, 0, sizeof(*rc)); + rc->uin = newrc.uin; + rc->ip = newrc.ip; + rc->port = newrc.port; + SLIST_INSERT_HEAD(&remote_client_list, rc, next); + return rc; +} + +#define GG_NICK_SIZE 45 +#define GG_IP_SIZE 16 + +int process_gg(struct client_info *info, u_char *data, int len, int dir) { + + struct buf *msg, buf; + struct gg_header *header; + struct gg_send_msg *send_msg; + struct gg_recv_msg *recv_msg; + struct gg_login *login; + struct gg_login_ext *login_ext; + struct gg_notify_reply *notify_reply; + struct remote_client_info *rc; + struct remote_client_info new_rc; + char *p; + char sbuff[GG_NICK_SIZE]; + char local_ip[GG_IP_SIZE]; + int i; + int count; + + buf_init(&buf, data, len); + + while (buf_len(&buf) > sizeof(*header)) { + header = (struct gg_header *)buf_ptr(&buf); + i = sizeof(*header) + header->length; + + if ((msg = buf_tok(&buf, NULL, i)) == NULL) + break; + + buf_skip(msg, sizeof(*header)); + + if ((header->type == GG_LOGIN || header->type == GG_LOGIN_EXT)&& dir == TO_SERVER) { + + login = (struct gg_login *)buf_ptr(msg); + + if (info->ip == login->local_ip) { + snprintf(sbuff, GG_NICK_SIZE, "%s/%u", inet_ntoa(int2in_addr(info->ip)), login->uin); + } else + strncpy(local_ip, inet_ntoa(int2in_addr(login->local_ip)), GG_IP_SIZE); + snprintf(sbuff, GG_NICK_SIZE, "%s/%s/%u", inet_ntoa(int2in_addr(info->ip)), local_ip, login->uin); + if (info->nick) free(info->nick); + info->nick = strdup(sbuff); + + if (Opt_debug != 0) { + if (header->type == GG_LOGIN) { + printf("%s GG_LOGIN %s\n", timestamp(), info->nick); + } else { + printf("%s GG_LOGIN_EXT %s\n", timestamp(), info->nick); + } + } + } else + + if (header->type == GG_SEND_MSG && dir == TO_SERVER) { + send_msg = (struct gg_send_msg *)buf_ptr(msg); + buf_skip(msg, sizeof(*send_msg)); + + p = buf_strdup(msg); + if (regex_match(p)) { + rc = find_remote_client(send_msg->recipient); + if (rc && rc->ip != 0) { + snprintf(sbuff, GG_NICK_SIZE, "%s:%u/%u", inet_ntoa(int2in_addr(rc->ip)), rc->port, rc->uin); + } else { + snprintf(sbuff, GG_NICK_SIZE, "%u", send_msg->recipient); + } + printf("%s GG_SEND %s > %s: %s\n", timestamp(), info->nick, sbuff, p); + } + free(p); + } else + + if (header->type == GG_RECV_MSG && dir == TO_CLIENT) { + recv_msg = (struct gg_recv_msg *)buf_ptr(msg); + buf_skip(msg, sizeof(*recv_msg)); + + p = buf_strdup(msg); + if (regex_match(p)) { + rc = find_remote_client(recv_msg->sender); + if (rc && rc->ip != 0) { + snprintf(sbuff, GG_NICK_SIZE, "%s:%u/%u", inet_ntoa(int2in_addr(rc->ip)), rc->port, rc->uin); + } else { + snprintf(sbuff, GG_NICK_SIZE, "%u", recv_msg->sender); + } + printf("%s GG_RECV %s < %s: %s\n", timestamp(), info->nick, sbuff, p); + } + free(p); + } + + if (header->type == GG_NOTIFY_REPLY && dir == TO_CLIENT) { + notify_reply = (struct gg_notify_reply *)buf_ptr(msg); + + if (notify_reply->status == GG_STATUS_NOT_AVAIL_DESCR || + notify_reply->status == GG_STATUS_AVAIL_DESCR || + notify_reply->status == GG_STATUS_BUSY_DESCR) { + count = 1; + } else { + count = header->length / sizeof(*notify_reply); + } + + for (i = 0; i < count; i++) { + rc = find_remote_client(notify_reply->uin); + if (rc) { + if (rc->ip != 0) { + rc->ip = notify_reply->remote_ip; + rc->port = notify_reply->remote_port; + } + } else { + new_rc.uin = notify_reply->uin; + new_rc.ip = notify_reply->remote_ip; + new_rc.port = notify_reply->remote_port; + rc = add_remote_client(new_rc); + } + if (Opt_debug != 0) { + printf("%s GG_NOTIFY_REPLY #%u [%s:%u/%u]\n", timestamp(), + i, inet_ntoa(int2in_addr(rc->ip)), rc->port, rc->uin); + } + buf_skip(msg, sizeof(*notify_reply)); + notify_reply = (struct gg_notify_reply *)buf_ptr(msg); + } + } + + if (header->type == GG_NOTIFY && dir == TO_SERVER) { + if (Opt_debug != 0) { + printf("%s GG_NOTIFY (%u)\n", timestamp(), header->length); + } + } + } + + return(len - buf_len(&buf)); +} + + void sniff_msgs(struct tcp_stream *ts, void **conn_save) { struct client_info *c; - int (*process_msgs)(struct client_info *, u_char *, int); + int (*process_msgs)(struct client_info *, u_char *, int, int); int i; if (ts->addr.dest >= 6660 && ts->addr.dest <= 6680) { @@ -563,8 +825,12 @@ else if (ts->addr.dest == 1863) { process_msgs = process_msn; } + else if (ts->addr.dest == 8074 || (ts->addr.dest == 443 && + (ts->addr.daddr & gg_netmask) == gg_network)) { + process_msgs = process_gg; + } else return; - + switch (ts->nids_state) { case NIDS_JUST_EST: @@ -573,15 +839,18 @@ i = 0; SLIST_FOREACH(c, &client_list, next) { - if (c->ip == ts->addr.saddr) { + if (c->ip == ts->addr.saddr && c->port == ts->addr.source) { i = 1; break; } } if (i == 0) { if ((c = malloc(sizeof(*c))) == NULL) nids_params.no_mem("sniff_msgs"); + memset(c, 0, sizeof(*c)); c->ip = ts->addr.saddr; + c->port = ts->addr.source; c->nick = strdup("unknown"); + c->local_ip = 0; SLIST_INSERT_HEAD(&client_list, c, next); } *conn_save = (void *)c; @@ -592,12 +861,14 @@ if (ts->server.count_new > 0) { i = process_msgs(c, ts->server.data, - ts->server.count - ts->server.offset); + ts->server.count - ts->server.offset, + TO_SERVER); nids_discard(ts, i); } else if (ts->client.count_new > 0) { i = process_msgs(c, ts->client.data, - ts->client.count - ts->client.offset); + ts->client.count - ts->client.offset, + TO_CLIENT); nids_discard(ts, i); } fflush(stdout); @@ -608,10 +879,12 @@ if (ts->server.count > 0) process_msgs(c, ts->server.data, - ts->server.count - ts->server.offset); + ts->server.count - ts->server.offset, + TO_SERVER); else if (ts->client.count > 0) process_msgs(c, ts->client.data, - ts->client.count - ts->client.offset); + ts->client.count - ts->client.offset, + TO_CLIENT); fflush(stdout); break; } @@ -627,7 +900,7 @@ { int c; - while ((c = getopt(argc, argv, "i:hv?V")) != -1) { + while ((c = getopt(argc, argv, "dpi:hv?V")) != -1) { switch (c) { case 'i': nids_params.device = optarg; @@ -635,6 +908,13 @@ case 'v': Opt_invert = 1; break; + case 'd': + Opt_debug = 1; + break; + case 'p': + // disable promiscous mode + nids_params.promisc = 0; + break; default: usage(); } @@ -653,10 +933,14 @@ nids_params.scan_num_hosts = 0; nids_params.syslog = null_syslog; + gg_network = inet_addr(GG_NETWORK);; + gg_netmask = inet_addr(GG_NETMASK); + if (!nids_init()) errx(1, "%s", nids_errbuf); SLIST_INIT(&client_list); + SLIST_INIT(&remote_client_list); nids_register_tcp(sniff_msgs); @@ -666,6 +950,11 @@ } else warnx("listening on %s", nids_params.device); + if (nids_params.promisc == 0) { + warnx("promiscous mode disabled"); + } else + warnx("promiscous mode enabled"); + nids_run(); /* NOTREACHED */