ArcGIS  is a family of software providing geographic information system services. While testing a customer’s ArcGIS architecture we came across a SAML login flow. In this blogpost we show how we found and exploited an AES-CBC padding oracle in this flow.
The vulnerabilities were responsibly disclosed to ESRI and are now fixed in the Portal for ArcGIS Security 2021 Update 1 Patch. Compass Security also published an advisory which can be found here. The vulnerabilities are tracked under CVE-2021-29108.
The customer uses SAML, a well-known authorization standard, with Azure as the Identity Provider (IDP) to authenticate their users to the ArcGIS application. In the SAML context, ArcGIS is the service provider (SP).
Note that all the requests are sent from the user’s browser. The SAML response contains the assertion signed by the IDP. The assertion contains the user information, in this case the username and role.
My colleague discovered a XSW4 Signature wrapping  attack against ArcGIS. This attack basically tricks the service provider to validate the signature against a valid assertion block but then parses the user information from a different unsigned assertion block. This attack allows the attacker to impersonate any other user by inserting information into the unsigned assertion block.
After discussing with our customer, SAML encryption was turned on to temporarily prevent this attack. With SAML encryption the assertion block is encrypted, which should make XSW4 attacks impossible.
Another issue we discovered was that assertions could be reused. This becomes relevant later on but generally makes testing SAML quite convenient.
The first thing we did after encryption was turned on is check how the encrypted assertions looked.
Marked in purple is the base64 encoded encrypted assertion. Marked in green is the used encryption algorithm (AES256-CBC with a block size of 16 bytes). The used encryption algorithm does not specify any sort of message authentication. This means ArcGIS has no way to check if the ciphertext has been tampered with before decrypting. This allows us to mess with the ciphertext, which is exactly what we’re going to do.
As a first step we modified a byte in the last block of the ciphertext.
The original (1) and modified ciphertext (2). (I just lazily changed a character in the base64 decoding).
After sending the modified SAML response, ArcGIS responded with the following error message:
The error states: “Error validating encrypted Assertion Given final block not properly padded“. The error clearly indicates that an attempt was made to decrypt the ciphertext, but failed due to invalid padding. Is it possible we found a padding oracle?!? It would make sense since we modified the last block, which would completely change the decrypted value and in turn also the relevant padding values.
To confirm that this is not a generic error we modified a byte in the second-to-last ciphertext block, which should not influence the padding:
The error message:
The error states: “The element type AuthnStatement must be terminated by the matching end-tag“. It appears the decryption succeeded but then something failed when parsing the SAML XML. At this point all the indicators for a padding oracle are present and we wanted to efficiently confirm the vulnerability.
To confirm this vulnerability we decided to decrypt the last byte of the first plaintext block.
Quick reminder of how AES-CBC decryption works:
The plaintext is obtained by decrypting a ciphertext block and Xoring the result with the previous ciphertext block.
To be able to exploit a padding oracle we need to understand how the padding works. Checking the link: http://www.w3.org/2001/04/xmlenc#aes256-cbc in the SAML response and searching for padding we quickly find the padding scheme used.
Basically the padding scheme fills the final plaintext block with filler characters, except the last byte value of the final block, which becomes the number of bytes used for padding.
For example assume a block size of 16 bytes and a final plaintext block: 0xdeadbeef. The final block has length 4 so 12 bytes need to be added for padding. The padding would be 11 bytes of filler + 0x0c (12).
Final padded block: 0xdeadbeef??????????????????????0c.
Now we also have a better understanding of why we were able to trigger the padding error from before. Valid padding for blocks of size 16 bytes always need a final byte value between 1 and 16. (All possible padding sizes added to the final block)
For my confirmation I split the ciphertext into 16 byte blocks and then only send two blocks to my oracle: the first ciphertext block (which is the initialization vector) and the second ciphertext block (which holds the encrypted first plaintext block). We send 256 different SAML responses to ArcGIS. Each SAML response contains a different last byte value for the initialization vector. The following image illustrates the idea behind this:
Since the plaintext block is obtained by XOR’ing the previous ciphertext block with the intermediate block, the last byte of the previous block directly influences the value of the last byte of the plaintext. The padding will be valid if the value of the final byte is between 1 and 16. If the value is not in this range we will see the error message indicating incorrect padding.
Running this attack (marked in red is the value of the final byte value of the IV). All error messages about padding are filtered:
The error we receive for byte values starting at 192 is: “Structures must start and end within the same entity“. This sounds like an XML parsing error.
Overall 16 values are found which result in a non-padding related error message.
Interestingly one of these error messages for the byte value 218 is different. It states: “SAML response null“.
For the byte value 218 the final padding byte value is 16. This means that 16 bytes were added as padding. Since only two blocks are present and the first one is not part of the plaintext, 16 bytes of padding means the entire first plaintext block is padding and there is no plaintext. This explains the error message.
Now we are able to deduce the value of the last byte of the intermediate block. The value is 218 ^ 16 = 202.
With the intermediate block value we can use the original last byte value of the IV block to obtain the original plaintext byte. The value of the original last byte of the first plaintext block is 202 ^ 24 = 94.
Checking the ASCII table a byte value of 94 corresponds to the underscore character “_”. Looking at one of the old non-encrypted assertions in Burp, it can be seen that the 16th character of the assertions is always underscore. The ID value always starts with a underscore. There is no reason to assume that with encrypted assertions the format of the ID would change. We have thus succesfully confirmed a padding oracle
The first step for exploitation is to decrypt an assertion. Abusing the oracle to decrypt an assertion is slightly different than the usual padding oracle because of the used padding scheme. There is a nice blog post  and paper  which nicely explain how a padding oracle with XML encryption can be attacked.
We simply implemented the attack method described in the links above, wrapping it all in a SAML flow.
Running the exploit:
After some time the assertion is completely decrypted. But what now? Intuitively we could again apply an XSW4 attack to the decrypted assertion and then use the oracle to reencrypt. Fortunately even though SAML encryption is active, ArcGIS still accepts unencrypted assertions. So we can directly apply XSW4 to the decrypted assertion and impersonate any other user! This only works of course because assertions can be reused. (Note that we couldn’t just send one of the original SAML responses because the signing certificate had also been changed when SAML encryption was activated).
 https://enterprise.arcgis.com/, the official website.
 https://epi052.gitlab.io/notes-to-self/blog/2019-03-13-how-to-test-saml-a-methodology-part-two/#xml-signature-wrapping, for more info about XSW4 attacks
 https://blog.cryptographyengineering.com/2011/10/23/attack-of-week-xml-encryption/, blog post about attacking XML encryption
 https://www.nds.ruhr-uni-bochum.de/media/nds/veroeffentlichungen/2011/10/22/HowToBreakXMLenc.pdf, paper on breaking XML encryption with a oracle
Using AES-GCM instead of AES-CBC would have prevented the attack. That would have been basic security hygiene that should have been in place.
Indeed, GCM being authenticated, this leaves no room for padding oracle attacks. Thanks for your input.