Fig. 1. Landing
Fig. 2. The original response


First attempt: XXE through request body

Fig. 3. Checking XXE with file-scheme
Fig. 4. Checking XXE with http-scheme
  • There’s some XML processing with a standard Java SAX parser from javax.xml.* (standard error messages).
  • file and http (https) schemes are not allowed for general entities.
  • The Java web-application possibly uses Spring (standard JSON-object format for Internal Server Error).

Second attempt: Fuzzing payload format

Fig. 5. Attempt to inject tags into attribute value
Fig. 6. Attempt to send invalid string value for field with type int
Fig. 7. Attempt to send random string as a value of type-attribute for field

Endpoint discovery

Fig. 8. Dirbusting with Burp Suite Intruder (why not? 🙂)
Fig. 9. Checking /dev/api/render

Third attempt: Fuzzing payload format through developers’ endpoint

Fig. 10. Attempt to inject tags into attrubute value
Fig. 11. Attempt to send random string as a value of type-attribute for field
Fig. 12. Attempt to send invalid string value for field with type int
Fig. 13. Executing Python code with eval function

Investigating server through RCE

It’s time to make some preparations. To send arbitrary code for evaluation and ensure it runs as intended, it is good to write some code to automate these tasks.

Searching for information

Listing application directory:

  1. — the Bottle, a single file web framework for Python.
  2. card_render — an application folder with source files
  3. — a file with a hint:
{internet} -> 80:[front] -> 4041:[waf]{FLAG is here} -> 3031:[app]
------> 3031:[app-dev]

Network connectivity

Everybody wants a reverse shell after RCE, but its possibility depends on network connectivity. By means of a wget or with a Python socket module we can check that there's no TCP/UDP connection from app-dev to the Internet.


Now we know that:

  1. app is a Python web application that renders SVG and has an RCE vulnerability.
  2. app-dev is an instance of app, but for testing purposes.
  3. waf is a Java web application that validates requests for app and makes the app's RCE not exploitable.
  4. FLAG for this challenge is stored on the waf machine.


WAF Bypass

We can make some preparations to do research on XML validation via java.xml.*.

Playing with invalid XML document

Here you need to find a 0-day to bypass validation. There are not so many things you can play with: the internal DTD and namespaces.


Now we can update our attacking script to work with the production API endpoint — adding WAF bypass logic:

Searching vectors to WAF

According to the network hint, there must be some vulnerability on the WAF that will expose the FLAG.

  1. hidden vulnerable endpoint/service that is only accessible from the internal network
  2. XML processing of SVG-response from the app

Attack on the way back

We need to replace SVG in the response from app with our XXE payload.

  1. There is a response validation by SVG schema (tests 1, 5, 6, 7).
  2. During response validation, waf resolves external entities and allows external HTTP requests (test 3).
  3. Invalid attribute value for SVG element rect is reflected in the response error message (test 7). - [11/Feb/2021 03:13:37] 
"GET /?{78806158f1928b18ec1a583c0b9b82c5} HTTP/1.1" 200 -

The whole chain

Fig. 14. The whole chain of exploitation

BONUS: Original design w/o simplification :)

Originally, the waf had no connection to the Internet. So, OOB XXE was not applicable.

Fig. 15. The original chain of exploitation


Roman Shemyakin (@ramon93i7) — Design, Implementation, CVE-2020–14621
Vlad Lazarev (@Val1d) — “Roma, please, make it s1mpler!”



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store



International community conference for cybersecurity researchers and professionals. No suits, no business — only hardcore research.