After registering shadow:shadowforge, I started to click around in the application while the traffic ran through BurpSuite. I quickly found an interesting functionality in the application. Using the function upload I could upload JSON, but also XML. This was clearly mentioned on the frontend.
Usually a website won't explicitly say that you can upload XML. We as hackers, should always consider to try and upload XML. It's not because the frontend says only JSON, the backend says the same thing.
I noticed an example JSON format ready to download, so users could upload their own cards based on that example. The example looked like this.
{"name":"Sample Deck","description":"A sample deck showing the import format for custom flashcards","category":"Example","cards":[{"front":"What is the capital of France?","back":"Paris - the city of lights and capital of France since 987 AD."},{"front":"What programming language is this app built with?","back":"JavaScript - using Node.js for backend and React for frontend."}]}
Pulling this code through ChatGPT with the question to make that in an XML and adding my own DTD to it, resulted in this payload.
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPEfoo[<!ELEMENT foo ANY ><!ENTITYxxe SYSTEM "file://flag.txt">]><deck><name>Ex Deck</name><cards><card><front>&xxe;</front><back>pass</back></cards></cards></deck>
So now, all I had to do, was upload this file and I would see the contents of the flag! 🥳 But that kinda blew up in my face 💥
Change of plans, the application was checking my XML object and it did not like the DTD.
Whenever a DTD attack failes, we can try an XIncludeattack. Instead of trying to hijack the rules, we try to sneak in an extra field that hopefully delivers our payload.
An XInclude payload is the exact same XML object, we only add an additional <xi: ... field to it.
This payload did not cause any issue and went through. This resulted in a working payload and we got the flag! 🇧🇪