SHOW:
|
|
- or go back to the newest paste.
1 | #!/usr/bin/env python2 | |
2 | ||
3 | import urllib2 | |
4 | import sys | |
5 | import subprocess | |
6 | import os | |
7 | TARGET = 'http://crypto-class.appspot.com/po?er=' | |
8 | #-------------------------------------------------------------- | |
9 | # padding oracle | |
10 | #-------------------------------------------------------------- | |
11 | class PaddingOracle(object): | |
12 | def query(self, q): | |
13 | target = TARGET + urllib2.quote(q) # Create query URL | |
14 | req = urllib2.Request(target) # Send HTTP request to server | |
15 | try: | |
16 | f = urllib2.urlopen(req) # Wait for response | |
17 | sys.exit(0) | |
18 | except urllib2.HTTPError, e: | |
19 | if e.code == 404: | |
20 | sys.exit(1) | |
21 | else: | |
22 | sys.exit(-1) | |
23 | ||
24 | def from_text_pair(code): | |
25 | assert(len(code)==2) | |
26 | return int('0x' + code, 16) | |
27 | ||
28 | def from_text(text): | |
29 | assert(len(text) % 2 == 0) | |
30 | result=[] | |
31 | for i in range(0,int(len(text)/2)): | |
32 | l=text[i*2] | |
33 | h=text[i*2+1] | |
34 | r=from_text_pair(l+h) | |
35 | result.append(r) | |
36 | return result | |
37 | ||
38 | def to_hex_byte(b): | |
39 | h = hex(b) | |
40 | if not (len(h) == 3 or len(h) == 4): | |
41 | print "to_hex_byte(%s) problem" % b | |
42 | sys.exit(0) | |
43 | def byte(b, i): | |
44 | return int('0x' + hex(b)[i], 16) | |
45 | if len(h) == 3: | |
46 | return '0' + h[-1] | |
47 | else: | |
48 | return h[-2] + h[-1] | |
49 | ||
50 | def to_hex(t): | |
51 | return ''.join(map(to_hex_byte, t)) | |
52 | ||
53 | def to_text(data): | |
54 | return ''.join(list(map(chr,data))) | |
55 | ||
56 | def norm(data): | |
57 | return to_text(from_text(data)) | |
58 | ||
59 | def guess(result, IV, C, last=False): | |
60 | l=len(result) | |
61 | pl=[] | |
62 | for g in xrange(0,256): | |
63 | iv=from_text(IV) | |
64 | for i in xrange(0,l): | |
65 | k=i+1 | |
66 | iv[-k] = iv[-k] ^ result[i] ^ (l+1) | |
67 | m=l+1 | |
68 | iv[-m] = iv[-m] ^ g ^ (l+1) | |
69 | pl.append(subprocess.Popen(["./padding_oracle.py", (to_hex(iv)+C), "oracle"], cwd=os.getcwd())) | |
70 | map(lambda p: p.wait(), pl) | |
71 | rl=map(lambda p: p.returncode, pl) | |
72 | for_return=[] | |
73 | for (g,r) in enumerate(rl): | |
74 | if r == 0: | |
75 | print "ACCEPTED=%s" % g | |
76 | elif r == 1: | |
77 | if (not last) or g != (l+1) or (len(result) and result[0] == (l+1)): | |
78 | print "PASSED=%s" % g | |
79 | for_return.append(g) | |
80 | assert(len(for_return)==1) | |
81 | return for_return[0] | |
82 | ||
83 | if __name__ == "__main__": | |
84 | result="" | |
85 | if len(sys.argv) == 1: | |
86 | print >>sys.stderr, "Specify cipher text as argument" | |
87 | sys.exit(-1) | |
88 | elif len(sys.argv) == 2: | |
89 | ORIG=sys.argv[1] | |
90 | if len(ORIG) % 32 != 0: | |
91 | print >>sys.stderr, "Invalid cipher text length" | |
92 | sys.exit(-1) | |
93 | elif len(sys.argv) == 3 and sys.argv[-1] == "oracle": | |
94 | po = PaddingOracle() | |
95 | po.query(sys.argv[1]) | |
96 | else: | |
97 | print >>sys.stderr, "Specify cipher text as argument" | |
98 | sys.exit(-1) | |
99 | block_count=len(ORIG)/32 | |
100 | if block_count < 2: | |
101 | print >>sys.stderr, "You have just IV, no cypher text given" | |
102 | sys.exit(-1) | |
103 | block_count-=1 | |
104 | for i in xrange(0,block_count): | |
105 | print "Decode block %s/%s" % (i+1, block_count) | |
106 | a=i*32 | |
107 | b=a+32 | |
108 | c=b+32 | |
109 | IV=ORIG[a:b] | |
110 | C=ORIG[b:c] | |
111 | block=[] | |
112 | while len(block) < 16: | |
113 | - | block.append(guess(block,IV,C,last=(i==block_count+1))) |
113 | + | block.append(guess(block,IV,C,last=(i+1==block_count))) |
114 | if i == 2: | |
115 | pad = block[0] | |
116 | block=block[pad:] | |
117 | text=to_text(reversed(block)) | |
118 | print "Block %s/%s is '%s'" % (i,block_count,text) | |
119 | result+= "".join(text) | |
120 | print "Result is '%s'" % result |