I am trying to create a padding oracle attack to decrypt a cipher that is encrypted with cbc and PKCS#7 padding.
My first step is just to try and decrypt the second block.
I have read a lot about it, and have started to code the first step of the attack, where I edit last byte in the first block and send it to the oracle. But there is a point of the attack/decryption method I'm a bit confused about regarding the xor of the bytes.
The part I don't understand completely is the math on how manipulating the last byte in the first block result in the last byte in the decrypted byte to turns out to be 0x01
, 0x02
etc.
I haven't figured out how the math for that works, for what I have researched it should just be to xor OriginalByte xor TestByte xor 1.
Should that be equal to 0x01
?
Here I have a string "TestBlockForStackBBBBBBBBBBBa31"
, it is 31 bytes. That means that it has to get padded with 1 to make it equal to 32 bytes so it fits inside 16 byte blocks.
The string byte is as following (without encryption):
54657374426C6F636B466F72537461636B4242424242424242424242613331
Then we decrypt the string with the key and IV below using cbc and PKCS#7.
byte[] Key = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9};
//we don't need key the key under the attach, only under encryption.
byte[] IV = new byte[]{2, 3, 2, 3, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2 };
We then get this result:
Ciphertext: ;fŒ˜ÆOgÄ:VûÎ{Ž+6iXK¿îMŠžÌš Cipher bytes: 3B668C98C64F67C43A56FBCE7B8E150E9D2B1F3669584BBFEE4D8A0E189ECC9A
Under the padding oracle attack I edit the last byte in the first block
(3B668C98C64F67C43A56FBCE7B8E15 0E <--).
I know that when I edit the last byte in the first block to 0D the decryption result will have a 0x01 at the end. The first block is then going to look like this:
3B668C98C64F67C43A56FBCE7B8E150D
And what I then send to the oracle in this case DecryptStringFromBytes (code can be found in RijndaelManaged.CreateDecryptor Method) is the following
first the edited chiper 3B668C98C64F67C43A56FBCE7B8E150D9D2B1F3669584BBFEE4D8A0E189ECC9A
, then the key that is only 0 (Key = new byte[16]), then the same iv as above.
It then returns that the padding is valid. I did go into the function BCryptDecrypt (used inside the decryption call) and set a breakpoint to confirm this, and it is indeed 0x01
.
The output bytes from the call BCryptDecrypt is then like this:
[0] 0x95 byte [1] 0x28 byte [2] 0xE5 byte [3] 0x18 byte [4] 0x90 byte [5] 0x8E byte [6] 0x31 byte [7] 0xFF byte [8] 0xF0 byte [9] 0x28 byte [10] 0x86 byte [11] 0x7B byte [12] 0x9D byte [13] 0x63 byte [14] 0x2F byte [15] 0x01 byte
The decrypted file result that returns from the decrypter to the user looks like this:
Text : ?????xi?G?w?T}!y?(???1??(?{?c/ Bytes : 3F3F3F3F3F78693F473F773F547D21793F283F183F3F313F3F283F7B3F632F (Thay have removed the 0x01 and the bytes is a bit different, maybe something with how I formatted it or it does something more before returning the bytes?)
So my questions are:
- How does the info I did send turn out to be
0x01
at the end? - What do I need to xor to the result to get the plaintext/byte?