module_upnp.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. /*
  2. * ZMap Copyright 2013 Regents of the University of Michigan
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy
  6. * of the License at http://www.apache.org/licenses/LICENSE-2.0
  7. */
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <stdint.h>
  11. #include <unistd.h>
  12. #include <string.h>
  13. #include <assert.h>
  14. #include "../../lib/includes.h"
  15. #include "../../lib/logger.h"
  16. #include "../fieldset.h"
  17. #include "probe_modules.h"
  18. #include "packet.h"
  19. #include "module_udp.h"
  20. static const char *upnp_query = "M-SEARCH * HTTP/1.1\r\n"
  21. "Host:239.255.255.250:1900\r\n"
  22. "ST:upnp:rootdevice\r\n"
  23. "Man:\"ssdp:discover\"\r\nMX:3\r\n\r\n";
  24. probe_module_t module_upnp;
  25. #define ICMP_UNREACH_HEADER_SIZE 8
  26. int upnp_global_initialize(struct state_conf *state)
  27. {
  28. int num_ports = state->source_port_last - state->source_port_first + 1;
  29. udp_set_num_ports(num_ports);
  30. return EXIT_SUCCESS;
  31. }
  32. int upnp_init_perthread(void* buf, macaddr_t *src, macaddr_t *gw,
  33. port_h_t dst_port, __attribute__((unused)) void **arg_ptr)
  34. {
  35. memset(buf, 0, MAX_PACKET_SIZE);
  36. struct ether_header *eth_header = (struct ether_header *) buf;
  37. make_eth_header(eth_header, src, gw);
  38. struct ip *ip_header = (struct ip*)(&eth_header[1]);
  39. uint16_t len = htons(sizeof(struct ip) + sizeof(struct udphdr) + strlen(upnp_query));
  40. make_ip_header(ip_header, IPPROTO_UDP, len);
  41. struct udphdr *udp_header = (struct udphdr*)(&ip_header[1]);
  42. len = sizeof(struct udphdr) + strlen(upnp_query);
  43. make_udp_header(udp_header, dst_port, len);
  44. char* payload = (char*)(&udp_header[1]);
  45. assert(sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct udphdr)
  46. + strlen(upnp_query) <= MAX_PACKET_SIZE);
  47. assert(MAX_PACKET_SIZE - ((char*)payload - (char*)buf) > (int) strlen(upnp_query));
  48. strcpy(payload, upnp_query);
  49. return EXIT_SUCCESS;
  50. }
  51. int upnp_validate_packet(const struct ip *ip_hdr, uint32_t len,
  52. uint32_t *src_ip, uint32_t *validation)
  53. {
  54. if (!udp_validate_packet(ip_hdr, len, src_ip, validation)) {
  55. return 0;
  56. }
  57. if (ip_hdr->ip_p == IPPROTO_UDP) {
  58. struct udphdr *udp = (struct udphdr *) ((char *) ip_hdr + ip_hdr->ip_hl * 4);
  59. uint16_t sport = ntohs(udp->uh_sport);
  60. if (sport != zconf.target_port) {
  61. return 0;
  62. }
  63. }
  64. return 1;
  65. }
  66. void upnp_process_packet(const u_char *packet,
  67. __attribute__((unused)) uint32_t len, fieldset_t *fs)
  68. {
  69. struct ip *ip_hdr = (struct ip *) &packet[sizeof(struct ether_header)];
  70. if (ip_hdr->ip_p == IPPROTO_UDP) {
  71. struct udphdr *udp = (struct udphdr *) ((char *) ip_hdr + ip_hdr->ip_hl * 4);
  72. char *payload = (char*)(&udp[1]);
  73. uint16_t plen = udp->uh_ulen - 8;
  74. char *s = malloc(plen+1);
  75. //char *t = malloc(plen+1);
  76. assert(s);
  77. strncpy(s, payload, plen);
  78. //strncpy(t, payload, plen);
  79. s[plen] = 0;
  80. int is_first = 1;
  81. const char *classification = "none";
  82. uint64_t is_success = 0;
  83. char *server=NULL, *location=NULL, *usn=NULL, *st=NULL,
  84. *cachecontrol=NULL, *ext=NULL, *xusragent=NULL,
  85. *date=NULL, *agent=NULL;
  86. char *pch = strtok(s, "\n");
  87. while (pch != NULL) {
  88. if (pch[strlen(pch)-1] == '\r') {
  89. pch[strlen(pch)-1] = '\0';
  90. }
  91. if (strlen(pch) == 0) {
  92. pch = strtok(NULL, "\n");
  93. continue;
  94. }
  95. // the first pch is always supposed to be an HTTP response
  96. if (is_first) {
  97. if (strcmp(pch, "HTTP/1.1 200 OK")) {
  98. classification = "no-http-header";
  99. is_success = 0;
  100. goto cleanup;
  101. }
  102. is_first = 0;
  103. is_success = 1;
  104. classification = "upnp";
  105. pch = strtok(NULL, "\n");
  106. continue;
  107. }
  108. char *value = pch;
  109. char *key = strsep(&value, ":");
  110. if (value && value[0] == ' ') {
  111. value += (size_t)1;
  112. }
  113. if (!key) {
  114. pch = strtok(NULL, "\n");
  115. continue;
  116. }
  117. if (!value) {
  118. pch = strtok(NULL, "\n");
  119. continue;
  120. }
  121. if (!strcasecmp(key, "server")) {
  122. server = strdup(value);
  123. } else if (!strcasecmp(key, "location")) {
  124. location = strdup(value);
  125. } else if (!strcasecmp(key, "USN")) {
  126. usn = strdup(value);
  127. } else if (!strcasecmp(key, "EXT")) {
  128. ext = strdup(value);
  129. } else if (!strcasecmp(key, "ST")) {
  130. st = strdup(value);
  131. } else if (!strcasecmp(key, "Agent")) {
  132. agent = strdup(value);
  133. } else if (!strcasecmp(key, "X-User-Agent")) {
  134. xusragent = strdup(value);
  135. } else if (!strcasecmp(key, "date")) {
  136. date = strdup(value);
  137. } else if (!strcasecmp(key, "Cache-Control")) {
  138. cachecontrol = strdup(value);
  139. } else {
  140. //log_debug("upnp-module", "new key: %s", key);
  141. }
  142. pch = strtok(NULL, "\n");
  143. }
  144. cleanup:
  145. fs_add_string(fs, "classification", (char *) classification, 0);
  146. fs_add_uint64(fs, "success", is_success);
  147. if (server) {
  148. fs_add_string(fs, "server", server, 1);
  149. }
  150. else {
  151. fs_add_null(fs, "server");
  152. }
  153. if (location) {
  154. fs_add_string(fs, "location", location, 1);
  155. }
  156. else {
  157. fs_add_null(fs, "location");
  158. }
  159. if (usn) {
  160. fs_add_string(fs, "usn", usn, 1);
  161. }
  162. else {
  163. fs_add_null(fs, "usn");
  164. }
  165. if (st) {
  166. fs_add_string(fs, "st", st, 1);
  167. }
  168. else {
  169. fs_add_null(fs, "st");
  170. }
  171. if (ext) {
  172. fs_add_string(fs, "ext", ext, 1);
  173. }
  174. else {
  175. fs_add_null(fs, "ext");
  176. }
  177. if (cachecontrol) {
  178. fs_add_string(fs, "cache-control", cachecontrol, 1);
  179. }
  180. else {
  181. fs_add_null(fs, "cache-control");
  182. }
  183. if (xusragent) {
  184. fs_add_string(fs, "x-user-agent", xusragent, 1);
  185. }
  186. else {
  187. fs_add_null(fs, "x-user-agent");
  188. }
  189. if (agent) {
  190. fs_add_string(fs, "agent", agent, 1);
  191. }
  192. else {
  193. fs_add_null(fs, "agent");
  194. }
  195. if (date) {
  196. fs_add_string(fs, "date", date, 1);
  197. }
  198. else {
  199. fs_add_null(fs, "date");
  200. }
  201. fs_add_uint64(fs, "sport", ntohs(udp->uh_sport));
  202. fs_add_uint64(fs, "dport", ntohs(udp->uh_dport));
  203. fs_add_null(fs, "icmp_responder");
  204. fs_add_null(fs, "icmp_type");
  205. fs_add_null(fs, "icmp_code");
  206. fs_add_null(fs, "icmp_unreach_str");
  207. fs_add_binary(fs, "data", (ntohs(udp->uh_ulen) - sizeof(struct udphdr)), (void*) &udp[1], 0);
  208. free(s);
  209. } else if (ip_hdr->ip_p == IPPROTO_ICMP) {
  210. struct icmp *icmp = (struct icmp *) ((char *) ip_hdr + ip_hdr->ip_hl * 4);
  211. struct ip *ip_inner = (struct ip *) ((char *) icmp + ICMP_UNREACH_HEADER_SIZE);
  212. // ICMP unreach comes from another server (not the one we sent a probe to);
  213. // But we will fix up saddr to be who we sent the probe to, in case you care.
  214. fs_modify_string(fs, "saddr", make_ip_str(ip_inner->ip_dst.s_addr), 1);
  215. fs_add_string(fs, "classification", (char*) "icmp-unreach", 0);
  216. fs_add_uint64(fs, "success", 0);
  217. fs_add_null(fs, "server");
  218. fs_add_null(fs, "location");
  219. fs_add_null(fs, "usn");
  220. fs_add_null(fs, "st");
  221. fs_add_null(fs, "ext");
  222. fs_add_null(fs, "cache-control");
  223. fs_add_null(fs, "x-user-agent");
  224. fs_add_null(fs, "agent");
  225. fs_add_null(fs, "date");
  226. fs_add_null(fs, "sport");
  227. fs_add_null(fs, "dport");
  228. fs_add_string(fs, "icmp_responder", make_ip_str(ip_hdr->ip_src.s_addr), 1);
  229. fs_add_uint64(fs, "icmp_type", icmp->icmp_type);
  230. fs_add_uint64(fs, "icmp_code", icmp->icmp_code);
  231. if (icmp->icmp_code <= ICMP_UNREACH_PRECEDENCE_CUTOFF) {
  232. fs_add_string(fs, "icmp_unreach_str", (char *) udp_unreach_strings[icmp->icmp_code], 0);
  233. } else {
  234. fs_add_string(fs, "icmp_unreach_str", (char *) "unknown", 0);
  235. }
  236. fs_add_null(fs, "data");
  237. } else {
  238. fs_add_string(fs, "classification", (char *) "other", 0);
  239. fs_add_uint64(fs, "success", 0);
  240. fs_add_null(fs, "server");
  241. fs_add_null(fs, "location");
  242. fs_add_null(fs, "usn");
  243. fs_add_null(fs, "st");
  244. fs_add_null(fs, "ext");
  245. fs_add_null(fs, "cache-control");
  246. fs_add_null(fs, "x-user-agent");
  247. fs_add_null(fs, "agent");
  248. fs_add_null(fs, "date");
  249. fs_add_null(fs, "sport");
  250. fs_add_null(fs, "dport");
  251. fs_add_null(fs, "icmp_responder");
  252. fs_add_null(fs, "icmp_type");
  253. fs_add_null(fs, "icmp_code");
  254. fs_add_null(fs, "icmp_unreach_str");
  255. fs_add_null(fs, "data");
  256. }
  257. }
  258. static fielddef_t fields[] = {
  259. {.name = "classification", .type="string", .desc = "packet classification"},
  260. {.name = "success", .type="int", .desc = "is response considered success"},
  261. {.name = "server", .type="string", .desc = "UPnP server"},
  262. {.name = "location", .type="string", .desc = "UPnP location"},
  263. {.name = "usn", .type="string", .desc = "UPnP usn"},
  264. {.name = "st", .type="string", .desc = "UPnP st"},
  265. {.name = "ext", .type="string", .desc = "UPnP ext"},
  266. {.name = "cache-control", .type="string", .desc = "UPnP cache-control"},
  267. {.name = "x-user-agent", .type="string", .desc = "UPnP x-user-agent"},
  268. {.name = "agent", .type="string", .desc = "UPnP agent"},
  269. {.name = "date", .type="string", .desc = "UPnP date"},
  270. {.name = "sport", .type = "int", .desc = "UDP source port"},
  271. {.name = "dport", .type = "int", .desc = "UDP destination port"},
  272. {.name = "icmp_responder", .type = "string", .desc = "Source IP of ICMP_UNREACH message"},
  273. {.name = "icmp_type", .type = "int", .desc = "icmp message type"},
  274. {.name = "icmp_code", .type = "int", .desc = "icmp message sub type code"},
  275. {.name = "icmp_unreach_str", .type = "string", .desc = "for icmp_unreach responses, the string version of icmp_code (e.g. network-unreach)"},
  276. {.name = "data", .type="binary", .desc = "UDP payload"}
  277. };
  278. probe_module_t module_upnp = {
  279. .name = "upnp",
  280. .packet_length = 139,
  281. .pcap_filter = "udp || icmp",
  282. .pcap_snaplen = 1500,
  283. .port_args = 1,
  284. .global_initialize = &upnp_global_initialize,
  285. .thread_initialize = &upnp_init_perthread,
  286. .make_packet = &udp_make_packet,
  287. .print_packet = &udp_print_packet,
  288. .process_packet = &upnp_process_packet,
  289. .validate_packet = &upnp_validate_packet,
  290. .close = NULL,
  291. .helptext = "Probe module that sends a TCP SYN packet to a specific "
  292. "port. Possible classifications are: synack and rst. A "
  293. "SYN-ACK packet is considered a success and a reset packet "
  294. "is considered a failed response.",
  295. .fields = fields,
  296. .numfields = 18};