Building Open Source Network Security Tools Invictus Ferramenta Mike Schiffman The RSA Conference, April 2003 Today’s Presentation is an Overview of This: Agenda 1. Introduction and Overview 2. The Modular Model of Network Security Tools 3. The Component and Technique Layers 4. Network Security Tool Classification 5. Active and Passive Reconnaissance Technique Details 6. Modeling Existing Tools 7. Inside a Network Security Tool: Firewalk Internals 8. Questions and Comments Primer on Mike Schiffman • Researcher, Cisco Systems • Critical Infrastructure Assurance Group (CIAG), Cisco Systems • Technical Advisory Board for Qualys, IMG Universal • Consulting Editor for Wiley & Sons • R&D, Consulting and Speaking background: • Firewalk, Libnet, Libsf, Libradiate, Various whitepapers and reports • Done time with: @stake, Guardent, Cambridge Technology Partners, ISS • Author: • Building Open Source Network Security Tools, Wiley & Sons • Hacker’s Challenge Book I, Osborne McGraw-Hill • Hacker’s Challenge Book II, Osborne McGraw-Hill Overview • What you will learn today • A new model for conceptualizing and describing network security tools • How to apply this model to existing tools • How to use this model to rapidly build new tools • Common network security tool techniques and how they are codified • What you should already know • General understanding of the TCP/IP protocol suite • Primarily layers 1 – 3 (OSI layers 2 – 4) • General network security concepts • For example; the difference between packet sniffing and port scanning • The C programming language Before we start… • Where should I spend my focus…? • Lots of material • Show of hands… • Libnet • Libpcap • The Paradigm and NST terminology • Code? Paradigm Overview Technically Accurate. Not Tangible. What is a Network Security Tool? A network security tool is an algorithmic implement that is esigned to probe, assess, or increase the overall safety of or mitigate We need something risk associated withbetter… an entity across a communications medium. (there is something better) Unwieldy. Too Clinical. A (New) Paradigm • Functional • Tangible and Visual • Specifies a simple taxonomy for grouping and ordering tools • Tool Classifications • Separates a network security tool into three layers or tiers • Component, Technique, Control • Hierarchical dependencies • An object at a higher layer has dependencies on one or more objects below it The Modular Model of Network Security Tools denotes layer dependency denotes class binding ... Control Class T1 Technique Component C1 T3 C2 Class C3 The Component Layer • Most fundamental layer • Answers the question “How does this tool do what it does?” • Task oriented and specific • Components tend to outlay the developmental requirements and restraints of the tool • Software Development Lifecycle • C programming libraries • Robust, portable and generally simple APIs • Libpcap, Libnet, Libsf, Libnids, Libdnet, OpenSSL The Component Layer with Dependencies denotes dependency libnids TCP port scan detection libsf active fingerprinting TCP stream reassembly IP defragmentation passive fingerprinting libdnet addressing ARP and route blob and PRNG interface firewall ethernet and IP packet filtering packet construction general purpose cryptography packet capturing packet injection SSL / TLS libpcap libnet openssl The Technique Layer • Answers the question: “What does this tool do?” • More abstract and solution focused • The core essence of the tool is captured at this layer • When building or classifying tools, we start here • Class taxonomy is set at this layer • Packet Sniffing (Passive Reconnaissance) • Port Scanning (Active Reconnaissance) • Vulnerability Testing (Attack and Penetration) • Firewalling (Defensive) Network Security Tool Taxonomy • Simple method allowing for tool grouping • Tied to the Technique Layer • Tools may certainly fit in more than one category (Venn diagram) • Passive Reconnaissance • Active Reconnaissance • Attack and Penetration • Defensive The Technique Layer with Classification Bindings passive reconnaissance active reconnaissance attack and penetration port scanning vulnerability scanning intrusion detection IP expiry vulnerability testing firewalling packet sniffing Firewalking denotes tool class defensive encryption Classification Overview Passive Reconnaissance Tools • Gather information in an ostensibly non-detectable or unobtrusive way • Tend to have long lifecycles in terms of utility • Changes no state on the entity • Tcpdump • Ethereal • Mailsnarf Active Reconnaissance Tools • Gather information in a detectable way, often by sending network traffic and waiting for responses • Tend to have long lifecycles in terms of utility • Changes very little if any state on the entity • Firewalk • Strobe • Nmap • Traceroute Attack and Penetration Tools • Test for the existence of and/or exploit vulnerabilities • Tools can have a very limited lifetime • i.e.: Remote overflow in IIS version 5.0 • Often supported by Reconnaissance Tools • Nessus • SSH CRC32 overflow exploit • apache-scalp.c Defensive Tools • Keeps an entity safe often by protecting data or detecting illicit activity • Tend to be more complex and have extended execution lifetimes • Snort • GPG • PF (packet filter on OpenBSD) The Control Layer • General abstract “glue layer” • Can be thought of as a delivery mechanism for techniques • Less concerned with security-related topics as with program cohesion • Not the focus of this presentation • Command and Control • Reporting • Data Correlation and Storage The Model and The Software Development Lifecycle Modular model for network security tools requirements peer review / feedback analysis design coding maintenance deployment testing Component Layer Details Libpcap Libnet Libnids Libsf Libdnet OpenSSL Component Layer Details: Libpcap • Library for packet capture and filtering • Support for live capture and offline storage • Useful for building applications that need to do the following: • Network statistics collection • Network debugging • Security monitoring • Often found in active and passive reconnaissance tools Typical Libpcap Usage 1 Libpcap Context pcap_open_live() Libpcap Context 2 packet pcap_next() packet 3 PACKET PROCESSING Libpcap Context 4 pcap_close() Component Layer Details: Libnet • Library for packet construction and injection • Useful for building applications that need to do the following: • Network security testing • Network bandwidth testing • Network utility • Definitely the most debonair and sophisticated of the components – truly a discriminating programmer’s component • New version (1.1.1) is much more robust than its predecessors • Simple interface for novice users or • Powerful advanced interface • Often found in active reconnaissance and attack and penetration tools Typical Libnet Usage 1 Libnet context libnet_init() Libnet context 2 ptag libnet_build_tcp() Libnet context ptag libnet_build_ipv4( ) ptag Libnet context libnet_build_ether net() Libnet context Bytes written 3 libnet_write() Libnet context 4 libnet_destroy() Libnet Supported Protocols DNS NTP BOOTP DHCP Other Open Application Presentation Session TCP UDP Other Transport VRRP ICMP IGMP IP RIP, OSPF ESP AH Other Open Network CDP 802.1Q Ethernet II Data Link Physical 802.2, SNAP ARP, RARP 802.3 STP Other 4 bytes The Libnet Context libnet_t 1 byte 372 bytes fd int protocol int injection_type int protocol_blocks libnet_pblock_t * pblock_end libnet_pblock_t * link_type int link_offset int aligner int device char * stats struct libnet_stats ptag_state libnet_ptag_t label char[64] err_buf char[256] The Libnet Protocol Block 4 bytes libnet_pblock_t 1 byte buf u_char * b_len u_long h_len u_short, u_long copied 28 bytes type flag u_char, u_char ptag libnet_ptag_t next libnet_pblock_t * prev libnet_pblock_t * The Libnet Protocol Block single context, standard linkage for TCP header (prior to coalesce) TCP header IPv4 header 3 Ethernet header IPPROTO_RAW LIBNET_LINK 0xdfbf.... 0xdfbf.... 0xdfbf.... 0xdfbf.... 0xdfbf.... 20 20 14 link_type link_offset 20 40 0 14 copied 0x1e 0x01 copied 0x0d 0x01 copied 0x04 0 0xdfbf.... 1 2 3 0xdfbf.... 0xdfbf.... 0x00000000 0x00000000 0xdfbf.... 0xdfbf.... 0 3 “cardshark” 0 “fxp0” Component Layer Details: Libnids • Library that simulates a NIDS E-box • An E-box’s job is to sample the environment in which it is specialized for, and convert occurrences in the environment into standard data objects for subsequent storage and/or analysis. • Built on top of libpcap and libnet • Offers the following: • IP defragmentation • TCP stream reassembly • Time-based TCP port scan detection • Often found in defensive tools Component Layer Details: Libsf • Library for IP stack fingerprinting to perform remote OS detection • Built on top of libpcap and libnet • active and passive fingerprinting methods • Based off of the nmap database and P0f databases • Often found in reconnaissance tools Typical Libsf Usage 1 Libsf descriptor libsf_init() Libsf descriptor 2 libsf_active_id() Libsf descriptor 3 tm libsf_get_tm() Libsf descriptor 4 hs Libsf_get_hs() Libsf descriptor hs 5 OS libsf_os_get_match () Libsf descriptor 6 libsf_destroy() Libsf Active Fingerprinting Tests • Seven active tests can be performed using fringe packets: • TCP SYN to an open port • TCP NULL packet to an open port • TCP FIN|SYN|PSH|URG packet to an open port • TCP ACK packet to an open port • TCP SYN packet to a closed port • TCP ACK packet to a closed port • TCP FIN|PSH|URG to a closed port Libsf Passive Fingerprinting Tests • Eight passive tests can be preformed across incoming TCP SYN packets: • Determine original IP TTL • IP packet size • IP DF bit on or off • TCP window scale option present • TCP MSS option present • TCP SACK option present • TCP NOP option present • TCP window size Component Layer Details: Libdnet • Library for miscellaneous low-level network routines • Robust network address manipulation • Kernel ARP cache lookup and manipulation • Kernel route table lookup and manipulation • Network interface lookup and manipulation • Network firewall rule manipulation • Ethernet frame and IP packet transmission • Binary buffer manipulation • Random number manipulation • Often found in all tools Component Layer Details: OpenSSL • Library for SSL / TLS and general cryptography • SSL/TLS protocols • Symmetric cryptographic operations (ciphers, message digests) • Asymmetric cryptographic operations (digital signatures, enveloping) • Public Key Infrastructure (PKI), including OCSP, rich X509 certificate support, certificate verification, certificate requests, and CRLs • Often found in defensive tools Technique Layer Details Packet Sniffing Port Scanning IP Expiry Firewalking Technique Layer Details: Packet Sniffing • Passive Reconnaissance Technique • Used to capture packets on a network • Very powerful and useful in its own right • However it is also a fundamental building block in more complex tools • Ethernet • 1972, Bob Metcalfe, ALOHA became Ethernet • Shared medium (CSMA/CD) • Promiscuous mode instructs card to listen to every frame • Only works with stations in the same collision domain • Bridges, switches, routers, VLANS break sniffing Technique Layer Details: Packet Sniffing • Packet Demultiplexing • Breaking apart an Ethernet frame and passing it the protocol chain • Protocol Decoding • Dissection of the packet at a given OSI layer Technique Layer Details: Packet Sniffing Processing Demultiplexing of an Ethernet Frame 0x0800 Ethernet header Payload (28 bytes) ETHERTYPE_IP hl_v Ethernet II header 0x01 IPv4 header 20 byte header Payload (8 bytes) IPPROTO_ICMP Ethernet II header IPv4 header 0x08 ICMP header Echo request Sample Packet Sniffing Code Snippet packet = (u_char *)pcap_next(vp->p, &vp->h); /* * Figure out which layer 2 protocol the frame belongs to and call * the corresponding decoding module. The protocol field of an * Ethernet II header is the 13th + 14th byte. This is an endian * independent way of extracting a big endian short from memory. We * extract the first byte and make it the big byte and then extract * the next byte and make it the small byte. */ switch (vp->packet[12] << 0x08 | vp->packet[13]) { case 0x0800: /* IPv4 */ decode_ip(&vp->packet[14], vp->flags); break; case 0x0806: /* ARP */ decode_arp(&vp->packet[14], vp->flags); break; default: /* We're not bothering with 802.3 or anything else */ decode_unknown(&vp->packet[14], vp->flags); break; } Technique Layer Details: Port Scanning • Active Reconnaissance Technique • Used to determine TCP and UDP port status • Open, Closed, and optionally what application is listening • Many Considerations • Protocol • Detection and Filtering • Time and Bandwidth Technique Layer Details: Port Scanning Mechanics • Full-open • Ident • FTP bounce • Half-open • Side effect RST • Parallel • UDP • Stealth • FIN • XMAS (URG|ACK|PSH) • NULL • Fragmented IP Technique Layer Details: Port Scanning Full-open TCP port scan FIN SYN ACK SYN|ACK or RST FIN ACK scanning host target Connection establishment scanning host ACK target Connection teardown Sample Port Scanning Code Snippet int fd, n, c; struct sockaddr_in addr; u_short port_list[] = {22, 23, 25, 80, 6000, 0}; addr.sin_family = AF_INET; addr.sin_addr.s_addr = 0x200a8c0; /* 192.168.0.2 in network byte order */ for (n = 0; port_list[n] != 0; n++) { addr.sin_port = htons(port_list[n]); fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (fd == -1) { /* error */ } c = connect(fd, (struct sockaddr *)&addr, sizeof (addr)); if (c == -1) { /* error */ } else if (c == 0) { printf("port %d open\n", port_list[n]); } else { printf("port %d closed\n", port_list[n]); } close(fd); } Technique Layer Details: IP Expiry • Active Reconnaissance Technique • Used to map network devices en route to a target host • Van Jacobson, 1988, Traceroute • Originally used to trace IP packets to a particular destination host • Was extended into Firewalking Technique Layer Details: IP Expiry Transports • Protocol specific terminal packet semantics • UDP • Open port: undefined (no response) • Closed port: ICMP port unreachable • ICMP • ICMP echo reply • TCP SYN • Open port: SYN|ACK • Closed port: RST Technique Layer Details: IP Expiry TTL = n IP TTL = n, where: UDP: empty packet to unused port ICMP: ECHO request TCP: SYN to arbitrary port ICMP TTL expired in transit packet with x.x.x.x as expiry router x.x.x.x terminal response packet UDP: port unreachable ICMP: ECHO reply TCP: RST or SYN|ACK IP TTL = 5 IP TTL = 4 IP TTL = 3 IP TTL = 2 scanning host destination host IP TTL = 1 10.0.0.20 10.0.0.1 10.0.1.1 10.0.0.1 10.0.1.1 10.0.2.1 10.0.3.1 terminal response 10.0.2.1 10.0.3.1 10.0.3.20 c = libnet_write(l); if (c == -1) { /* error */ } fprintf(stderr, "Hop %02d: ", ttl); pcap_t *p; for (done = icmp = ip = 0, ttl = 1; ttl </* 31read && !done; ttl++) loop */ libnet_t *l; { for (start = time(NULL); (time(NULL) - start) < 2; ) time_t start; icmp = libnet_build_icmpv4_echo( { u_char *packet; ICMP_ECHO, /* type */ packet = (u_char *)pcap_next(p, &ph); int c, ttl, done; 0, code */ if /* (packet == NULL) char *device = "fxp0"; 0, { /* checksum */ struct pcap_pkthdr ph; 242, /* id */ continue; libnet_ptag_t icmp, ip; ttl, } /* sequence */ u_long src_ip = 0x1400000a; /* 10.0.0.20 in network byte order */ NULL, payload */ /* /* assume ethernet here for simplicity */ u_long dst_ip = 0x1403000a; /* 10.0.3.20 in network byte order */ 0, /*=payloadsiz*/ ip_h (struct libnet_ipv4_hdr *)(packet + 14); struct libnet_icmpv4_hdr *icmp_h; l, context */ if /* (ip_h->ip_p == IPPROTO_ICMP) struct libnet_ipv4_hdr *ip_h, *oip_h; icmp); { /* libnet id */ char errbuf[LIBNET_ERRBUF_SIZE]; if (icmp == -1) icmp_h = (struct libnet_icmpv4_hdr *)(packet + 34); { /* expired in transit */ l = libnet_init(LIBNET_RAW4, NULL, errbuf); /* error */ if (icmp_h->icmp_type == ICMP_TIMXCEED && if (l == NULL) } icmp_h->icmp_code == ICMP_TIMXCEED_INTRANS) { ip = libnet_build_ipv4( { /* error */ LIBNET_IPV4_H + LIBNET_ICMPV4_ECHO_H, /* length oip_h*/ = (struct libnet_ipv4_hdr *)(packet + 42); } 0, /* TOS if*/ (oip_h->ip_id == htons(242)) p = pcap_open_live(device, 60, 0, 500, errbuf); 242, /* IP{ID */ if (p == NULL) 0, /* IP Frag */ fprintf(stderr, "%s\n", { ttl, /* TTL */ libnet_addr2name4(ip_h->ip_src.s_addr, 0)); /* error */ IPPROTO_ICMP, /* protocol */ break; } 0, /* checksum */ } src_ip, /* } src ip */ dst_ip, /* ip */ response */ /*dst terminal NULL, /* */ ifpayload (icmp_h->icmp_type == ICMP_ECHOREPLY) 0, /* { payloadsiz*/ l, /* context */ if (icmp_h->icmp_id == 242 && icmp_h->icmp_seq == ttl) ip); /* libnet id */ { if (ip == -1) fprintf(stderr, "%s\n", { libnet_addr2name4(ip_h->ip_src.s_addr, 0)); /* error */ done = 1; } break; } } } } Sample IP Expiry Code Snippet Technique Layer Details: Firewalking • Active Reconnaissance Technique • Based off of IP expiry • Used to determine ACL filtering rules on a packet forwarding device • Schiffman, Goldsmith, 1998 (Daveg) Technique Layer Details: Firewalking • Send out a TCP or UDP packet with an IP TTL one greater of the target gateway • Packet passed by gateway ACL: ICMP TTL expired in transit • Packet denied by gateway: No response • Requires two hosts, target and metric • Target is the target gateway to be scanned • Metric is a host or gateway downstream from the target • Doesn’t have to be reachable Technique Layer Details: Firewalking Firewalking host breakdown scanning host 10.0.0.20 target 10.0.0.1 10.0.1.1 10.0.2.1 metric 10.0.3.1 10.0.3.20 Technique Layer Details: Firewalking (Phase One: Hopcount Ramping) Firewalking Phase one Ramping hopcounts via IP expiry. TTL = 3 TTL = 2 scanning host target metric TTL = 1 10.0.0.20 10.0.0.1 10.0.1.1 10.0.2.1 10.0.3.1 10.0.0.1 10.0.1.1 10.0.2.1 1. Target gateway is reached with a TTL of three. 2. Scan is bound here with a TTL of four. 10.0.3.20 Technique Layer Details: Firewalking (Phase Two: Scanning, Packet is not Filtered) TTL = 4, TCP port = 22 Firewalking Phase two Firewalking scan of target, packet passes ACL scanning host target metric 1. Packet is sent to the metric. 10.0.0.20 10.0.0.1 10.0.1.1 10.0.2.1 10.0.3.1 4. Logged as open. 2. Packet is not filtered, passes through. ICMP TTL expired in transit 3. Packet expires. 10.0.3.20 Technique Layer Details: Firewalking (Phase Two: Scanning, Packet is Filtered) TTL = 4, TCP port = 23 Firewalking Phase two Firewalking scan of target, packet violates ACL scanning host target metric 1. Packet is sent to the metric. 10.0.0.20 10.0.0.1 10.0.1.1 10.0.2.1 10.0.3.1 4. Timer expires, port is filtered on target. 2. Packet is filtered. 3. No response. 10.0.3.20 Firewalk Packet Loss • Packets can be dropped for a variety of reasons • IP is an unreliable network • However, what if there is a prohibitive filter on a gateway prior to the target? • We would get false negatives reporting our packet is being filtered on the target when in fact it is being filtered by another host… Technique Layer Details: Firewalking (Phase Two: Early Filtering of Packets) IP TTL = 4, TCP port = 139 Firewalking Phase two Early filtering of packets. scanning host target metric 1. Packet is sent to the metric. 10.0.0.20 10.0.0.1 10.0.1.1 3. Scanning host cannot detect the error and assumes packet was filtered at 10.0.2.1 resulting in a potential false negative. 2. Packet is filtered here and dropped and never makes it to the target. 10.0.2.1 10.0.3.1 10.0.3.20 Firewalk Early Packet Filtering Solution • We have two solutions: • Performing a “creeping walk” on each intermediate hop en route to the target. This will determine which gateway has the prohibitive filter • Physically relocate the scanning host to another part of the network so it no longer has to pass through the prohibitive filter in question • This may not always be an option Firewalk Adjacent Target and Metric • Target and metric and topologically adjacent • Metric is exactly one hop downstream from the target • If packet violates ACL, nothing happens out of the ordinary • Scan times out and ACL is noted • If packet is passed by the target, it is processed as per RFC 1122 • Results vary, but packet is generally processed as per the protocol specific terminal packet semantics as with IP expiry • Using this, additional scanning can be performed Technique Layer Details: Firewalking (Phase Two: Scanning, Adjacent Target and Metric) IP TTL = 4, TCP port = 443 Firewalking Phase two Target and metric adjacent. scanning host target metric 1. Packet is sent to the metric. 10.0.0.20 10.0.0.1 10.0.1.1 10.0.2.1 2. Packet passes ACL. TCP SYN|ACK 10.0.2.20 3. Packet would expire on metric; but is processed and a terminal response sent to the scanning host. Modeling Existing Tools Traceroute Modeled Traceroute denotes layer dependency denotes class binding control logic interface reporting correlation Control active reconnaissance re Takes p IP expiry Technique Component libpcap ce d e n ce passive reconnaissance packet sniffing libnet The Firewalk Tool Modeled Firewalk denotes layer dependency denotes class binding passive reconnaissance active reconnaissance control logic house keeping reporting analysis Control Technique Component Packet sniffing Port scanning libpcap IP expiry libnet Firewalking libdnet Inside a Network Security Tool: Firewalk Internals startup Firewalk Overall Flow usage(argv[0]); fw_shutdown(&fp); #if /* (HAVE_CONFIG_H) shouldbreak; probably record proper exit status */ break;we"../include/config.h" #include return (EXIT_SUCCESS); case 'i': default: #endif } /* interface */ usage(argv[0]); #include "../include/firewalk.h" fp->device = optarg; }"../version.h" #include void} break; int usage(u_char case *argv0) 'n': c = argc optind; int firewalk(struct firepack { /* do not**fp) use names */ if (c != 2) main(int { argc, char *argv[]) fprintf(stderr, fp->flags "Usage&= : %s ~FW_RESOLVE; [options] target_gateway metric\n" { { int done, i,[-d j; %d - %d] destination port to use (ramping phase)\n" "\t\t break; /* int c; u_short bport, cport, eport; "\t\t case [-h] 'p': program help\n" * firepack We should only have two arguments at this point, the target struct *fp; "\t\t /* [-i select device] firewalk interface\n" protocol */ * gateway and the metric. char /* inform *port_list the user =do NULL; what's */ "\t\t fp->protocol [-n] not resolve =what fw_prot_select(optarg); IP addresses into hostnames\n" */ char"\t\t printf("%s-based errbuf[FW_ERRBUF_SIZE]; scan.\n", break; [-p TCP | UDP] firewalk protocol\n" usage(argv[0]); (*fp)->protocol ? "TCP" : "UDP"); "\t\t case[-r] 'r':strict == RFCIPPROTO_TCP adherence\n" } printf("Firewalk printf("Ramping phase 5.0 [gateway source port: ACL scanner]\n"); %d, destination port: %d\n", "\t\t /* [-S Strict x network - y,RFC z] components adherence port range*/ to scan\n" /* initialize the */ (*fp)->sport, (*fp)->dport); "\t\t fp->flags [-s %d %d] |= FW_STRICT_RFC; source port\n" if argv[optind], argv[optind + 1],== port_list) == /* (fw_init_net(&fp, if ((*fp)->flags (*fp)->protocol IPPROTO_TCP) "\t\t break; [-T 1&-FW_STRICT_RFC 1000] packet && read timeout in ms\n" 1) {* Initialize the main control context. We keep all of our "\t\t case[-t 'S': 1 - %d] IP time to live\n" {* program printf("Using state here strict and RFC this adherence.\n"); is just about every "\t\t /* [-v] scan program these version\n" ports */ used by fprintf(stderr, "fw_init_network(): %s\n", fp->errbuf); }* function in the program. "\t\tdone; port_list [-x 1 - %d] = optarg; expire vector\n" printf("Hotfoot */ goto through %s usingFW_PORT_MAX, %s as a metric.\n", "\n", break; argv0, FW_PORT_MIN, FW_PORT_MIN, } if (fw_init_context(&fp, libnet_addr2name4(((*fp)->gateway), errbuf) == -1) FW_PORT_MAX, case 's': printf("Firewalk state initialization completed successfully.\n"); { ((*fp)->flags) & FW_RESOLVE), /* source FW_IP_HOP_MAX, port */ /* execute scan: phase one,FW_XV_MAX); and hopefully phaseerrbuf); two */ fprintf(stderr, libnet_addr2name4(((*fp)->metric), "fw_init_control(): %s\n", exit(EXIT_SUCCESS); fp->sport = fw_str2int(optarg, "source port", switch (firewalk(&fp)) goto((*fp)->flags) done; & FW_RESOLVE)); } FW_PORT_MIN, FW_PORT_MAX); { } /* break; case -1: * */ PHASE ONE: Firewalk hopcount ramping /* EOF case 'T': case FW_SERIOUS_ERROR: /* * process A standard commandline arguments IP */expiry scan is initiated towards /* Traceroute-style time to wait packets from other end */ /* grievous error offor some sortto */ while * the ((c metric, = getopt(argc, with the argv, intent "d:fhi:no:p:rS:s:T:t:vx:")) being find how many"read hops!= away EOF) the fp->pcap_timeout = fw_str2int(optarg, timer", fprintf(stderr, "firewalk(): %s\n", fp->errbuf); {* target gateway is from the scanning host. We'll increment the FW_PCAP_TIMEOUT_MIN, FW_PCAP_TIMEOUT_MAX); break; * hopcounter switch (c) and update packet template each pass through theloop. break; case FW_ABORT_SCAN: */ { case 't': /* hop count exceeded or metric en route */ printf("Ramping case 'd': Phase:\n"); /* set initial IP TTL */ fprintf(stderr, "Scan %s.\n",ramping fp->errbuf); for (done = 0, /* i destination = 0; port &&aborted: ito < FW_IP_HOP_MAX; use during phase */ fp->ttl = !done fw_str2int(optarg, "initial i++) TTL", break; { fp->dport = fw_str2int(optarg, "ramping destination FW_IP_HOP_MIN, FW_IP_HOP_MAX); FW_USER_INTERRUPT: port", case /* send a series of probes (currently only one) */ break; fprintf(stderr, "Scan aborted by user.\n"); for (j = 0; j < 1; FW_PORT_MIN, j++) FW_PORT_MAX); case 'v': break; { break; /* version */ default: caseprintf(FW_BANNER fprintf(stderr, 'f': "%2d "version (TTL %2d): ", i + 1, (*fp)->ttl); : %s\n", VERSION); printf("\nScan completed successfully.\n"); if (fw_packet_inject(fp) /* stack fingerprint of == each -1) host */ goto done; break; { |= FW_FINGERPRINT; casefp->flags 'x': } break; /* /* expire vector */ done: casefp->xv * 'h': Perhaps this write error"expire was transient. = fw_str2int(optarg, vector", We'll hope fw_report_stats(&fp); /* * program for the help best. */ Inform the user and continue. FW_XV_MIN, FW_XV_MAX); Initialization No Report to user Success? Yes Ramping phase No Report to user Success? Yes Scanning phase Shutdown Report to user startup Firewalk Initialization int /* setup /* the metric */ /*/* get the datalink size */ fw_init_net(struct if * (((*fp)->metric Set pcap filter firepack = libnet_name2addr4((*fp)->l, and **fp, determine char *gw, outgoing char packet *m, char m, size. 1)) *port_list) == The -1) filter *switch Build(pcap_datalink((*fp)->p)) a probe packet template. We'll use this packet template { { * will be determined by the scanning protocol: int *{ over and over for each write to the network, modifying certain #if HAVE_BPF *snprintf((*fp)->errbuf, UDP scan: FW_ERRBUF_SIZE, fw_init_context(struct * fields case (IP DLT_SLIP: TTL,firepack UDP/TCP ports **fp, and charof *errbuf) course checksums as we go). int*one; icmp[0] "libnet_name2addr4(): == 11 or icmp[0] == 3 %sor (metric: udp %s)", { */ (*fp)->packet_offset = 0x10; #endif * TCP scan: libnet_geterror((*fp)->l), m); *fp(fw_packet_build_probe(fp) if = (struct break; firepack *)malloc(sizeof(struct == -1) firepack)); char *return errbuf[PCAP_ERRBUF_SIZE]; icmp[0] (-1); == 11 or icmp[0] == 3 or tcp[14] == 0x12 or tcp[14] \ if (*fp { case == DLT_RAW: NULL) } * == 0x4 or tcp[14] == 0x14 { /* error (*fp)->packet_offset msg set in fw_packet_build_probe() = 0x00; */ /* */ get a libnet context */ snprintf(errbuf, return break; (-1); FW_ERRBUF_SIZE, "malloc(): %s", strerror(errno)); (*fp)->l /* switch sanity((*fp)->protocol) =check libnet_init(LIBNET_LINK, */ (*fp)->device, errbuf); } return case DLT_PPP: (-1); if{((*fp)->gateway ((*fp)->l == NULL) == (*fp)->metric) } return (1); (*fp)->packet_offset = 0x04; { case IPPROTO_UDP: memset(*fp, break; 0, sizeof(struct firepack)); snprintf((*fp)->errbuf, if (fw_set_pcap_filter(FW_BPF_FILTER_UDP, FW_ERRBUF_SIZE, "libnet_init(): fp) == -1) %s", case DLT_EN10MB: { "target errbuf);gateway and metric cannot be the same"); /* setdefault: defaults here */ return (-1); /* err msg set in fw_set_pcap_filter() */ (*fp)->ttl(*fp)->packet_offset = 1; /* = 0x0e; initial probe IP TTL */ } return (-1); (*fp)->sport break; = 53; /* source port (TCP and UDP) */ } (*fp)->dport } = 33434; /* ala traceroute */ /* get our/* device port IP list + if UDPstuff the */ user situated didn't*/ specify one*/ (*fp)->protocol = IPPROTO_UDP; if (libnet_plist_chain_new((*fp)->l, ((*fp)->device (*fp)->packet_size == NULL) = LIBNET_IPV4_H &(*fp)->plist, + LIBNET_UDP_H; (*fp)->id = getpid(); { port_list break; == NULL ? strdup(FW_DEFAULT_PORT_LIST) : (*fp)->pcap_timeout = FW_REPLY_TIMEOUT; (*fp)->device port_list) case IPPROTO_TCP: == -1) = libnet_getdevice((*fp)->l); (*fp)->xv = 1; } { if (fw_set_pcap_filter(FW_BPF_FILTER_TCP, fp) == -1) (*fp)->flags |= FW_RESOLVE; snprintf((*fp)->errbuf, { FW_ERRBUF_SIZE, /* get the "libnet_plist_chain_new(): source /* err address msg set of our in fw_set_pcap_filter() outgoing %s\n", interface libnet_geterror((*fp)->l)); */ */ /* setup our signal handler to handle a ctrl-c */ (*fp)->sin.sin_addr.s_addr return (-1); return (-1); = libnet_get_ipaddr4((*fp)->l); if (catch_sig(SIGINT, catch_sigint) == -1) } } { /* get setup a pcap the /* target IP context + TCP gateway */ */ snprintf(errbuf, FW_ERRBUF_SIZE, "catch_sig(): %s", if (((*fp)->gateway (*fp)->p =(*fp)->packet_size pcap_open_live((*fp)->device, = libnet_name2addr4((*fp)->l, = LIBNET_IPV4_H FW_SNAPLEN, + LIBNET_TCP_H; gw,0, 1)) 0,== errbuf); -1) strerror(errno)); { (((*fp)->p) == NULL) if return (-1); { snprintf((*fp)->errbuf, /* randomize the TCP FW_ERRBUF_SIZE, sequence number */ } snprintf((*fp)->errbuf, libnet_seed_prand((*fp)->l); "libnet_name2addr4(): FW_ERRBUF_SIZE, %s (target"pcap_open_live(): gateway: %s)", %s", (*fp)->seq libnet_geterror((*fp)->l), errbuf); = libnet_get_prand(LIBNET_PRu32); gw); return (1); returnbreak; (-1); } } default: sprintf((*fp)->errbuf, "fw_init_network(): unsupported protocol"); return (-1); Shutdown } fw_init_context() No Allocate and groom memory Set initial defaults Set signal handler Success? Yes getopt() No Sanity check some user parameters Success? No Yes fw_init_net() No Success? Yes Ramping Phase Initialize libnet Initialize libpcap Verify and setup network addresses Setup port list Set packet filter Build packet template Firewalk Packet Construction int a = arp_open(); fw_packet_build_probe(struct fw_packet_build_tcp(struct firepack firepack **fp) **fp) if (a == NULL) { /* /*{build our IPv4 header */ arp_t /* *build Now *a;we a TCP need header to get */the MAC address of our first hop gateway. (*fp)->ip snprintf((*fp)->errbuf, = libnet_build_ipv4( FW_ERRBUF_SIZE, "arp_open()"); route_t (*fp)->tcp * Dnet *r; to = the libnet_build_tcp( rescue! We start by doing a route table lookup return (*fp)->packet_size, (-1); /* packetlength */ struct * toarp_entry determine (*fp)->sport, arp; the IP address we use to get /* to source the TCP port */ } 0, /* IP tos */ struct * destination route_entry (*fp)->dport, host route; (the metric). /* dest TCP port */ /* get the (*fp)->id, MAC of the first hop gateway */ /* IP id */ */ (*fp)->seq, /* sequence number */ arp.arp_pa 0,= route.route_gw; /* IP frag bits */ /* r = first route_open(); 0L, build our transport layer header *//* ACK number */ if (arp_get(a, (*fp)->ttl, &arp) < 0) /* IP time to live */ switch if (r == ((*fp)->protocol) TH_SYN, NULL) /* control flags */ { (*fp)->protocol, /* transport protocol */ {{ 1024, /* window size */ snprintf((*fp)->errbuf, 0, FW_ERRBUF_SIZE, "route_get()"); /* checksum */ case snprintf((*fp)->errbuf, 0, IPPROTO_UDP: FW_ERRBUF_SIZE,/* "route_open()"); checksum */ arp_close(a); (*fp)->sin.sin_addr.s_addr, /* IP source */ route_close(r); if (fw_packet_build_udp(fp) == -1) /* urgent */ 0, return (*fp)->metric, (-1); /* IP destination */ return { (*fp)->packet_size (-1); - LIBNET_IPV4_H, /* TCP size */ } NULL, /* IP payload */ } NULL, /* error msg set in fw_packet_build_udp() /* IP payload */ */ arp_close(a); 0, /* IP payload size */ 0, return (-1); /* IP payload size */ (*fp)->l, /* libnet context */ /* convert } (*fp)->l, the metric address to dnet's native /* libnet addr_tcontext format */ /* build our 0); ethernet header */ /* No saved ptag */ if (addr_aton(libnet_addr2name4((*fp)->metric, break; 0); /* No 0), saved ptag */ if (libnet_autobuild_ethernet( case IPPROTO_TCP: &route.route_dst) < 0) if ((*fp)->ip (u_char== *)&arp.arp_ha.addr_eth, -1) if { ((*fp)->tcp if (fw_packet_build_tcp(fp) == -1) == -1) { ETHERTYPE_IP, { snprintf((*fp)->errbuf, { FW_ERRBUF_SIZE, "addr_aton()"); snprintf((*fp)->errbuf, (*fp)->l) == -1) FW_ERRBUF_SIZE, "libnet_build_ipv4() %s", snprintf((*fp)->errbuf, route_close(r); /* error msg setFW_ERRBUF_SIZE, in fw_packet_build_tcp() "libnet_build_tcp() */ %s", { libnet_geterror((*fp)->l)); return libnet_geterror((*fp)->l)); return (-1); (-1); snprintf((*fp)->errbuf, return (-1); FW_ERRBUF_SIZE, } return } (-1); } "libnet_autobuild_ethernet() %s", }/* get the break; route entry telling us how to reach the metric */ libnet_geterror((*fp)->l)); return if (route_get(r, default: (1); &route) < 0) arp_close(a); } { sprintf((*fp)->errbuf, return (-1); snprintf((*fp)->errbuf, "fw_packet_build_probe(): FW_ERRBUF_SIZE, unknown "route_get()"); protocol"); } route_close(r); return (-1); } return (-1); return (1); } } route_close(r); startup Firewalk Ramping Phase /* if (!done) switch (fw_packet_capture(fp)) * PHASE { ONE: { Firewalk hopcount ramping * A standard if Traceroute-style (fw_packet_update_probe(fp, case FW_PACKET_IS_UNREACH_EN_ROUTE: IP expiry scan 0) == is-1) initiated towards * the metric, { with case the FW_PACKET_IS_TTL_EX_EN_ROUTE: intent being to find how many hops away the * target gateway /* is error iffrom ((*fp)->flags msg the set scanning in fw_packet_update_probe & FW_BOUND) host. We'll increment */ the * hopcounter and return update { (-1); packet template each pass through the loop. */ } printf("Binding host reached.\n"); printf("Ramping } Phase:\n"); done = 1; for } (done = 0, i = 0; } !done && i < FW_IP_HOP_MAX; i++) { if (done && !((*fp)->flags break; & FW_BOUND)) /* send a series { case of FW_PACKET_IS_TERMINAL_TTL_EX: probes (currently only one) */ for (j /* = 0; j case < 1; FW_PACKET_IS_TERMINAL_UNREACH: j++) { * If we're case "done" FW_PACKET_IS_TERMINAL_SYNACK: but not "bound" then we hit the metric fprintf(stderr, * before case weFW_PACKET_IS_TERMINAL_RST: hit "%2d the(TTL target %2d): gateway. ", i + This 1, (*fp)->ttl); means the targetYes if * (fw_packet_inject(fp) gateway is /* not any en terminal route == to response -1)the metric. will end Game's phaseover one kids. */ No {*/ done = 1; Success? sprintf((*fp)->errbuf, /* break; * "metric Perhaps case -1:responded this writebefore error target; was transient. must notWe'll be enhope route"); return * (FW_ABORT_SCAN); for the case FW_SERIOUS_ERROR: best. Inform the user and continue. } */ /* err msg set in fw_packet_capture() */ Update ramping if (!done) fprintf(stderr, return (FW_SERIOUS_ERROR); "fw_packet_inject():probe %s\n", fw_packet_update_probe() { case(*fp)->errbuf); FW_USER_INTERRUPT: /* if continue; we fall /*through user hit down ctrl-c here, */we've exceeded our hopcount */ } sprintf((*fp)->errbuf, return (FW_USER_INTERRUPT); "hopcount exceeded"); return } (FW_ABORT_SCAN); } } fw_packet_inject() No Success? Yes fw_packet_capture() No Success? Yes Yes Metric reached? No Yes Hopcount exceeded? No No Bound / done? Yes Shutdown Write probe to network Scanning Phase Verify probe startup Firewalk Scanning Phase /* send a series of probes (currently only one) */ /* for (j = 0; j < 1; j++) * PHASE TWO: { Firewalk scanning * A series of probes fprintf(stderr, are sent from "portto %3d: the", metric cport); with the bound IP * TTL. If a given (*fp)->stats.ports_total++; probe is accepted through the target gateway's * ACL, we willif receive (fw_packet_inject(fp) an ICMP TTL expired == -1) in transit from the * binding host{If we receive no response after the timeout expires, * it is assumed the /*probe violated the ACL on the target and was * dropped. * Perhaps this write error was transient. We'll */ * hope for the best. Inform the user and continue. (*fp)->ttl += (*fp)->xv; */ printf("Scan bound at fprintf(stderr, %d hops.\n", (*fp)->ttl); "fw_packet_inject(): %s\n", printf("Scanning Phase: \n"); (*fp)->errbuf); for (done = 0, i = 0; continue; !done; i++) { } if (!libnet_plist_chain_next_pair((*fp)->plist, /* we don't care what the return value &bport, is this &eport)) time */ { switch(fw_packet_capture(fp)) /* we've{exhausted our portlist and we're done */ done = 1; case FW_USER_INTERRUPT: continue; return (FW_USER_INTERRUPT); } case -1: while (!(bport >case eport) FW_SERIOUS_ERROR: && bport != 0) { /* err msg set in fw_packet_capture() */ cport = bport++;return (FW_SERIOUS_ERROR); if (fw_packet_update_probe(fp, default: cport) == -1) { /* empty */ /* error } msg set in fw_packet_update_probe */ return (-1); } } } return (1); } libnet_plist_chain_next_pair() Yes Exhausted port list? No fw_packet_update_probe() No Update scanning probe Success? Yes Write probe to network fw_packet_inject() No Success Yes fw_packet_capture() Success No Shutdown Yes Verify probe startup Firewalk Capture switchfor (!(((*fp)->flags) (timed_out = 0;&!timed_out FW_BOUND) && ? fw_packet_verify_ramp(fp) loop; ) : { casefw_packet_verify_scan(fp)) FW_PORT_IS_OPEN_RST: { c = select(pcap_fd /* SCANNING: A+response 1, &read_set, from a0, closed 0, &timeout); TCP port */ switch casefw_report(FW_PORT_IS_OPEN_RST, FW_PACKET_IS_TTL_EX_EN_ROUTE: (c) fp); { /* RAMPING: TTL expired en route to gateway (standard) */ (*fp)->stats.packets_caught_interesting++; case fw_report(FW_PACKET_IS_TTL_EX_EN_ROUTE, return -1:(FW_PORT_IS_OPEN_RST); fp); case(*fp)->stats.packets_caught_interesting++; FW_PORT_IS_OPEN_UNREACH: snprintf((*fp)->errbuf, FW_ERRBUF_SIZE, Shutdown return /* SCANNING: (FW_PACKET_IS_TTL_EX_EN_ROUTE); "select() A port unreachable %s", strerror(errno)); response */ casefw_report(FW_PORT_IS_OPEN_UNREACH, FW_PACKET_IS_UNREACH_EN_ROUTE: return (-1); fp); case /* RAMPING: (*fp)->stats.packets_caught_interesting++; 0: Unreachable en route to gateway (uncommon) */ fw_report(FW_PACKET_IS_UNREACH_EN_ROUTE, return timed_out (FW_PORT_IS_OPEN_UNREACH); = 1; fp); case(*fp)->stats.packets_caught_interesting++; FW_PORT_IS_OPEN_TTL_EX: continue; default: return /* SCANNING: (FW_PACKET_IS_TTL_EX_EN_ROUTE); A TTL expired */ casefw_report(FW_PORT_IS_OPEN_TTL_EX, FW_PACKET_IS_TERMINAL_TTL_EX: if (FD_ISSET(pcap_fd, &read_set) fp); == 0) /* RAMPING: (*fp)->stats.packets_caught_interesting++; { TTL expired at destination (rare) */ fw_report(FW_PACKET_IS_TERMINAL_TTL_EX, return timed_out = 1; (FW_PORT_IS_OPEN_TTL_EX); fp); case(*fp)->stats.packets_caught_interesting++; FW_PACKET_IS_BORING: continue; default: return } (FW_PACKET_IS_TERMINAL_TTL_EX); casecontinue; FW_PACKET_IS_TERMINAL_UNREACH: /* fall through to read the packet */ } } /* RAMPING: Unreachable at destination (uncommon) */ } (*fp)->packet fw_report(FW_PACKET_IS_TERMINAL_UNREACH, = (u_char *)pcap_next((*fp)->p, fp); &pc_hdr); if ((*fp)->packet (*fp)->stats.packets_caught_interesting++; == NULL) { return (FW_PACKET_IS_TERMINAL_UNREACH); case /*FW_PACKET_IS_TERMINAL_SYNACK: no NULL packets please */ continue; fw_report(FW_PACKET_IS_TERMINAL_SYNACK, fp); } (*fp)->stats.packets_caught_interesting++; (*fp)->stats.packets_caught++; return (FW_PACKET_IS_TERMINAL_SYNACK); case FW_PACKET_IS_TERMINAL_RST: fw_report(FW_PACKET_IS_TERMINAL_RST, fp); (*fp)->stats.packets_caught_interesting++; return (FW_PACKET_IS_TERMINAL_RST); case FW_PORT_IS_OPEN_SYNACK: /* SCANNING: A response from an open TCP port */ fw_report(FW_PORT_IS_OPEN_SYNACK, fp); (*fp)->stats.packets_caught_interesting++; return (FW_PORT_IS_OPEN_SYNACK); select() Error Error? Timeout? Ready? Ready pcap_next() No Success? Yes fw_packet_verify() Yes Boring packet? No Return response Timeout FW_NO_REPLY startup Firewalk Packet Verification (ramping phase) Yes Packet we sent? No ICMP packet? No Yes Time exceed? Unreach? Yes No Yes No No TCP packet? In Transit? Scanning TCP? Yes SYN or RST packet? Yes No Yes No Match our tuple? Yes Firewalk Response Packet? No Yes From metric? Yes FW_PACKET_IS_TERMINAL No From gateway? FW_PACKET_IS_BORING No Yes No Yes RFC compliant? Yes Scan is bound No FW_PACKET_IS_EN_ROUTE startup Yes Firewalk Packet Verification (Scanning Phase) Packet we sent? No ICMP packet? No Yes Time exceed? Unreach? Yes No Yes No No TCP packet? In Transit? Scanning TCP? Yes No SYN or RST packet? Yes No Yes Match our tuple? Yes Firewalk Response Packet? No FW_PACKET_IS_BORING Yes No No Yes RFC compliant? Yes FW_PORT_IS_OPEN No Conclusion • Modular Model of Network Security Tools • Components and Techniques • This was not an exhaustive list of Components or Techniques… • Examples of how to code Techniques using Components Questions and Comments? mike@infonexus.com http://www.packetfactory.net