After learning the techniques for exploiting XXE vulnerability, it is time to explore exploiting XXE with a local DTD. This technique becomes necessary when some restrictions on the application server prevent you from declaring external DTDs. A local DTD refers to a .dtd file that already exist on the target server.
When to use Local DTD?
1. When you cannot retrieve data in-band because there is no reflection of your injected.
2. When you are unable to retrieve data OOB due to certain restrictions.
XXE Testing Methodology
1. Change the XML object to anything.
2. Try to declare a reference entity or parameter entity.
3. Change the file protocol handler value to a nonexistent one. Alternatively, you can change the file protocol handler to http to point your own server and observe the access logs by using the command “tail -f /var/log/apache2/access.log” to test for XXE.
It doesn’t make sense to declare a reference entity due to the Invalid product ID, but let’s give it a try.
As you can see, the error we received has changed and now we are able to see that “etc/passwd” keyword has reflected on the response. It’s time to proceed step 3. I modified the file protocol handler’s value with a nonexistent document, and it resulted in an error “No such file or directory.” As you can see, in this point, you can enumerate all the documents on the server. However, there is a tip on the lab definitions. There is a local DTD file located at “/usr/share/elp/dtd/docbookx.dtd”
I tried to read the given DTD file, but the file was complicated, so I did a quick search. The GitHub source and this blog were pretty cool. I just copied and pasted.
When the XML parser encounters “ENTITY % local_dtd SYSTEM “file:///usr/share/yelp/dtd/docbookx.dtd”, it fetches the “docbookx.dtd” file and assigns its content to the “local_dtd” entity variable. This is because the SYSTEM operand denotes an external DTD. In this example, we are unable to define an external DTD. Therefore, we treat the local DTD file as if it were external and shape out payload accordingly.
Similarly, we placed the content of “/etc/passwd” into the file variable entity. using “ENTITY % file SYSTEM “file:///etc/passwd”. We encode the % symbol to avoid confusion during the parsing process.
In the line “ENTITY % evval ENTITY % error SYSTEM 'file:///abcxyz/%file;'” the objective is to cause an error, as we discovered before. We use this approach to read a multi-line file. In other words, we are dynamically requesting the %file variable.
(file:///abcxyz/%file;)