Hiding XXE in Spreadsheets
- 3 minutes read - 622 wordsRecently I tried to poke holes in a service. I found myself laughing out loud. This was a vulnerability whereby modifying a SAML authentication while being rePOSTed via the browser allowed me to inject a malicious payload (see XML External Entity (XXE) Processing and XML External Entity (XXE) Prevention Cheat Sheet) that could be used to use up a service’s memory and CPU. Health checks and automatic service restarts would have healed the service but it still would have allowed an attacker to mount a Denial of Service attack without needing a lot of requests.
Finding the Issue
Subsequently, I identified a number of services that needed to be fixed, and while I was fixing services I used the following regular expression to find other possible weaknesses:
|
|
This lead me to find the following code snippet in a class called WorksheetParser
|
|
and WorksheetParser
was used to parse ODF spreadsheets (OpenOffice spreadsheets).
In this app, “worksheet"s were used so that organisations can use a simple spreadsheet to collect their information and upload it. The app parsed the information and played it back to the user.
Now, this got me thinking - as the ODF file format is just a ZIP file with XML content - and I had just found an
unsecured SAXParserFactory
, how difficult would it be to exploit that?
The Exploit
So I got the spreadsheet and opened it up in LibreOffice and I filled in some basic data including first name and last name and saved the file.
Then I unzipped it
|
|
then I just edited the content.xml file and added
|
|
then I looked for the last name that I entered (“Doe”) - and replaced it with &xxe;
Then it was just a matter of zipping it back up again as my new payload file
|
|
Then once I had uploaded the file and the app played back the last name - I was able to get the IAM role…
Limitations
The exploit was somewhat limited because the app validated the last name, and if there are unknown characters (like ‘{’ or ‘}') an error would be displayed. So I wasn’t able to extract the AWS keys by setting the payload to:
|
|
Also those credentials would have been somewhat limited as they were locked down.
However, with enough knowledge of the system and the ability to execute arbitrary GET requests, I believe quite a bit of damage could have been done.
The Fix
The offending class was changed to
|
|
as per the OWASP XXE Prevention Cheat Sheet.
Moral of the Story
- Malicious XXE payloads can hidden in files that do not have the XML extension
- Do not assume that XML processing is safe by default (particular when using older libraries)
- XML is evil
If you'd like to find more of my writing, why not follow me on Bluesky or Mastodon?