void process_upnp_response(struct Ferret *ferret, struct NetFrame *frame, const unsigned char *px, unsigned length) { unsigned offset=0; while (offset < length) { const unsigned char *line = px+offset; unsigned line_length; for (line_length=0; offset+line_length < length && px[offset+line_length] != '\n'; line_length++) ; offset += line_length; if (offset<length && px[offset] == '\n') offset++; while (line_length && isspace(line[line_length-1])) line_length--; if (line_length>3 && strnicmp((const char*)line, "ST:", 3) == 0) { JOTDOWN(ferret, JOT_SZ("proto","upnp"), JOT_SRC("ip.src", frame), JOT_PRINT("ST", line+3, line_length-3), 0); } } }
/*TODO: currently, nobody references this function*/ void dns_dynamic_update(struct Ferret *ferret, struct NetFrame *frame, const unsigned char *px, unsigned length, struct DNS *dns) { unsigned i; for (i=0; i<dns->answer_count; i++) { char name[256]; unsigned name_length; unsigned x; struct DNSRECORD *rec = &dns->answers[i]; name_length = dns_extract_name(frame, px, length, rec->name_offset, name, sizeof(name)); x = rec->clss<<16 | rec->type; SAMPLE(ferret,"DynDNS", JOT_NUM("Prereq", x)); switch (rec->type) { case 0x0001: /*A*/ switch (rec->clss) { case 0x0001: /*INTERNET*/ { unsigned ip_address = ex32be(px+rec->rdata_offset); if (rec->rdata_length != 4) FRAMERR(frame, "dns: data not 4-bytes long, was %d-bytes instead (class=%d, type=%d, name=%s)\n", rec->rdata_length, rec->clss, rec->type, name); JOTDOWN(ferret, JOT_IPv4("ID-IP", ip_address), JOT_PRINT("name", name, name_length), 0); JOTDOWN(ferret, JOT_SZ("proto","NETBIOS"), JOT_SZ("op","register"), JOT_SRC("ip.src", frame), JOT_PRINT("name", name, name_length), JOT_IPv4("address", ip_address), 0); } break; default: FRAMERR(frame, "dns: unknown class=%d (type=%d, name=%s)\n", rec->clss, rec->type, name); } break; } } }
void process_cups(struct Ferret *ferret, struct NetFrame *frame, const unsigned char *px, unsigned length) { unsigned offset = 0; unsigned type=0; unsigned state = 0; const unsigned char *uri; unsigned uri_length; const unsigned char *location; unsigned location_length; const unsigned char *information; unsigned information_length; const unsigned char *model; unsigned model_length; extract_num(px, length, &offset, &type); extract_num(px, length, &offset, &state); extract_string(px, length, &offset, &uri, &uri_length); extract_string(px, length, &offset, &location, &location_length); extract_string(px, length, &offset, &information, &information_length); extract_string(px, length, &offset, &model, &model_length); JOTDOWN(ferret, JOT_SZ("proto", "CUPS"), JOT_SRC("ip.src", frame), JOT_NUM("type",type), 0); JOTDOWN(ferret, JOT_SZ("proto", "CUPS"), JOT_SRC("ip.src", frame), JOT_NUM("state",state), 0); JOTDOWN(ferret, JOT_SZ("proto", "CUPS"), JOT_SRC("ip.src", frame), JOT_PRINT("uri", uri, uri_length), 0); JOTDOWN(ferret, JOT_SZ("proto", "CUPS"), JOT_SRC("ip.src", frame), JOT_PRINT("location", location, location_length), 0); JOTDOWN(ferret, JOT_SZ("proto", "CUPS"), JOT_SRC("ip.src", frame), JOT_PRINT("info", information, information_length), 0); JOTDOWN(ferret, JOT_SZ("proto", "CUPS"), JOT_SRC("ip.src", frame), JOT_PRINT("model", model, model_length), 0); }
void process_simple_smtp_data(struct TCPRECORD *sess, struct TCP_STREAM *to_server, struct NetFrame *frame, const unsigned char *px, unsigned length) { struct FerretEngine *eng = sess->eng; struct Ferret *ferret = eng->ferret; unsigned offset=0; unsigned command; unsigned command_length; unsigned parm; unsigned parm_length; if (sess == NULL) return; frame->layer7_protocol = LAYER7_SMTP; while (offset<length) { /* Handle end-of-email '.' issue */ if (offset<length && px[offset] == '.') { if (offset+1<length && px[offset] == '\n' && offset+2<length && px[offset] == '\r' && px[offset+1] == '\n') { to_server->app.smtpreq.is_body = 0; to_server->app.smtpreq.is_data = 0; return; } } if (to_server->app.smtpreq.is_body) { while (offset<length && px[offset] != '\n') offset++; if (offset<length && px[offset] == '\n') offset++; continue; } while (offset<length && isspace(px[offset]) && px[offset] != '\n') offset++; command = offset; while (offset<length && px[offset] != ':' && px[offset] != '\n') offset++; command_length = offset-command; if (command_length == 0) { to_server->app.smtpreq.is_body = 1; continue; } while (command_length && isspace(px[offset+command_length])) command_length--; if (command_length && px[offset+command_length] == ':') command_length--; while (command_length && isspace(px[offset+command_length])) command_length--; while (offset<length && px[offset] == ':') offset++; while (offset<length && isspace(px[offset]) && px[offset] != '\n') offset++; parm = offset; if ((offset<length && px[offset] == '\n') || (offset+1<length && px[offset] == '\r' && px[offset+1] == '\n')) { to_server->app.smtpreq.is_body = 1; return; } again: while (offset<length && px[offset] != '\n') offset++; if (offset<length && px[offset] == '\n') offset++; if (offset<length && px[offset] != '\n' && isspace(px[offset]) && (offset+1<length && px[offset] != '\r' && px[offset] != '\n')) goto again; parm_length = offset-parm; while (parm_length && isspace(px[parm+parm_length-1])) parm_length--; JOTDOWN(ferret, JOT_SZ("proto","RFC822msg"), JOT_PRINT("header", px+command, command_length), JOT_PRINT("value", px+parm, parm_length), JOT_SRC("client", frame), JOT_DST("server", frame), 0); if (is_command("subject", px+command, command_length)) { smtp_copy(to_server->app.smtpreq.subject, px+parm, parm_length); } if (is_command("X-Mailer", px+command, command_length)) { JOTDOWN(ferret, JOT_SRC("ID-IP", frame), JOT_PRINT("X-Mailer", px+parm, parm_length), 0); } if (is_command("X-MimeOLE", px+command, command_length)) { JOTDOWN(ferret, JOT_SRC("ID-IP", frame), JOT_PRINT("X-MimeOLE", px+parm, parm_length), 0); } } }
void process_simple_smtp_request(struct TCPRECORD *sess, struct TCP_STREAM *to_server, struct NetFrame *frame, const unsigned char *px, unsigned length) { struct FerretEngine *eng = sess->eng; struct Ferret *ferret = eng->ferret; char command[16]; const char *parm; unsigned parm_length; unsigned i; unsigned x; /* IF CLOSING CONNECTION */ if (px == NULL) { return; } frame->layer7_protocol = LAYER7_SMTP; if (to_server->app.smtpreq.is_data) { process_simple_smtp_data(sess, to_server, frame, px, length); return; } /* Remove leading whitespace */ for (i=0; i<length && isspace(px[i]); i++) ; /* Grab command. This means parsing up to the first space * character, or the first ':' character in the case of * mailfrom: or rcptto: */ x=0; again: while (i<length && !isspace(px[i]) && px[i] != ':') { if (x < sizeof(command) -1) { command[x++] = (char)toupper(px[i]); command[x] = '\0'; } i++; } if (i<length && px[i] == ':') i++; /* skip space after command */ while (i<length && isspace(px[i])) i++; if (stricmp(command, "mail")==0 || stricmp(command, "rcpt")==0) { if (i >= length) return; goto again; } SAMPLE(ferret,"SMTP", JOT_SZ("command", command)); /* Grab parm */ parm = (const char*)px+i; x=i; while (i<length && px[i] != '\n') i++; parm_length = i-x; if (parm_length && parm[parm_length-1] == '\n') parm_length--; if (parm_length && parm[parm_length-1] == '\r') parm_length--; JOTDOWN(ferret, JOT_SZ("proto", "SMTP"), JOT_SZ("op", command), JOT_PRINT("parm", parm, parm_length), JOT_SRC("client", frame), JOT_DST("server", frame), 0); /* test parms */ if (stricmp(command, "MAILFROM")==0) { strip_address(&parm, &parm_length); if (sess) smtp_copy(to_server->app.smtpreq.from, parm, parm_length); JOTDOWN(ferret, JOT_SRC("IP", frame), JOT_PRINT("e-mail", parm, parm_length), 0); } if (stricmp(command, "RCPTTO")==0) { strip_address(&parm, &parm_length); if (sess) smtp_copy(to_server->app.smtpreq.to, parm, parm_length); JOTDOWN(ferret, JOT_SRC("IP", frame), JOT_PRINT("friend", parm, parm_length), 0); } if (stricmp(command, "DATA")==0 && sess) { to_server->app.smtpreq.is_data = 1; } if (stricmp(command, "RSET")==0 && sess) { to_server->app.smtpreq.is_data = 0; } }
/** * This is the main function of the DNS parser. * * This is where the each DNS 'answer' (or 'additional' or 'authoritative') * record is parsed. Mostly, we ignore the return code, though some functions * pay attention to and provide slightly different information depending * upon the opcode. */ static void dns_parse_resource_record(struct Ferret *ferret, struct NetFrame *frame, const unsigned char *px, unsigned length, struct DNSRECORD *rec, struct DNS *dns) { char name[512]; /* reserve a longer name than the max theoretical limit */ unsigned name_length; char name2[512]; /* reserve a longer name than the max theoretical limit */ unsigned name2_length; unsigned ip_address; unsigned offset = rec->rdata_offset; unsigned offset_max = MIN(rec->rdata_offset+rec->rdata_length, length); /* MULTICAST DNS (mDNS): handle the multicast DNS records differently * from normal DNS records. */ if (!dns->is_response && frame->dst_port == 5353) { bonjour_parse_resource_record(ferret, frame, px, length, rec, dns); return; } else if (dns->is_response && (frame->src_port == 5353 || (frame->dst_port == 5353 && frame->src_port != 53))) { bonjour_parse_resource_record(ferret, frame, px, length, rec, dns); return; } /* NETBIOS: handle NetBIOS records differently from normal DNS records */ if (!dns->is_response && frame->dst_port == 137) { netbios_parse_resource_record(ferret, frame, px, length, rec, dns); return; } else if (dns->is_response && frame->src_port == 137) { netbios_parse_resource_record(ferret, frame, px, length, rec, dns); return; } /* First, let's extract a pretty version of the name */ name_length = dns_extract_name(frame, px, length, rec->name_offset, name, sizeof(name)); if (rec->type == 0x8001) FRAMERR(frame, "TODO\n"); if (rec->clss == 0xfe) return; /* RFC2671 - Extension Mechanisms for DNS (EDNS0) */ if (rec->type == 41) { /* Regress: defcon2008/dump000.pca(12541) */ /* TODO: parse this */ return; } /* Haven't implemented dynamic update yet * TODO: */ if (dns->opcode == 21 || dns->opcode == 5) return; switch (rec->type<<16 | rec->clss) { case TYPECLASS(1,0x8001): /* type=A(IPv4 address), class=INTERNET(cache flush) */ bonjour_parse_resource_record(ferret, frame, px, length, rec, dns); break; case TYPECLASS(1,1): /* type=A(IPv4 address), class=INTERNET */ if (!is_valid_opcode(dns->opcode, 0x10, 5, -1)) { FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode); return; } ip_address = ex32be(px+rec->rdata_offset); if (rec->rdata_length != 4) FRAMERR(frame, "dns: data not 4-bytes long, was %d-bytes instead (class=%d, type=%d, name=%s)\n", rec->rdata_length, rec->clss, rec->type, name); JOTDOWN(ferret, JOT_PRINT("ID-DNS", name, name_length), JOT_IPv4("address", ip_address), 0); break; case TYPECLASS(2,1): /* type=NS, class=INTERNET */ if (!is_valid_opcode(dns->opcode, 0x10, -1)) { FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode); return; } name2_length = dns_extract_name(frame, px, length, rec->rdata_offset, name2, sizeof(name2)); ip_address = dns_resolve_alias(frame, px, length, dns, name2, 0); JOTDOWN(ferret, JOT_PRINT("ID-DNS", name, name_length), JOT_PRINT("Name-Server", name2, name2_length), JOT_IPv4("address", ip_address), 0); break; case TYPECLASS(5,1): /*type=CNAME(aliased canonical name), class=INTERNET */ if (!is_valid_opcode(dns->opcode, 0x10, 5, -1)) { FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode); return; } name2_length = dns_extract_name(frame, px, length, rec->rdata_offset, name2, sizeof(name2)); ip_address = dns_resolve_alias(frame, px, length, dns, name2, 0); if (ip_address != 0) { JOTDOWN(ferret, JOT_PRINT("ID-DNS", name, name_length), JOT_IPv4("alias",ip_address), 0); } JOTDOWN(ferret, JOT_PRINT("ID-DNS", name, name_length), JOT_PRINT("alias", name2, name2_length), 0); break; case TYPECLASS(6,1): /*type=SOA, class=INTERNET*/ if (!is_valid_opcode(dns->opcode, 0x10, -1)) { FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode); return; } /* * Authoritative Name Server */ name2_length = dns_extract_name(frame, px, length, offset, name2, sizeof(name2)); JOTDOWN(ferret, JOT_PRINT("ID-DNS", name, name_length), JOT_SZ("SOA", "Start of zone authority"), JOT_PRINT("Name-Server", name2, name2_length), 0); ip_address = dns_resolve_alias(frame, px, length, dns, name2, 0); if (ip_address) JOTDOWN(ferret, JOT_PRINT("ID-DNS", name, name_length), JOT_SZ("SOA", "Start of zone authority"), JOT_PRINT("Name-Server", name2, name2_length), JOT_IPv4("address", ip_address), 0); skip_name(px, length, &offset); /* Contact */ if (offset < offset_max) { name2_length = dns_extract_name(frame, px, length, offset, name2, sizeof(name2)); JOTDOWN(ferret, JOT_PRINT("ID-DNS", name, name_length), JOT_SZ("SOA", "Start of zone authority"), JOT_PRINT("Contact", name2, name2_length), 0); skip_name(px, length, &offset); } break; case TYPECLASS(10,1): /* type=NULL, class=INTERNET*/ /* Regress: defcon2008-dns2.pcap(100803): name=Vaaaaiaqaac.tunnel.fastcoder.net */ /* I'm not sure what this is, other than passing data as Null records. * This would be a good thing for an intrusion-detection system to trigger * on. */ break; case TYPECLASS(12,0x8001): /*type=PTR, class=INTERNET */ bonjour_parse_resource_record(ferret, frame, px, length, rec, dns); break; case TYPECLASS(12,1): /*type=PTR(pointer reverse lookup), class=INTERNET */ if (!is_valid_opcode(dns->opcode, 0x10, -1)) { FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode); return; } if (name_length > 6 && memcmp(name+name_length-6, ".local", 6) == 0) { JOTDOWN(ferret, JOT_SRC("ID-IP", frame), JOT_PRINT("Service", name,name_length), 0); /* Extract MAC address */ { const unsigned char *p_name; unsigned name_length; const unsigned char *p_mac = find_mac(px, MIN(length, rec->rdata_offset+rec->rdata_length), rec->rdata_offset, &p_name, &name_length); if (p_mac) { JOTDOWN(ferret, JOT_SRC("ID-IP", frame), JOT_PRINT("mac", p_mac, 19), 0); JOTDOWN(ferret, JOT_SRC("ID-IP", frame), JOT_PRINT("name", p_name, name_length), 0); } } } else if (endsWith(name, ".in-addr.arpa")) { /* Extract a 4-byte IPv4 address * Example: "18.0.0.10.in-addr.arpa"*/ unsigned ipv4=0; unsigned i; unsigned j=0; for (i=0; i<4; i++) { unsigned num = 0; for (; name[j] && name[j] != '.'; j++) { if ('0' <= name[j] && name[j] <= '9') num = num * 10 + name[j]-'0'; } while (name[j] == '.') j++; ipv4 |= num<<(i*8); } /* Now get the name it points to */ name2_length = dns_extract_name(frame, px, length, offset, name2, sizeof(name2)); JOTDOWN(ferret, JOT_PRINT("ID-DNS", name2, name2_length), JOT_IPv4("ID-IP", ipv4), JOT_SRC("dnssrv", frame), 0); } else ; //FRAMERR(frame, "dns: unknown PTR record\n"); break; case TYPECLASS(13,0x8001): /*type=HINFO, class=INTERNET */ bonjour_parse_resource_record(ferret, frame, px, length, rec, dns); break; case TYPECLASS(15,1): /*type=MX, class=INTERNET */ /* Regress: defcon2008-dns2.pcap(18661) */ break; case TYPECLASS(16,0x8001): /*type=TXT, class=INTERNET(cache flush)*/ bonjour_parse_resource_record(ferret, frame, px, length, rec, dns); break; case TYPECLASS(16,1): /*type=TXT, class=INTERNET */ if (!is_valid_opcode(dns->opcode, 0x10, 5, -1)) { FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode); return; } if (stricmp(name, "current.cvd.clamav.net") == 0) { /* This is a single string containing a version string, like: * 0.91.1:44:3855:1186270141:1 */ break; } else if (starts_with("_DM-NOTIFICATION.", name, strlen(name))) { /* Regress: defcon2008\dump001.pcap(87082) */ /* TODO */ break; } else if (endsWith(name, "._workstation._tcp.local")) { /* Regress: defcon2008-dns2.pcap(56127): "mike-desktop [00:0c:29:f6:58:ca]._workstation._tcp.local" */ break; } else if (endsWith(name, ".asn.cymru.com")) { /* Regress: defcon2008-dns2.pcap(98958) */ /* This is a system for mapping IP to ASN numbers: * http://www.team-cymru.org/Services/ip-to-asn.html */ break; } else if (endsWith(name, ".wrs.trendmicro.com")) { /* Regress: defcon2008-dns2.pcap(184904) */ /* Appears to check whether IP addresses are trustworthy */ break; } else { FRAMERR(frame, "%s: unknown TXT record %s", "DNS", name); } break; case TYPECLASS(0x1c,1): /*type=AAAA(IPv6 address), class=INTERNET*/ case TYPECLASS(0x1c,255): /*type=AAAA(IPv6 address), class=INTERNET*/ if (!is_valid_opcode(dns->opcode, 0x10, 5, -1)) { FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode); return; } switch (dns->opcode) { case 0x10: { const unsigned char *ipv6_address = px+rec->rdata_offset; if (rec->rdata_length != 16) FRAMERR(frame, "dns: data not 16-bytes long, was %d-bytes instead (class=%d, type=%d, name=%s)\n", rec->rdata_length, rec->clss, rec->type, name); JOTDOWN(ferret, JOT_SZ("proto","DNS"), JOT_SZ("op","lookup"), JOT_SRC("ip.src", frame), JOT_PRINT("name", name, name_length), JOT_IPv6("address", ipv6_address, 16), 0); } case 5: /* dynamic update*/ /* Regress: defcon2008-dns2.pcap(7958) */ break; default: FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode); } break; case TYPECLASS(33,1): /*type=SRV, class=INTERNET */ if (!is_valid_opcode(dns->opcode, 0x10, -1)) { FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode); return; } if (rec->rdata_length < 7) FRAMERR(frame, "dns: unknown type=%d (class=%d, name=%s)\n", rec->type, rec->clss, name); else { unsigned port = px[rec->rdata_offset+4]<<8 | px[rec->rdata_offset+5]; name2_length = dns_extract_name(frame, px, length, rec->rdata_offset+6, name2, sizeof(name2)); ip_address = dns_resolve_alias(frame, px, length, dns, name2, 0); if (ip_address != 0) { JOTDOWN(ferret, JOT_PRINT("ID-DNS", name, name_length), JOT_PRINT("Server", name2, name2_length), JOT_NUM("Port", port), JOT_IPv4("IPv4",ip_address), 0); } else JOTDOWN(ferret, JOT_PRINT("ID-DNS", name, name_length), JOT_PRINT("Server", name2, name2_length), JOT_NUM("Port", port), 0); } break; default: FRAMERR(frame, "dns: unknown type=%d (class=%d, name=%s)\n", rec->type, rec->clss, name); } }
/** * This code analyzes a <name=value> pair within a cookie, within the * context of an HTTP request, which includes relavent information * about the host that it comes from */ void parse_http_cookie(struct TCPRECORD *sess, struct NetFrame *frame, const unsigned char *name, unsigned name_length, const unsigned char *value, unsigned value_length) { struct HTTPREQUEST *req = &sess->layer7.httpreq; unsigned char *dec; unsigned dec_length = value_length; if (dec_length > 1000) dec_length = 1000; switch (toupper(name[0])) { case 'C': /* MYSPACE COUNTRY CODE * Example: * COUNTRYCODE=MFMGCisGAQQBgjdYA%2FmgRTBDBgorBgEEAYI3WAMBoDUwMwIDAgABAgJmAwICAMAECOOUmLvDDv%2BRBBB6gRxsNuYMZ2M7SXM7N4fdBAgyFGPRkgkD7Q%3D%3D; */ if (match_name("COUNTRYCODE", name, name_length) && ends_with_t(".myspace.com", req->host)) { unsigned char *dec0; unsigned dec0_length; unsigned i; /* First, "uudecode" this */ dec0 = alloca(value_length); dec0_length = 0; for (i=0; i<value_length; i++) { if (value[i] != '%') dec0[dec0_length++] = value[i]; else { unsigned c=0; i++; if (i<value_length && isxdigit(value[i])) c = hexval(value[i++])<<4; if (i<value_length && isxdigit(value[i])) c |= hexval(value[i++]); dec0[dec0_length++] = (unsigned char)c; i--; } } /* Second, "base64 decode" this */ dec = alloca(dec0_length); dec_length = base64_decode(dec, dec_length, value, value_length); /* Third, "asn.1 decode" this */ { unsigned tag, len; const unsigned char *px = dec; unsigned offset = 0; unsigned length = dec_length; unsigned max_offset; tag = asn1_tag(px,length,&offset); len = asn1_length(frame,px,length, &offset); /* Process the big object */ if (tag == 0x30 && len != 0xFFFFFFFF) { max_offset = offset+len; tag = asn1_tag(px,max_offset,&offset); len = asn1_length(frame,px,max_offset, &offset); /* Process the OID */ if (tag == 0x06) { JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP", frame), JOT_OID("MySpace-CountryCode", px+offset, len), 0); } offset += len; } } } break; case 'D': /* go.com (including such properties as espn.com) put in their cookies some sort of location information. Here are some examples that were googled from the web: Z2JyO2VuZztsb25kb247YnJvYWRiYW5kOzU7NTs0Oy0xOzA1MS41MDA7LTAwMC4xMTc7ODI2OzEwMTk4OzQ3ODI7NTsK Z2JyO2VuZztsb25kb247YnJvYWRiYW5kOzU7NTs1Oy0xOzA1MS41MDA7LTAwMC4xMTc7ODI2OzEwMTk4OzQ3ODI7NTsK dXNhO21kO2NvbGxlZ2UgcGFyazt0MTs1OzQ7NDs1MTE7MDM4Ljk5NzstMDc2LjkyODs4NDA7MjE7MTU7NjsK dXNhO3R4O2RhbGxhczticm9hZGJhbmQ7NTs0OzQ7NjIzOzAzMi43ODc7LTA5Ni43OTk7ODQwOzQ0Ozc3OzY7Cg== dXNhO3R4O2RhbGxhczticm9hZGJhbmQ7NTs0OzQ7NjIzOzAzMi43ODc7LTA5Ni43OTk7ODQwOzQ0Ozc3OzY7Cg== dXNhO2dhO2F0bGFudGE7YnJvYWRiYW5kOzU7NTs1OzUyNDswMzMuNzQ5Oy0wODQuMzg4Ozg0MDsxMTszOzY7Cg== dXNhO29yO2JlYXZlcnRvbjticm9hZGJhbmQ7NTszOzM7ODIwOzA0NS40OTE7LTEyMi44MDU7ODQwOzM4OzYyOzY7Cg== dXNhO3R4O2RhbGxhczticm9hZGJhbmQ7NTs0OzQ7NjIzOzAzMi43ODc7LTA5Ni43OTk7ODQwOzQ0Ozc3OzY7Cg== dXNhO3R4O2RhbGxhczticm9hZGJhbmQ7NTs0OzM7NjIzOzAzMi43ODc7LTA5Ni43OTk7ODQwOzQ0Ozc3OzY7Cg== */ if (match_name("DE2", name, name_length) && ends_with_t(".go.com", req->host)) { dec = alloca(dec_length); dec_length = base64_decode(dec, dec_length, value, value_length); JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP", frame), JOT_PRINT("GO-LOC", dec, dec_length), 0); } break; case 'E': if (starts_with("EMAIL", name, name_length)) { JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP", frame), JOT_PRINT("e-mail", value, value_length), 0); } if (starts_with("E-MAIL", name, name_length)) { JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP", frame), JOT_PRINT("e-mail", value, value_length), 0); } break; case 'G': /* d78da8e7eb998e8f571c4c641b104c60cxsAAABVUyxnYSxsYXdyZW5jZXZpbGxlLCwsLCw1MjQ= bf8e3d7c0474fa9da14b6551e6846ec7cxUAAABVUyxnYSxhdGxhbnRhLCwsLCw1MjQ= */ if (match_name("GEO", name, name_length) && ends_with_t(".youtube.com", req->host)) { unsigned i; unsigned comma_count=0; dec = alloca(dec_length); dec_length = base64_decode(dec, dec_length, value, value_length); for (i=dec_length; i>0; i--) { if (dec[i-1] == ',') { /*US,ga,lawrenceville,,,,,524*/ if (++comma_count == 7) break; } } if (i>3 && isalpha(dec[i-2]) && isalpha(dec[i-3])) { unsigned offset=i-3; while (i<dec_length && comma_count > 5) { if (dec[i] == ',') comma_count--; i++; } JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP", frame), JOT_PRINT("YouTube-Loc", dec+offset, i-offset-1), 0); } } /*Example: * [email protected]/769779 */ if (match_name("GMAILCHAT", name, name_length) && ends_with_t("mail.google.com", req->host)) { unsigned j; for (j=0; j<value_length && value[j] != '/'; j++) ; JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP", frame), JOT_PRINT("e-mail", value, j), 0); } break; case 'I': if (match_name("ID", name, name_length) && ends_with_t(".doubleclick.net", req->host)) { JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP", frame), JOT_PRINT("DoubleClick", value, value_length), 0); } break; case 'L': if (match_name("LOGIN", name, name_length) || match_name("LOGIN_X", name, name_length)) { JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP", frame), JOT_URLENC("login", value, value_length), 0); if (ends_with_t(".facebook.com", req->host)) { req->login = stringtab_lookup(sess->eng->stringtab, value, value_length); JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP", frame), JOT_URLENC("Facebook-user", req->login->str, req->login->length), 0); } if (contains("@", value, value_length)) { JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP", frame), JOT_URLENC("e-mail", value, value_length), 0); } else if (contains("%40", value, value_length)) { JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP", frame), JOT_URLENC("e-mail", value, value_length), 0); } } break; case 'M': /*http://facebook.com *m_user = warnerc2%40gpc.edu%3A71101757%3ASwUchOEuvzIbYo7E*/ if (match_name("M_USER", name, name_length)) { if (ends_with_t(".facebook.com", req->host)) { JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP", frame), JOT_URLENC("e-mail", value, value_length), 0); } } /* http://login.live.com/login.srf * [email protected] */ if (match_name("MSPPRE", name, name_length)) { if (ends_with_t(".live.com", req->host)) { JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP", frame), JOT_PRINT("e-mail", value, value_length), 0); } } /* Canadian Broadcasting */ if (match_name("MyCBCSignIn", name, name_length)) { if (ends_with_t(".cbc.ca", req->host)) { JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP", frame), JOT_PRINT("e-mail", value, value_length), 0); } } if (match_name("ME", name, name_length)) { if (ends_with_t(".myspace.com", req->host)) { JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP", frame), JOT_URLENC("e-mail", value, value_length), 0); } } break; case 'P': if (starts_with("PASSWORD", name, name_length)) { JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP", frame), JOT_PRINT("password", value, value_length), 0); } break; case 'U': if (starts_with("USERNAME", name, name_length)) { JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP", frame), JOT_PRINT("username", value, value_length), 0); } break; case 'W': if (starts_with("WATCHED_VIDEO_ID_LIST_", name, name_length)) { size_t l = sizeof("WATCHED_VIDEO_ID_LIST_")-1; JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP", frame), JOT_URLENC("YouTube-ID", name+l, name_length-l), 0); } break; } }
/** * This parses a TLV record instead of a SNAC packet, which is itself * inside of a FLAP PDU. We identify the precise item by the SNAC-family, * SNAC-subtype, and TLV-tag */ static void parse_tlv(struct TCPRECORD *sess, struct NetFrame *frame, const unsigned char *px, unsigned length) { struct FerretEngine *eng = sess->eng; struct Ferret *ferret = eng->ferret; struct AIMPARSER *aim = &sess->layer7.aim; unsigned h; /* This function is going to process the data within a SNAC TLV field. * We are just going to handle this all in a big switch/case statement. */ #define HASH(x,y,z) (((x)<<16)|((y)<<8)|(z)) h = HASH(aim->pdu.family, aim->pdu.subtype, aim->tlv_tag); /* If we are in the middle of parsing the string, just grab * it in our re-assembly buffer */ if (px != NULL) { strfrag_append(sess->str, px, length); return; } /* Process the string we've reassembled. We are going to hash on the full context * of the PDU rather than just the TLV tag */ switch (h) { case 0x00170203: /* family=Sign-on, subtype=Logon, tag=client-id-string */ JOTDOWN(ferret, JOT_SRC("ID-IP",frame), JOT_PRINT("AIM-Client-ID", sess->str->the_string, sess->str->length), 0); break; case 0x0017020e: /* family=Sign-on, subtype=Logon, tag=country */ JOTDOWN(ferret, JOT_SRC("ID-IP",frame), JOT_PRINT("AIM-Country", sess->str->the_string, sess->str->length), 0); break; case 0x0017020f: /* family=Sign-on, subtype=Logon, tag=language */ JOTDOWN(ferret, JOT_SRC("ID-IP",frame), JOT_PRINT("AIM-Language", sess->str->the_string, sess->str->length), 0); break; case 0x00170225: /* family=Sign-on, subtype=Logon, tag=password hash */ JOTDOWN(ferret, JOT_SRC("ID-IP",frame), JOT_HEXSTR("AIM-Password-Hash", sess->str->the_string, sess->str->length), 0); break; break; case 0x00170201: /* family=Sign-on, subtype=Logon, tag=screen-name */ case 0x00170601: /* family=Sign-on, subtype=Sign-on, tag=screen-name */ /* This is the sign-on 'screen-name' in the packet that the user sends to * the logon server (logon.oscar.aol.com). The server will respond with * a 'challenge'. The user will then send the screen-name and hash of * challenge and password to the real server he wants to connect to */ JOTDOWN(ferret, JOT_SRC("ID-IP",frame), JOT_PRINT("AIM-Screen-Name", sess->str->the_string, sess->str->length), 0); break; case 0x00170301: /* family=Logon, subtype=Reply, tag=screen-name */ JOTDOWN(ferret, JOT_DST("ID-IP",frame), /* logon reply screen name sent from server*/ JOT_PRINT("AIM-Screen-Name", sess->str->the_string, sess->str->length), 0); break; case 0x00170311: /* family=Logon, subtype=Reply, tag=email */ JOTDOWN(ferret, JOT_DST("ID-IP",frame), /* logon reply screen name sent from server*/ JOT_PRINT("e-mail", sess->str->the_string, sess->str->length), 0); break; case 0x00170349: /* family=Logon, subtype=Reply, tag=auth-protocol */ JOTDOWN(ferret, JOT_DST("ID-IP",frame), /* logon reply screen name sent from server*/ JOT_HEXSTR("AIM-digest-sig", sess->str->the_string, sess->str->length), 0); break; case 0x00170700: /*AIM Sign-on(0x17), Sign-on Reply(7), Challenge(10)*/ /* This is the 'challenge' sent back by logon.oscar.aol.com. The user * will hash this with his password in order to logon to all the other * servers. * * Because of this, we need to attach this string to the session going * in the reverse direction. That will enable us to log the authentication * process in case we want to log the hashes */ JOTDOWN(ferret, JOT_SRC("ID-IP",frame), JOT_PRINT("AIM-Challenge", sess->str->the_string, sess->str->length), 0); break; case 0x0017038e: /* authorization cookie */ /* This is a long string to pull out, but it gives anybody who has * this cookie the ability to log onto any AIM service */ JOTDOWN(ferret, JOT_DST("ID-IP",frame), JOT_HEXSTR("AIM-Auth-Cookie", sess->str->the_string, sess->str->length), 0); break; case 0x00030b00: /* INCOMING oncoming buddy name */ case 0x00020600: if (sess->str->length) { JOTDOWN(ferret, JOT_DST("ID-IP",frame), JOT_PRINT("AIM-Buddy", sess->str->the_string, sess->str->length), 0); JOTDOWN(ferret, JOT_DST("ID-IP",frame), JOT_PRINT("friend", sess->str->the_string, sess->str->length), 0); } break; case 0x00021500: /* OUTGOING user info query*/ if (sess->str->length) { JOTDOWN(ferret, JOT_SRC("ID-IP",frame), JOT_PRINT("AIM-Buddy", sess->str->the_string, sess->str->length), 0); JOTDOWN(ferret, JOT_SRC("ID-IP",frame), JOT_PRINT("friend", sess->str->the_string, sess->str->length), 0); } break; case 0x00040700: /* Messaging, incoming */ if (sess->str->length) { JOTDOWN(ferret, JOT_DST("ID-IP",frame), JOT_PRINT("AIM-Buddy", sess->str->the_string, sess->str->length), 0); JOTDOWN(ferret, JOT_DST("ID-IP",frame), JOT_PRINT("friend", sess->str->the_string, sess->str->length), 0); strfrag_xfer(sess->str+1, sess->str); } break; case 0x00040702: /* Messaging, INCOMING */ decode_message(sess, frame, sess->str[0].the_string, sess->str[0].length, 0); break; case 0x00040600: /* Messaging, outgoing */ if (sess->str->length) { JOTDOWN(ferret, JOT_SRC("ID-IP",frame), JOT_PRINT("AIM-Buddy", sess->str->the_string, sess->str->length), 0); JOTDOWN(ferret, JOT_SRC("ID-IP",frame), JOT_PRINT("friend", sess->str->the_string, sess->str->length), 0); strfrag_xfer(sess->str+1, sess->str); } break; case 0x00040602: /* Messaging, outgoing */ decode_message(sess, frame, sess->str[0].the_string, sess->str[0].length, 1); break; case 0x00020604: /* Buddy Info - away message */ if (sess->str->length) { JOTDOWN(ferret, JOT_DST("ID-IP",frame), JOT_PRINT("AIM-Buddy", sess->str[1].the_string, sess->str[1].length), JOT_PRINT("Away-Message", sess->str[0].the_string, sess->str[0].length), 0); } break; case 0x00041400: /* typing, outgoing */ if (sess->str->length) { JOTDOWN(ferret, JOT_SRC("ID-IP",frame), JOT_PRINT("AIM-Buddy", sess->str->the_string, sess->str->length), 0); JOTDOWN(ferret, JOT_SRC("ID-IP",frame), JOT_PRINT("friend", sess->str->the_string, sess->str->length), 0); } break; case 0x00040605: /* File transfer */ parse_message_filexfer_rendezvous(sess, frame, sess->str->the_string, sess->str->length); break; case 0x00040701: case 0x00040703: case 0x00040705: case 0x0004070b: case 0x0004070f: case 0x00040713: case 0x00040716: case 0x0004071d: case 0x00040603: /* Messaging, outgoing, server-ack requested */ break; case 0x00130601: /* SNAC Server Side Information Entry List*/ case 0x001306c9: case 0x001306d6: case 0x0013066a: case 0x0013066d: case 0x00130631: /* This is the start of an SSI Entry list, maybe we should * remember this??? */ break; case 0x00130731: if (sess->str[1].length && sess->str[0].length) { JOTDOWN(ferret, JOT_DST("ID-IP",frame), JOT_PRINT("AIM-Buddy", sess->str[1].the_string, sess->str[1].length), JOT_PRINT("AIM-Description", sess->str[0].the_string, sess->str[0].length), 0); } break; /* Others that I've seen */ case 0x0017064b: case 0x0017065a: case 0x0017024c: case 0x00170216: case 0x00170217: case 0x00170218: case 0x00170219: case 0x0017021a: case 0x00170214: case 0x0017024a: case 0x00170305: case 0x00170306: case 0x00170313: case 0x00170354: case 0x00170340: case 0x00170343: case 0x00170341: case 0x00170342: case 0x00170348: case 0x00170344: case 0x00170347: case 0x00170345: case 0x00170346: case 0x00020301: case 0x00020302: case 0x00020305: case 0x00020303: case 0x00020304: case 0x00030302: case 0x00030301: case 0x00030304: case 0x00040504: case 0x00090302: case 0x00090301: case 0x00020405: case 0x00011e1d: case 0x00011e06: case 0x0004060d: case 0x00020601: /* Buddy Info - User Class */ case 0x00020603: /* Buddy Info - Online Since AND Away Msg Encoding ??? */ case 0x00020605: /* Buddy Info - Member Since */ case 0x0002060b: /* Buddy Info - unknown timestamp */ case 0x0002060d: /* Buddy Info - Capabilities List */ case 0x0002060f: /* Buddy Info - Session Length */ case 0x0002061d: /* Buddy Info - Available Message */ case 0x0002061f: /* Buddy Info - unknown */ case 0x00020623: /* Buddy Info - unknown timestamp */ case 0x00020626: /* Buddy Info - unknown timestamp (member since?) */ case 0x00020627: /* Buddy Info - unknown timestamp */ break; case 0x001306C8: /*SSI: members of this group */ break; default: /* TODO: add SAMPLE here */ switch (h&0xFFFFFF00) { case 0x00130300: break; default: FRAMERR(frame, "%s: unknown TLV tag: 0x%08x\n", "AIM", h); } break; } strfrag_finish(sess->str); }
void decode_message(struct TCPRECORD *sess, struct NetFrame *frame, const unsigned char *px, unsigned length, unsigned is_outgoing) { struct FerretEngine *eng = sess->eng; struct Ferret *ferret = eng->ferret; const unsigned char *msg = px; unsigned msg_length = length; unsigned msg_offset = 0; if (msg_length > 2 && ex16be(msg+msg_offset) == 0x501) { /*unsigned flags = ex16be(msg+msg_offset);*/ unsigned len=0; msg_offset += 2; if (msg_offset+2 < msg_length) { len = ex16be(msg+msg_offset); msg_offset += len+2; } if (msg_offset+2 < msg_length) msg_offset += 2; /* block info */ if (msg_offset+2 < msg_length) { len = ex16be(msg+msg_offset); msg_offset += 2; /* block length */ } msg_offset += 4; /* character set */ if (len > 4) len -= 4; /* subtract the charset info from the block lenght*/ if (msg_offset > msg_length) { FRAMERR(frame, "%s: integer overflow\n", "AIM"); return; } if (msg_offset + len > msg_length) len = msg_length - msg_offset; if (len > 6 && strnicmp((const char*)msg+msg_offset, "<HTML>", 6)==0) { unsigned char *msg2 = alloca(len); unsigned msg2_len; msg2_len = strip_html_tags(msg+msg_offset, len, msg2, len); if (is_outgoing) JOTDOWN(ferret, JOT_SRC("ID-IP",frame), JOT_PRINT("AIM-Message-To", sess->str[1].the_string, sess->str[1].length), JOT_PRINT("AIM-Message", msg2, msg2_len), 0); else JOTDOWN(ferret, JOT_DST("ID-IP",frame), JOT_PRINT("AIM-Message-From", sess->str[1].the_string, sess->str[1].length), JOT_PRINT("AIM-Message", msg2, msg2_len), 0); } else { if (is_outgoing) JOTDOWN(ferret, JOT_SRC("ID-IP",frame), JOT_PRINT("AIM-Message-To", sess->str[1].the_string, sess->str[1].length), JOT_PRINT("AIM-Message", msg+msg_offset, msg_length-msg_offset), 0); else JOTDOWN(ferret, JOT_DST("ID-IP",frame), JOT_PRINT("AIM-Message-From", sess->str[1].the_string, sess->str[1].length), JOT_PRINT("AIM-Message", msg+msg_offset, msg_length-msg_offset), 0); } } else { while (msg_offset<msg_length && msg[msg_offset] < 26) msg_offset++; if (is_outgoing) JOTDOWN(ferret, JOT_SRC("ID-IP",frame), JOT_PRINT("AIM-Message-To", sess->str[1].the_string, sess->str[1].length), JOT_PRINT("AIM-Message", msg+msg_offset, msg_length-msg_offset), 0); else JOTDOWN(ferret, JOT_DST("ID-IP",frame), JOT_PRINT("AIM-Message-From", sess->str[1].the_string, sess->str[1].length), JOT_PRINT("AIM-Message", msg+msg_offset, msg_length-msg_offset), 0); } }
/** * Parse the "rendez-vous" TLV within a packet. Since this is a TLV, it has * already been reassembled by our string frag parser. */ static void parse_message_filexfer_rendezvous(struct TCPRECORD *sess, struct NetFrame *frame, const unsigned char *px, unsigned length) { unsigned offset=0; /* skip some fields */ offset += 2+8; /* verify we have the file transfer ID */ while (offset < 2+8+16) { if (px[offset] != (unsigned char)("\x09\x46\x13\x43\x4c\x7f\x11\xd1\x82\x22\x44\x45\x53\x54\x00\x00"[offset-8-2])) return; /* not a file transfer command */ /*TODO: SAMPLE this */ offset++; } /* go through the embeded TLVs */ while (offset<length) { unsigned tag; unsigned len; if (offset+4>length) break; tag = ex16be(px+offset+0); len = ex16be(px+offset+2); offset += 4; /* TLV: Unknown Value ID: Unknown (0x000a) Length: 2 Value TLV: Unknown Value ID: Unknown (0x000f) Length: 0 Value TLV: Internal IP Value ID: Internal IP (0x0003) Length: 4 Value: 12625930 TLV: External Port Value ID: External Port (0x0005) Length: 2 Value: 5190 TLV: Extended Data Value ID: Extended Data (0x2711) Length: 17 Value */ switch (tag) { case 0x000a: case 0x000f: case 0x0010: break; case 3: /* Internet IP */ { unsigned j; unsigned ip=0; for (j=0; j<4 && offset+j<length; j++) ip = ip << 8 | px[offset+j]; JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP",frame), JOT_SZ("AIM", "File-Transfer"), JOT_IPv4("Internal-IP", ip), 0); } break; case 5: /* Internal Port */ { unsigned j; unsigned port=0; for (j=0; j<2 && offset+j<length; j++) port = port << 8 | px[offset+j]; JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP",frame), JOT_SZ("AIM", "File-Transfer"), JOT_NUM("Internal-Port", port), 0); } break; case 0x2711: /* filename */ if (len > length-offset) len = length-offset; if (len > 4) { len -= 4; offset += 4; } while (offset < length && len && px[offset] < 26) { offset++; len--; } JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP",frame), JOT_SZ("AIM", "File-Transfer"), JOT_PRINT("Filename", px+offset, len), 0); break; default: /* TODO: SAMPLE this */ FRAMERR(frame, "%s: unknown\n", "AIM"); break; } offset += len; } }
void parse_atalk_ddp(struct Ferret *ferret, struct NetFrame *frame, const unsigned char *px, unsigned length) { unsigned offset=0; struct { unsigned hop_count; unsigned datagram_length; unsigned checksum; unsigned protocol_type; unsigned address_src; unsigned address_dst; unsigned port_src; unsigned port_dst; } ddp; ferret->statistics.atalk++; if (length < 13) { FRAMERR(frame, "%s: truncated\n", "DDP"); return; } ddp.hop_count = px[0]>>4; ddp.datagram_length = (px[0]&0xF)<<8 | px[1]; ddp.checksum = ex16be(px+2); ddp.address_dst = ex16be(px+4)<<8; ddp.address_src = ex16be(px+6)<<8; ddp.address_dst |= px[8]; ddp.address_src |= px[9]; ddp.port_dst = px[10]; ddp.port_src = px[11]; ddp.protocol_type = px[12]; if (length > ddp.datagram_length) { if (length-ddp.datagram_length == 4) ferret->statistics.remaining_4++; /*hints that an FCS trails*/ length = ddp.datagram_length; } frame->ipver = ADDRESS_ATALK_EDDP; frame->src_ipv4 = ddp.address_src; frame->dst_ipv4 = ddp.address_dst; frame->src_port = ddp.port_src; frame->dst_port = ddp.port_dst; /* skip the header */ offset += 13; /* If this is a broadcast packet, we can make the assumption * that the sender is on the local subnet */ JOTDOWN(ferret, JOT_MACADDR("ID-MAC", frame->src_mac), JOT_SRC("AppleTalk", frame), 0); /* Parse the next layer */ SAMPLE(ferret, "ATALK-DDP",JOT_NUM("protocol", ddp.protocol_type)); SAMPLE(ferret, "ATALK-DDP",JOT_NUM("dst-port", ddp.port_dst)); switch (ddp.protocol_type) { case 0x02: /* NBP - Name Binding Protocol */ parse_atalk_nbp(ferret, frame, px+offset, length-offset); break; case 0x06: /* ZIP (Zone Information Protocol) */ break; case 0x01: /* RTMP (Routing Table Maintenance Protocol), works like RIP */ case 0x03: /* ATP (Appletalk Transfer Protocol) */ case 0x04: /* Echo, works like ICMP Echo */ case 0x05: /* RTMP requests */ case 0x07: /* ADSP (Appletalk Data Stream Protocol) */ case 0x08: /* SNMP, same as normal SNMP */ case 0x16: /* IP over AppleTalk */ default: FRAMERR(frame, "%s: unknown protocol=%d, srcport=%d, dstport=%d\n", "DDP", ddp.protocol_type, ddp.port_src, ddp.port_dst); } }
/** * Parses the <name=value> pairs in HTTP URLs and HTTP POST content data */ void http_parse_form_field(struct TCPRECORD *sess, struct NetFrame *frame, struct StringT *name, const unsigned char *value, unsigned value_length) { struct TCP_STREAM *stream = &sess->to_server; struct HTTPREQUEST *req = &stream->app.httpreq; if (name == NULL) return; switch (toupper(name->str[0])) { case 'E': if (match_name_t("EMAIL", name)) { JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP", frame), JOT_URLENC("e-mail", value, value_length), 0); if (ends_with_t(".myspace.com", req->host)) { req->login = stringtab_lookup(sess->eng->stringtab, value, value_length); if (req->password) { JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP", frame), JOT_URLENC("MySpace-user", req->login->str, req->login->length), JOT_URLENC("password", req->password->str, req->password->length), 0); } else JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP", frame), JOT_URLENC("MySpace-user", req->login->str, req->login->length), 0); } } break; case 'P': if (match_name_t("PASSWORD", name)) { JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP", frame), JOT_URLENC("form-password", value, value_length), 0); if (ends_with_t(".myspace.com", req->host)) { req->password = stringtab_lookup(sess->eng->stringtab, value, value_length); if (req->login) { JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP", frame), JOT_URLENC("MySpace-user", req->login->str, req->login->length), JOT_URLENC("password", req->password->str, req->password->length), 0); } } } if (match_name_t("PASSWD", name)) { JOTDOWN(sess->eng->ferret, JOT_SRC("ID-IP", frame), JOT_URLENC("password", value, value_length), 0); } break; case 'Q': if (match_name_t("Q", name)) { if (ends_with_t(".google.com", req->host)) { if (!starts_with("cache:", req->url, req->url_length)) { JOTDOWN(sess->eng->ferret, JOT_SRC("IP", frame), JOT_URLENC("search", value, value_length), 0); } } } break; case 'V': if (match_name_t("VIDEO_ID", name)) { if (ends_with_t(".youtube.com", req->host)) { JOTDOWN(sess->eng->ferret, JOT_SRC("Watches", frame), JOT_URLENC("YouTube", value, value_length), 0); req->youtube_video_id = stringtab_lookup(sess->eng->stringtab, value, value_length); } } break; } }
void process_ymsg_client_request( struct TCPRECORD *sess, struct NetFrame *frame, struct StringReassembler *ymsg_packet) { struct FerretEngine *eng = sess->eng; struct Ferret *ferret = eng->ferret; unsigned service = sess->layer7.ymsg.service; unsigned status = sess->layer7.ymsg.status; struct Atom atom; switch (service) { case 18: /* Ping */ break; case 0x54: /*YAHOO_SERVICE_AUTHRESP - Response to server challenge */ switch (status) { case 0: case 1515563605: /* Web Login: Ref: 2009-01-24-1.pcap(6243) */ atom = ymsg_get_enumerated_item(ymsg_packet, "0"); /* "yahoo_id" */ if (atom.len) { JOTDOWN(ferret, JOT_SRC("ID-IP", frame), JOT_PRINT("username", atom.px+atom.offset, atom.len), 0); strncpy_s(sess->layer7.ymsg.username, sizeof(sess->layer7.ymsg.username), atom.px+atom.offset, atom.len); } atom = ymsg_get_enumerated_item(ymsg_packet, "1"); /* "active_id", which may differ from "yahoo_id" */ if (atom.len) { JOTDOWN(ferret, JOT_SRC("ID-IP", frame), JOT_PRINT("username", atom.px+atom.offset, atom.len), 0); strncpy_s(sess->layer7.ymsg.username, sizeof(sess->layer7.ymsg.username), atom.px+atom.offset, atom.len); } /* * Report challenge/response for password-cracking tools */ if (sess->reverse && sess->reverse->str[1].length) { /* if we have a challenge from the other direction */ strfrag_init(&sess->reverse->str[1]); } break; default: FRAMERR_UNPARSED(frame, "YMSG.service", service); } break; /*YAHOO_SERVICE_AUTH Authentication */ case 0x57: switch (status) { case 0: atom = ymsg_get_enumerated_item(ymsg_packet, "1"); /* "yahoo_id" */ if (atom.len) { JOTDOWN(ferret, JOT_SRC("ID-IP", frame), JOT_PRINT("username", atom.px+atom.offset, atom.len), 0); strncpy_s(sess->layer7.ymsg.username, sizeof(sess->layer7.ymsg.username), atom.px+atom.offset, atom.len); } break; default: FRAMERR_UNPARSED(frame, "YMSG.service", service); } break; case 198: /* Yahoo v6 Status Update */ break; case 138: /* Ref: 2009-01-24-1.pcap(1441) */ /* Appears to be the user's login name as the one * field in this packet */ break; case 21: /* skin name */ /* Ref: 2009-01-24-1.pcap(6394) */ /* TODO * This contains some information about the user's machine, such as * what type of machine it is */ break; default: FRAMERR_UNPARSED(frame, "YMSG.service", service); } }
void parse_atalk_nbp(struct Ferret *ferret, struct NetFrame *frame, const unsigned char *px, unsigned length) { struct { unsigned op; unsigned count; unsigned xid; } nbp; unsigned offset=0; if (length < 2) { FRAMERR(frame, "%s: truncated\n", "NBP"); return; } /* * Parse the header first */ nbp.op = (px[0]>>4)&0x0F; nbp.count = (px[0]>>0)&0x0F; nbp.xid = px[1]; offset = 2; /* * Parse all the name-bindings */ while (nbp.count) { unsigned atalk_addr; unsigned atalk_port; unsigned enumerator; unsigned object_len; const unsigned char *object; unsigned type_len; const unsigned char *type; unsigned zone_len; const unsigned char *zone; nbp.count--; if (offset + 6 > length) { FRAMERR(frame, "%s: truncated\n", "NBP"); return; } atalk_addr = ex24be(px+offset); offset += 3; atalk_port = px[offset++]; enumerator = px[offset++]; /* Extract the items */ extract_item(ferret, frame, px, length, &offset, &object, &object_len); extract_item(ferret, frame, px, length, &offset, &type, &type_len); extract_item(ferret, frame, px, length, &offset, &zone, &zone_len); if (offset > length) break; switch (nbp.op) { case 2: JOTDOWN(ferret, JOT_SRC("ID-ATALK", frame), JOT_PRINT("Lookup", type, type_len), JOT_PRINT("Object", object, object_len), JOT_PRINT("Zone", zone, zone_len), 0); break; default: FRAMERR(frame, "%s: not implemented\n", "NBP"); } } }