If you are a security enthusiast, like me, then you likely find yourself tinkering with exploit code for most of the major vulnerabilities that are released. This "tinkering" can be incredibly valuable to security researchers, blue teamers, and especially penetration testers. In fact, I frequently find myself modifying and testing public exploit code during penetration tests.
The reason for modifying this code is most often due to the fact that a lot of exploit code written for websites like "exploit-db.com" are proof-of-concept scripts that show a concept, but don't exploit it flexibly or as efficiently as they could. For example, when the Equifax breach came out, I set up a lab with several of the major Apache Struts vulnerabilities from 2017 for testing purposes. CVE-2017-5638 and CVE-2017-9805 were two easily testable exploits thanks to Metasploit having modules available.
Normally Metasploit is highly modular and achieves what I need but that's not always the case. In this instance, the module in question was limited to reverse call back payloads. While such payloads are very useful, it's very common for reverse connections from DMZ servers to be blocked. On top of this, it assumes that you also have a public IP to catch the call back on or perhaps in-bound firewall filtering is in place to block bind shells. These are all examples of instances where pulling down publicly released exploit code and modifying it would come in handy.
Problems facing some publicly released proof-of-concept exploit code is that it is often created without giving any major thought to user error, how applications function, or countless other factors. CVE-2017-9805 was a perfect example of this as Metasploit didn't solve my reverse call back issue. Additionally, the sample public exploit code I found for it didn't properly handle special characters due to the payload being XML and would break if a user-supplied command contained certain special characters.
Challenges Of Modifying CVE-2017-9805 Exploit Code
The Apache Struts 2 REST Plugin XStream RCE (CVE-2017-9805) uses an XStream handler to deserialize without type filtering of XML payloads. As such, a properly crafted XML payload could allow an attacker to send a specially crafted HTTP request to achieve command execution.
The problem with most of the public exploit code I found was that it wasn't
object-oriented and simply did string concatenation to insert the user supplied command in-between the XML payload without accounting for special characters that break XML.
A quick example of XML without special characters:
<memo> <to>Nick Burns</to> <from>HR</from> <heading>Need Help Cant Print</heading> <body>Cant print out. Need computer help </body> </memo>
Now what happens if we pass in special characters as simple as a text emoji of ">_> "?
<memo> <to>Nick Burns</to> <from>HR</from> <heading>Need Help Cant Print</heading> <body>Cant print out. Need computer help >_> </body> </memo>
The unencoded ">" characters near the end would likely throw off our payload. This is likely to happen in a user supplied command as the greater than symbol ">" is often used to direct standard out to a file in Linux. The XML format uses entity encoding similar to HTML to account for this. For example, if we wanted to encode the greater than sign ">" for XML, we would convert to ">".
The problem with this encoding when trying to achieve command execution through struts is that it will not interpret these characters to the system as the intended greater than sign ">"; which breaks our command execution.
This means we need to:
1. Encode special characters without using XML encoding
2. Decode that on the command line and execute it without using any special characters that would break XML.
We could base64 encode the user supplied command (since base64 characters don't break XML) and decode that on the command line into a file, then execute that file with /bin/bash and then remove that temporary file all while avoiding special XML characters. For example, the following one-line command could achieve this:
echo L3Vzci9iaW4vd2hvYW1pIA==| base64 -d | tee -a /tmp/payload.tmp ; /bin/bash /tmp/payload.tmp; /bin/rm /tmp/ payload.tmp
Finally, we embed this command in our XML payload and our vulnerable apache struts server will execute the user's base64 encoded command regardless of any special characters in their supplied command. A sample of the finished version of the exploit code for CVE-2017-9805 can be found here:
The above example a perfect illustration of why having the skills to interpret and modify public exploit code "on-the-fly" is so critical a skill to possess. This is especially true of penetration testers and is often what separates "Script Kiddies" from the proficient security professionals.