123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- /*
- * ZMap Copyright 2013 Regents of the University of Michigan
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy
- * of the License at http://www.apache.org/licenses/LICENSE-2.0
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <stdint.h>
- #include <unistd.h>
- #include <string.h>
- #include <assert.h>
- #include "../../lib/includes.h"
- #include "../../lib/logger.h"
- #include "../fieldset.h"
- #include "probe_modules.h"
- #include "packet.h"
- #include "module_udp.h"
- static const char *upnp_query = "M-SEARCH * HTTP/1.1\r\n"
- "Host:239.255.255.250:1900\r\n"
- "ST:upnp:rootdevice\r\n"
- "Man:\"ssdp:discover\"\r\nMX:3\r\n\r\n";
- probe_module_t module_upnp;
- #define ICMP_UNREACH_HEADER_SIZE 8
- int upnp_global_initialize(struct state_conf *state)
- {
- int num_ports = state->source_port_last - state->source_port_first + 1;
- udp_set_num_ports(num_ports);
- return EXIT_SUCCESS;
- }
- int upnp_init_perthread(void* buf, macaddr_t *src, macaddr_t *gw,
- port_h_t dst_port, __attribute__((unused)) void **arg_ptr)
- {
- memset(buf, 0, MAX_PACKET_SIZE);
- struct ether_header *eth_header = (struct ether_header *) buf;
- make_eth_header(eth_header, src, gw);
- struct ip *ip_header = (struct ip*)(ð_header[1]);
- uint16_t len = htons(sizeof(struct ip) + sizeof(struct udphdr) + strlen(upnp_query));
- make_ip_header(ip_header, IPPROTO_UDP, len);
- struct udphdr *udp_header = (struct udphdr*)(&ip_header[1]);
- len = sizeof(struct udphdr) + strlen(upnp_query);
- make_udp_header(udp_header, dst_port, len);
- char* payload = (char*)(&udp_header[1]);
- assert(sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct udphdr)
- + strlen(upnp_query) <= MAX_PACKET_SIZE);
- assert(MAX_PACKET_SIZE - ((char*)payload - (char*)buf) > (int) strlen(upnp_query));
- strcpy(payload, upnp_query);
- return EXIT_SUCCESS;
- }
- int upnp_validate_packet(const struct ip *ip_hdr, uint32_t len,
- uint32_t *src_ip, uint32_t *validation)
- {
- if (!udp_validate_packet(ip_hdr, len, src_ip, validation)) {
- return 0;
- }
- if (ip_hdr->ip_p == IPPROTO_UDP) {
- struct udphdr *udp = (struct udphdr *) ((char *) ip_hdr + ip_hdr->ip_hl * 4);
- uint16_t sport = ntohs(udp->uh_sport);
- if (sport != zconf.target_port) {
- return 0;
- }
- }
- return 1;
- }
- void upnp_process_packet(const u_char *packet,
- __attribute__((unused)) uint32_t len, fieldset_t *fs)
- {
- struct ip *ip_hdr = (struct ip *) &packet[sizeof(struct ether_header)];
- if (ip_hdr->ip_p == IPPROTO_UDP) {
- struct udphdr *udp = (struct udphdr *) ((char *) ip_hdr + ip_hdr->ip_hl * 4);
- char *payload = (char*)(&udp[1]);
- uint16_t plen = udp->uh_ulen - 8;
- char *s = malloc(plen+1);
- //char *t = malloc(plen+1);
- assert(s);
- strncpy(s, payload, plen);
- //strncpy(t, payload, plen);
- s[plen] = 0;
- int is_first = 1;
- const char *classification = "none";
- uint64_t is_success = 0;
- char *server=NULL, *location=NULL, *usn=NULL, *st=NULL,
- *cachecontrol=NULL, *ext=NULL, *xusragent=NULL,
- *date=NULL, *agent=NULL;
- char *pch = strtok(s, "\n");
- while (pch != NULL) {
- if (pch[strlen(pch)-1] == '\r') {
- pch[strlen(pch)-1] = '\0';
- }
- if (strlen(pch) == 0) {
- pch = strtok(NULL, "\n");
- continue;
- }
- // the first pch is always supposed to be an HTTP response
- if (is_first) {
- if (strcmp(pch, "HTTP/1.1 200 OK")) {
- classification = "no-http-header";
- is_success = 0;
- goto cleanup;
- }
- is_first = 0;
- is_success = 1;
- classification = "upnp";
- pch = strtok(NULL, "\n");
- continue;
- }
- char *value = pch;
- char *key = strsep(&value, ":");
- if (value && value[0] == ' ') {
- value += (size_t)1;
- }
- if (!key) {
- pch = strtok(NULL, "\n");
- continue;
- }
- if (!value) {
- pch = strtok(NULL, "\n");
- continue;
- }
- if (!strcasecmp(key, "server")) {
- server = strdup(value);
- } else if (!strcasecmp(key, "location")) {
- location = strdup(value);
- } else if (!strcasecmp(key, "USN")) {
- usn = strdup(value);
- } else if (!strcasecmp(key, "EXT")) {
- ext = strdup(value);
- } else if (!strcasecmp(key, "ST")) {
- st = strdup(value);
- } else if (!strcasecmp(key, "Agent")) {
- agent = strdup(value);
- } else if (!strcasecmp(key, "X-User-Agent")) {
- xusragent = strdup(value);
- } else if (!strcasecmp(key, "date")) {
- date = strdup(value);
- } else if (!strcasecmp(key, "Cache-Control")) {
- cachecontrol = strdup(value);
- } else {
- //log_debug("upnp-module", "new key: %s", key);
- }
- pch = strtok(NULL, "\n");
- }
- cleanup:
- fs_add_string(fs, "classification", (char *) classification, 0);
- fs_add_uint64(fs, "success", is_success);
- if (server) {
- fs_add_string(fs, "server", server, 1);
- }
- else {
- fs_add_null(fs, "server");
- }
- if (location) {
- fs_add_string(fs, "location", location, 1);
- }
- else {
- fs_add_null(fs, "location");
- }
- if (usn) {
- fs_add_string(fs, "usn", usn, 1);
- }
- else {
- fs_add_null(fs, "usn");
- }
- if (st) {
- fs_add_string(fs, "st", st, 1);
- }
- else {
- fs_add_null(fs, "st");
- }
- if (ext) {
- fs_add_string(fs, "ext", ext, 1);
- }
- else {
- fs_add_null(fs, "ext");
- }
- if (cachecontrol) {
- fs_add_string(fs, "cache-control", cachecontrol, 1);
- }
- else {
- fs_add_null(fs, "cache-control");
- }
- if (xusragent) {
- fs_add_string(fs, "x-user-agent", xusragent, 1);
- }
- else {
- fs_add_null(fs, "x-user-agent");
- }
- if (agent) {
- fs_add_string(fs, "agent", agent, 1);
- }
- else {
- fs_add_null(fs, "agent");
- }
- if (date) {
- fs_add_string(fs, "date", date, 1);
- }
- else {
- fs_add_null(fs, "date");
- }
- fs_add_uint64(fs, "sport", ntohs(udp->uh_sport));
- fs_add_uint64(fs, "dport", ntohs(udp->uh_dport));
- fs_add_null(fs, "icmp_responder");
- fs_add_null(fs, "icmp_type");
- fs_add_null(fs, "icmp_code");
- fs_add_null(fs, "icmp_unreach_str");
- fs_add_binary(fs, "data", (ntohs(udp->uh_ulen) - sizeof(struct udphdr)), (void*) &udp[1], 0);
- free(s);
- } else if (ip_hdr->ip_p == IPPROTO_ICMP) {
- struct icmp *icmp = (struct icmp *) ((char *) ip_hdr + ip_hdr->ip_hl * 4);
- struct ip *ip_inner = (struct ip *) ((char *) icmp + ICMP_UNREACH_HEADER_SIZE);
- // ICMP unreach comes from another server (not the one we sent a probe to);
- // But we will fix up saddr to be who we sent the probe to, in case you care.
- fs_modify_string(fs, "saddr", make_ip_str(ip_inner->ip_dst.s_addr), 1);
- fs_add_string(fs, "classification", (char*) "icmp-unreach", 0);
- fs_add_uint64(fs, "success", 0);
- fs_add_null(fs, "server");
- fs_add_null(fs, "location");
- fs_add_null(fs, "usn");
- fs_add_null(fs, "st");
- fs_add_null(fs, "ext");
- fs_add_null(fs, "cache-control");
- fs_add_null(fs, "x-user-agent");
- fs_add_null(fs, "agent");
- fs_add_null(fs, "date");
- fs_add_null(fs, "sport");
- fs_add_null(fs, "dport");
- fs_add_string(fs, "icmp_responder", make_ip_str(ip_hdr->ip_src.s_addr), 1);
- fs_add_uint64(fs, "icmp_type", icmp->icmp_type);
- fs_add_uint64(fs, "icmp_code", icmp->icmp_code);
- if (icmp->icmp_code <= ICMP_UNREACH_PRECEDENCE_CUTOFF) {
- fs_add_string(fs, "icmp_unreach_str", (char *) udp_unreach_strings[icmp->icmp_code], 0);
- } else {
- fs_add_string(fs, "icmp_unreach_str", (char *) "unknown", 0);
- }
- fs_add_null(fs, "data");
- } else {
- fs_add_string(fs, "classification", (char *) "other", 0);
- fs_add_uint64(fs, "success", 0);
- fs_add_null(fs, "server");
- fs_add_null(fs, "location");
- fs_add_null(fs, "usn");
- fs_add_null(fs, "st");
- fs_add_null(fs, "ext");
- fs_add_null(fs, "cache-control");
- fs_add_null(fs, "x-user-agent");
- fs_add_null(fs, "agent");
- fs_add_null(fs, "date");
- fs_add_null(fs, "sport");
- fs_add_null(fs, "dport");
- fs_add_null(fs, "icmp_responder");
- fs_add_null(fs, "icmp_type");
- fs_add_null(fs, "icmp_code");
- fs_add_null(fs, "icmp_unreach_str");
- fs_add_null(fs, "data");
- }
- }
- static fielddef_t fields[] = {
- {.name = "classification", .type="string", .desc = "packet classification"},
- {.name = "success", .type="int", .desc = "is response considered success"},
- {.name = "server", .type="string", .desc = "UPnP server"},
- {.name = "location", .type="string", .desc = "UPnP location"},
- {.name = "usn", .type="string", .desc = "UPnP usn"},
- {.name = "st", .type="string", .desc = "UPnP st"},
- {.name = "ext", .type="string", .desc = "UPnP ext"},
- {.name = "cache-control", .type="string", .desc = "UPnP cache-control"},
- {.name = "x-user-agent", .type="string", .desc = "UPnP x-user-agent"},
- {.name = "agent", .type="string", .desc = "UPnP agent"},
- {.name = "date", .type="string", .desc = "UPnP date"},
- {.name = "sport", .type = "int", .desc = "UDP source port"},
- {.name = "dport", .type = "int", .desc = "UDP destination port"},
- {.name = "icmp_responder", .type = "string", .desc = "Source IP of ICMP_UNREACH message"},
- {.name = "icmp_type", .type = "int", .desc = "icmp message type"},
- {.name = "icmp_code", .type = "int", .desc = "icmp message sub type code"},
- {.name = "icmp_unreach_str", .type = "string", .desc = "for icmp_unreach responses, the string version of icmp_code (e.g. network-unreach)"},
- {.name = "data", .type="binary", .desc = "UDP payload"}
- };
- probe_module_t module_upnp = {
- .name = "upnp",
- .packet_length = 139,
- .pcap_filter = "udp || icmp",
- .pcap_snaplen = 1500,
- .port_args = 1,
- .global_initialize = &upnp_global_initialize,
- .thread_initialize = &upnp_init_perthread,
- .make_packet = &udp_make_packet,
- .print_packet = &udp_print_packet,
- .process_packet = &upnp_process_packet,
- .validate_packet = &upnp_validate_packet,
- .close = NULL,
- .helptext = "Probe module that sends a TCP SYN packet to a specific "
- "port. Possible classifications are: synack and rst. A "
- "SYN-ACK packet is considered a success and a reset packet "
- "is considered a failed response.",
- .fields = fields,
- .numfields = 18};
|