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 |