Index: Makefile.in =================================================================== --- Makefile.in (revision 17360) +++ Makefile.in (working copy) @@ -230,6 +230,7 @@ $(INSTALL) -c -m 644 docs/nmap.xsl $(DESTDIR)$(nmapdatadir)/ $(INSTALL) -c -m 644 docs/nmap.dtd $(DESTDIR)$(nmapdatadir)/ $(INSTALL) -c -m 644 nmap-services $(DESTDIR)$(nmapdatadir)/ + $(INSTALL) -c -m 644 nmap-payloads $(DESTDIR)$(nmapdatadir)/ $(INSTALL) -c -m 644 nmap-rpc $(DESTDIR)$(nmapdatadir)/ $(INSTALL) -c -m 644 nmap-os-db $(DESTDIR)$(nmapdatadir)/ $(INSTALL) -c -m 644 nmap-service-probes $(DESTDIR)$(nmapdatadir)/ Index: nmap.cc =================================================================== --- nmap.cc (revision 17360) +++ nmap.cc (working copy) @@ -102,6 +102,7 @@ #include "nmap_tty.h" #include "nmap_dns.h" #include "services.h" +#include "payload.h" #include "protocols.h" #include "targets.h" #include "TargetGroup.h" @@ -1350,6 +1351,9 @@ tty_init(); // Put the keyboard in raw mode + // XXX jrf + init_payloads(); + // After the arguments are fully processed we now make any of the timing // tweaks the user might've specified: if (pre_max_parallelism != -1) o.max_parallelism = pre_max_parallelism; Index: payload.h =================================================================== --- payload.h (revision 17360) +++ payload.h (working copy) @@ -92,6 +92,7 @@ #ifndef PAYLOAD_H #define PAYLOAD_H +int init_payloads(void); const char *get_udp_payload(u16 dport, size_t *length); const char *udp_port2payload(u16 dport, size_t *length); Index: payload.cc =================================================================== --- payload.cc (revision 17360) +++ payload.cc (working copy) @@ -93,163 +93,186 @@ #include "nbase.h" #include "payload.h" +#include "utils.h" extern NmapOps o; -/* - These payloads are sent with every host discovery or port scan probe. Only - include payloads that are unlikely to crash services, trip IDS alerts, or - change state on the server. +//#define DEBUG - Some of them are taken from nmap-service-probes. -*/ +// Where we will keep each protocol,port,payload +struct data; +struct proto_dport; +static std::map payload; -static const char payload_GenericLines[] = "\x0D\x0A\x0D\x0A"; -static const char payload_DNSStatusRequest[] = - "\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00"; -static const char payload_RPCCheck[] = - "\x72\xFE\x1D\x13\x00\x00\x00\x00\x00\x00\x00\x02\x00\x01\x86\xA0" - "\x00\x01\x97\x7C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00"; -static const char payload_NTPRequest[] = - "\xE3\x00\x04\xFA\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00\xC5\x4F\x23\x4B\x71\xB1\x52\xF3"; -static const char payload_NBTStat[] = - "\x80\xF0\x00\x10\x00\x01\x00\x00\x00\x00\x00\x00" - "\x20" "CKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x00\x00\x21\x00\x01"; -static const char payload_SNMPv3GetRequest[] = - "\x30\x3A\x02\x01\x03\x30\x0F\x02\x02\x4A\x69\x02\x03\x00\xFF\xE3" - "\x04\x01\x04\x02\x01\x03\x04\x10\x30\x0E\x04\x00\x02\x01\x00\x02" - "\x01\x00\x04\x00\x04\x00\x04\x00\x30\x12\x04\x00\x04\x00\xA0\x0C" - "\x02\x02\x37\xF0\x02\x01\x00\x02\x01\x00\x30\x00"; +#define MAXPORTS 32 // XXX Not sure if this should go here or somewhere else +#define BUFLEN 1024 // XXX Not sure if we should do this or use limits.h -/* X Display Manager Control Protocol. Version 1, packet type Query (2), no - authorization names. We expect a Willing or Unwilling packet in reply. - http://cgit.freedesktop.org/xorg/doc/xorg-docs/plain/hardcopy/XDMCP/xdmcp.PS.gz */ -static const char payload_xdmcp[] = "\x00\x01\x00\x02\x00\x01\x00"; +using namespace std; // to use std::map and std::string -/* -This one trips a Snort rule with SID 2049 ("MS-SQL ping attempt"). -static const char payload_Sqlping[] = "\x02"; -*/ +// The actual data structures +struct data { + string payload_data; +}; -/* Internet Key Exchange version 1, phase 1 Main Mode. We offer every - combination of (DES, 3DES) and (MD5, SHA) in the hope that one of them will - be acceptable. Because we use a fixed cookie, we set the association lifetime - to 1 second to reduce the chance that repeated probes will look like - retransmissions (and therefore not get a response). This payload comes from - ike-scan --lifetime 1 --cookie 0011223344556677 --trans=5,2,1,2 --trans=5,1,1,2 --trans=1,2,1,2 --trans=1,1,1,2 - We expect another phase 1 message in response. This payload works better with - a source port of 500 or a randomized initiator cookie. */ -static const char payload_ike[] = - /* Initiator cookie 0x0011223344556677, responder cookie 0x0000000000000000. */ - "\x00\x11\x22\x33\x44\x55\x66\x77\x00\x00\x00\x00\x00\x00\x00\x00" - /* Version 1, Main Mode, flags 0x00, message ID 0x00000000, length 192. */ - "\x01\x10\x02\x00\x00\x00\x00\x00\x00\x00\x00\xC0" - /* Security Association payload, length 164, IPSEC, IDENTITY. */ - "\x00\x00\x00\xA4\x00\x00\x00\x01\x00\x00\x00\x01" - /* Proposal 1, length 152, ISAKMP, 4 transforms. */ - "\x00\x00\x00\x98\x01\x01\x00\x04" - /* Transform 1, 3DES-CBC, SHA, PSK, group 2. */ - "\x03\x00\x00\x24\x01\x01\x00\x00\x80\x01\x00\x05\x80\x02\x00\x02" - "\x80\x03\x00\x01\x80\x04\x00\x02" - "\x80\x0B\x00\x01\x00\x0C\x00\x04\x00\x00\x00\x01" - /* Transform 2, 3DES-CBC, MD5, PSK, group 2. */ - "\x03\x00\x00\x24\x02\x01\x00\x00\x80\x01\x00\x05\x80\x02\x00\x01" - "\x80\x03\x00\x01\x80\x04\x00\x02" - "\x80\x0B\x00\x01\x00\x0C\x00\x04\x00\x00\x00\x01" - /* Transform 3, DES-CBC, SHA, PSK, group 2. */ - "\x03\x00\x00\x24\x03\x01\x00\x00\x80\x01\x00\x01\x80\x02\x00\x02" - "\x80\x03\x00\x01\x80\x04\x00\x02" - "\x80\x0B\x00\x01\x00\x0C\x00\x04\x00\x00\x00\x01" - /* Transform 4, DES-CBC, MD5, PSK, group 2. */ - "\x00\x00\x00\x24\x04\x01\x00\x00\x80\x01\x00\x01\x80\x02\x00\x01" - "\x80\x03\x00\x01\x80\x04\x00\x02" - "\x80\x0B\x00\x01\x00\x0C\x00\x04\x00\x00\x00\x01"; +struct proto_dport { + u8 proto; + u16 dport; -/* Routing Information Protocol version 1. Special-case request for the entire - routing table (address family 0, address 0.0.0.0, metric 16). RFC 1058, - section 3.4.1. */ -static const char payload_rip[] = - "\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x10"; + bool operator<(const proto_dport& other) const { + if (proto == other.proto) + return dport < other.dport; + else + return proto < other.proto; + } -/* RADIUS Access-Request. This is a degenerate packet with no username or - password; we expect an Access-Reject in response. The Identifier and Request - Authenticator are both 0. It was generated by running - echo 'User-Password = ""' | radclient auth "" - and then manually stripping out the password. +}; - Section 2 of the RFC says "A request from a client for which the RADIUS - server does not have a shared secret MUST be silently discarded." So this - payload only works when the server is configured (or misconfigured) to know - the scanning machine as a client. */ -static const char payload_radius[] = - "\x01\x00\x00\x14" - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; +/* ck4dups: Make sure that a protocol/destination port pair is not already + * in the table. + */ +static int ck4dups(u8 proto, u16 dport) { + proto_dport pp; + std::map::iterator i; -/* NFS version 2, RFC 1831. XID 0x00000000, program 100003 (NFS), procedure - NFSPROC_NULL (does nothing, see section 2.2.1), null authentication (see - section 9.1). */ -static const char payload_nfs[] = - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x01\x86\xA3" - "\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00"; + pp.proto = proto; + pp.dport = dport; -/* DNS Service Discovery (DNS-SD) service query, as used in Zeroconf. - Transaction ID 0x0000, flags 0x0000, 1 question: PTR query for - _services._dns-sd._udp.local. If the remote host supports DNS-SD it will send - back a list of all its services. This is the same as a packet capture of - dns-sd -B _services._dns-sd._udp . - See section 9 of - http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt. */ -static const char payload_dns_sd[] = - "\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00" - "\x09_services\x07_dns-sd\x04_udp\x05local\x00\x00\x0C\x00\x01"; + i = payload.find(pp); + if (i != payload.end()) { + printf("Duplicate proto/port pair, skipping %i %i proto and port\n", + pp.proto,pp.dport); + return 1; + } -/* Amanda backup service noop request. I think that this does nothing on the - server but only asks it to send back its feature list. In reply we expect an - ACK or (more likely) an ERROR. I couldn't find good online documentation of - the Amanda network protocol. There is parsing code in the Amanda source at - common-src/security-util.c. This is based on a packet capture of - amcheck */ -static const char payload_amanda[] = - "Amanda 2.6 REQ HANDLE 000-00000000 SEQ 0\n" - "SERVICE noop\n"; + return 0; +} -/* Citrix MetaFrame application browser service - Original idea from http://sh0dan.org/oldfiles/hackingcitrix.html - Payload contents copied from Wireshark capture of Citrix Program - Neighborhood client application. The application uses this payload to - locate Citrix servers on the local network. Response to this probe is - a 48 byte UDP payload as shown here: +/* add_payload: Add a single payload to the global payload map. */ +static void add_payload (u8 proto, char portnos[256], char npayload[BUFLEN*4]) { + unsigned int len; + int portlist[MAXPORTS]; + char *s, *token, *payload_string = NULL; - 0000 30 00 02 31 02 fd a8 e3 02 00 06 44 c0 a8 80 55 - 0010 00 00 00 00 00 00 00 00 00 00 00 00 02 00 06 44 - 0020 c0 a8 80 56 00 00 00 00 00 00 00 00 00 00 00 00 + for (int i = 0; i <= MAXPORTS; i++) + portlist[i] = 0; - The first 12 bytes appear to be the same in all responses. + s = portnos; + int x = 0; + while ((token = strtok(s, ",")) != NULL) { + s = NULL; + if (x < MAXPORTS) + portlist[x++] = atoi(token); + else { // Integration: change to fatal() + fprintf(stderr, "Too many ports listed, please adjust MAXPORTS"); + exit (EXIT_FAILURE); + } + } - Bytes 0x00 appears to be a packet length field - Bytes 0x0C - 0x0F are the IP address of the server - Bytes 0x10 - 0x13 may vary, 0x14 - 0x1F do not appear to - Bytes 0x20 - 0x23 are the IP address of the primary system in a server farm - configuration - Bytes 0x24 - 0x27 can vary, 0x28 - 0x2F do not appear to */ -static const char payload_citrix[] = - "\x1e\x00\x01\x30\x02\xfd\xa8\xe3\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; + payload_string = &npayload[0]; + len = sizeof(payload_string); +#ifndef DEBUG + if (!cstring_unescape(payload_string,&len)) { + fprintf(stderr, "Escaping string failure!\n"); + exit (EXIT_FAILURE); + } +#endif + for (int y = 0; y < MAXPORTS; y++) { + if (portlist[y] == 0) + break; -/* Quake 2 and Quake 3 game servers (and servers of derived games like Nexuiz). - Gets game information from the server (see probe responses in - nmap-service-probes). */ -static const char payload_quake2[] = "\xff\xff\xff\xffstatus"; -static const char payload_quake3[] = "\xff\xff\xff\xffgetstatus"; + proto_dport pp; + pp.proto = proto; + pp.dport = portlist[y]; -static const char payload_null[] = ""; + if (ck4dups(pp.proto,pp.dport) == 1) + continue; + data pl; + pl.payload_data.assign(payload_string); + payload[pp] = pl; + } +} +/* + * init_payloads: Loop through the payloads file and load all payloads into a + * global table. + */ +int init_payloads (void) { + int cnt, res, processing = 0; + FILE *fp; + char *p; + char filename[512]; + char buf[BUFLEN], line[BUFLEN], proto[256], portnos[256], portnos_tmp[256]; + char cval[BUFLEN], tmp_payload[BUFLEN * 4]; + + if (nmap_fetchfile(filename, sizeof(filename), "nmap-payloads") != 1) { + error("Unable to find nmap-payloads"); + exit (EXIT_FAILURE); + } + + memset(tmp_payload, '\0', (BUFLEN * 4)); // clear out tmp_payload + memset(proto, '\0', (256)); // clear out tmp_payload + fp = fopen(filename, "r"); // open the payloads file read only + if (!fp) return 1; // if we cannot then return 1 + + /* This is kind of a mess: + * - For each line, if this is the first payload set processing to 1 + * - Otherwise assume we are still building a new payload string and + * add it to tmp_payload + * - Or if we see another new port/pair add the current tmp_payload to + * the global table. + */ + while(fgets(line, sizeof(line), fp)) { + p = line; + while(*p && isspace((int) (unsigned char) *p)) + p++; + if (*p == '#') // Skip comments + continue; + + // New proto/port pair + if (!strncmp(proto, "udp", 3)) + strcpy(portnos_tmp, portnos); + + // XXX this should be a number calculated by MAX PORTNOS + res = sscanf(line, "%4s %4096s", proto, portnos); + if ((res == 2) && (!strncmp(proto, "udp", 3))) { + if (processing == 1) { // If we hit a new pair add tmp_payload to maptable + add_payload(IPPROTO_UDP, portnos_tmp, tmp_payload); + memset(tmp_payload, '\0', (BUFLEN * 4)); // clear tmp variable + } else + processing = 1; + } + + // Clean up each line as we read it in + if (strstr(line, "\"") != (char *)NULL) { + strncpy(buf, strstr(line, "\"") + 1, BUFLEN); + cnt = 0; + while (cnt < BUFLEN - 1) { + if ((isprint(buf[cnt])) && buf[cnt] != '"') + cval[cnt] = buf[cnt]; + else { + cval[cnt] = '\0'; + break; + } + + cnt++; + } + + cval[BUFLEN - 1] = '\0'; + strcat(tmp_payload, cval); + } + } + + fclose(fp); + + // I don't exactly like this but if there is still a payload left to be + // added do so now.... + if (tmp_payload) + add_payload(IPPROTO_UDP, portnos_tmp, tmp_payload); + return 0; +} + + /* Get a payload appropriate for the given UDP port. If --data-length was used, returns the global random payload. Otherwise, for certain selected ports a payload is returned, and for others a zero-length payload is returned. The @@ -268,77 +291,20 @@ a payload is returned, and for others a zero-length payload is returned. The length is returned through the length pointer. */ const char *udp_port2payload(u16 dport, size_t *length){ - const char *payload; - #define SET_PAYLOAD(p) do { *length = sizeof(p) - 1; payload = (p); } while (0) + std::map::iterator it; + proto_dport pp; + string retstr; - switch (dport) { - case 7: - SET_PAYLOAD(payload_GenericLines); - break; - case 53: - SET_PAYLOAD(payload_DNSStatusRequest); - break; - case 111: - SET_PAYLOAD(payload_RPCCheck); - break; - case 123: - SET_PAYLOAD(payload_NTPRequest); - break; - case 137: - SET_PAYLOAD(payload_NBTStat); - break; - case 161: - SET_PAYLOAD(payload_SNMPv3GetRequest); - break; - case 177: - SET_PAYLOAD(payload_xdmcp); - break; - case 500: - SET_PAYLOAD(payload_ike); - break; - case 520: - SET_PAYLOAD(payload_rip); - break; - /* - case 1434: - SET_PAYLOAD(payload_Sqlping); - break; - */ - case 1604: - SET_PAYLOAD(payload_citrix); - break; - /* RFC 2865: "The early deployment of RADIUS was done using UDP port number - 1645, which conflicts with the "datametrics" service. The officially - assigned port number for RADIUS is 1812. */ - case 1645: - case 1812: - SET_PAYLOAD(payload_radius); - break; - case 2049: - SET_PAYLOAD(payload_nfs); - break; - case 5353: - SET_PAYLOAD(payload_dns_sd); - break; - case 10080: - SET_PAYLOAD(payload_amanda); - break; - /* These servers are commonly run on a base port or a few port numbers - higher. */ - case 27910: case 27911: case 27912: case 27913: case 27914: - SET_PAYLOAD(payload_quake2); - break; - case 26000: case 26001: case 26002: case 26003: case 26004: /* Nexuiz */ - case 27960: case 27961: case 27962: case 27963: case 27964: /* Several */ - case 30720: case 30721: case 30722: case 30723: case 30724: /* Tremulous */ - case 44400: /* Warsow */ - SET_PAYLOAD(payload_quake3); - break; - default: - SET_PAYLOAD(payload_null); - break; + pp.proto = IPPROTO_UDP; + pp.dport = dport; + + it = payload.find(pp); + if (it != payload.end()) { + retstr.assign(it->second.payload_data.data()); + //SET_PAYLOAD(retstr.c_str()); + return (retstr.c_str()); } - return payload; + return NULL; }