/** * 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.testsuite.impl; import java.io.File; import java.io.FileFilter; import java.io.FilenameFilter; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import de.rub.nds.tlsattacker.attacks.config.BleichenbacherCommandConfig; import de.rub.nds.tlsattacker.attacks.config.HeartbleedCommandConfig; import de.rub.nds.tlsattacker.attacks.config.InvalidCurveAttackCommandConfig; import de.rub.nds.tlsattacker.attacks.config.PaddingOracleCommandConfig; import de.rub.nds.tlsattacker.attacks.config.PoodleCommandConfig; import de.rub.nds.tlsattacker.attacks.impl.BleichenbacherAttack; import de.rub.nds.tlsattacker.attacks.impl.HeartbleedAttack; import de.rub.nds.tlsattacker.attacks.impl.InvalidCurveAttack; import de.rub.nds.tlsattacker.attacks.impl.PaddingOracleAttack; import de.rub.nds.tlsattacker.attacks.impl.PoodleAttack; import de.rub.nds.tlsattacker.modifiablevariable.ModifiableVariable; import de.rub.nds.tlsattacker.modifiablevariable.util.ModifiableVariableAnalyzer; import de.rub.nds.tlsattacker.modifiablevariable.util.ModifiableVariableField; import de.rub.nds.tlsattacker.testsuite.config.ServerTestSuiteConfig; import de.rub.nds.tlsattacker.tls.Attacker; import de.rub.nds.tlsattacker.tls.config.CommandConfig; import de.rub.nds.tlsattacker.tls.config.ConfigHandler; import de.rub.nds.tlsattacker.tls.config.ConfigHandlerFactory; import de.rub.nds.tlsattacker.tls.config.GeneralConfig; import de.rub.nds.tlsattacker.tls.exceptions.ConfigurationException; import de.rub.nds.tlsattacker.tls.exceptions.WorkflowExecutionException; import de.rub.nds.tlsattacker.tls.util.LogLevel; import de.rub.nds.tlsattacker.tls.workflow.TlsContext; import de.rub.nds.tlsattacker.tls.workflow.TlsContextAnalyzer; import de.rub.nds.tlsattacker.tls.workflow.WorkflowExecutor; import de.rub.nds.tlsattacker.transport.TransportHandler; /** * * @author Juraj Somorovsky <juraj.somorovsky@rub.de> */ public class ServerTestSuite extends TestSuite { public static Logger LOGGER = LogManager.getLogger(ServerTestSuite.class); private final ServerTestSuiteConfig testConfig; private ConfigHandler configHandler; public ServerTestSuite(ServerTestSuiteConfig serverTestConfig, GeneralConfig generalConfig) { super(generalConfig); this.testConfig = serverTestConfig; } @Override public boolean startTests() { configHandler = ConfigHandlerFactory.createConfigHandler("client"); configHandler.initialize(generalConfig); this.startAttackTests(); this.startTestFromFiles(); return failedTests.isEmpty(); } private void startAttackTests() { Attacker<? extends CommandConfig> attacker; BleichenbacherCommandConfig bb = new BleichenbacherCommandConfig(); bb.setConnect(testConfig.getConnect()); attacker = new BleichenbacherAttack(bb); attacker.executeAttack(configHandler); if(attacker.isVulnerable()) { failedTests.add(BleichenbacherCommandConfig.ATTACK_COMMAND); } else { successfulTests.add(BleichenbacherCommandConfig.ATTACK_COMMAND); } InvalidCurveAttackCommandConfig icea = new InvalidCurveAttackCommandConfig(); icea.setConnect(testConfig.getConnect()); attacker = new InvalidCurveAttack(icea); attacker.executeAttack(configHandler); if(attacker.isVulnerable()) { failedTests.add(InvalidCurveAttackCommandConfig.ATTACK_COMMAND); } else { successfulTests.add(InvalidCurveAttackCommandConfig.ATTACK_COMMAND); } HeartbleedCommandConfig heartbleed = new HeartbleedCommandConfig(); heartbleed.setConnect(testConfig.getConnect()); attacker = new HeartbleedAttack(heartbleed); attacker.executeAttack(configHandler); if(attacker.isVulnerable()) { failedTests.add(HeartbleedCommandConfig.ATTACK_COMMAND); } else { successfulTests.add(HeartbleedCommandConfig.ATTACK_COMMAND); } PoodleCommandConfig poodle = new PoodleCommandConfig(); poodle.setConnect(testConfig.getConnect()); attacker = new PoodleAttack(poodle); attacker.executeAttack(configHandler); if(attacker.isVulnerable()) { failedTests.add(PoodleCommandConfig.ATTACK_COMMAND); } else { successfulTests.add(PoodleCommandConfig.ATTACK_COMMAND); } PaddingOracleCommandConfig po = new PaddingOracleCommandConfig(); po.setConnect(testConfig.getConnect()); attacker = new PaddingOracleAttack(po); attacker.executeAttack(configHandler); if(attacker.isVulnerable()) { failedTests.add(PaddingOracleCommandConfig.ATTACK_COMMAND); } else { successfulTests.add(PaddingOracleCommandConfig.ATTACK_COMMAND); } } private void startTestFromFiles() { File folder = new File(testConfig.getFolder()); File[] testsuites = folder.listFiles(new DirectoryFilter()); if(null == testsuites) { testsuites = new File[0]; } for (File testsuite : testsuites) { LOGGER.log(LogLevel.CONSOLE_OUTPUT, "Starting {} Test Suite", testsuite.getName()); File[] tests = testsuite.listFiles(new DirectoryFilter()); if(null == tests) { tests = new File[0]; } for (File test : tests) { LOGGER.info("Testing {} (one of these has to be succesful)", test.getName()); File[] testCases = test.listFiles(new DirectoryFilter()); if(null == testCases) { testCases = new File[0]; } boolean successfulTest = false; for (File testCase : testCases) { LOGGER.info(" Running {}", testCase.getName()); if (startTestCase(testCase)) { // one of our test cases was successful successfulTest = true; } } if (successfulTest) { LOGGER.log(LogLevel.CONSOLE_OUTPUT, "{} SUCCESSFUL ", test.getName()); successfulTests.add(test.getName()); } else { LOGGER.log(LogLevel.CONSOLE_OUTPUT, "{} FAILED ", test.getName()); failedTests.add(test.getName()); } } } LOGGER.log(LogLevel.CONSOLE_OUTPUT, "Summary of successful tests"); for (String s : successfulTests) { LOGGER.log(LogLevel.CONSOLE_OUTPUT, " {}", s); } LOGGER.log(LogLevel.CONSOLE_OUTPUT, "Summary of failed tests"); for (String s : failedTests) { LOGGER.log(LogLevel.CONSOLE_OUTPUT, " {}", s); } LOGGER.log(LogLevel.CONSOLE_OUTPUT, "Successful tests: {}", successfulTests.size()); LOGGER.log(LogLevel.CONSOLE_OUTPUT, "Failed tests: {}", failedTests.size()); } private boolean startTestCase(File testFolder) { boolean succesful = true; File[] xmlFiles = testFolder.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.toLowerCase().endsWith(".xml"); } }); if(null == xmlFiles) { xmlFiles = new File[0]; } for (File xmlFile : xmlFiles) { try { testConfig.setWorkflowInput(xmlFile.getAbsolutePath()); TransportHandler transportHandler = configHandler.initializeTransportHandler(testConfig); TlsContext tlsContext = configHandler.initializeTlsContext(testConfig); WorkflowExecutor workflowExecutor = configHandler.initializeWorkflowExecutor(transportHandler, tlsContext); workflowExecutor.executeWorkflow(); transportHandler.closeConnection(); if (TlsContextAnalyzer.containsFullWorkflow(tlsContext)) { LOGGER.info(" {} passed", xmlFile.getName()); List<ModifiableVariableField> mvfs = ModifiableVariableAnalyzer .getAllModifiableVariableFieldsRecursively(tlsContext.getWorkflowTrace()); for (ModifiableVariableField mvf : mvfs) { ModifiableVariable mv = mvf.getModifiableVariable(); if (mv != null && mv.containsAssertion()) { if (mv.validateAssertions()) { LOGGER.info(" Assertion in {}.{} succesfully validated", mvf.getObject().getClass() .getSimpleName(), mvf.getField().getName()); } else { LOGGER.info(" Assertion in {}.{} invalid", mvf.getObject().getClass() .getSimpleName(), mvf.getField().getName()); succesful = false; } } } } else { LOGGER.info(" {} failed", xmlFile.getName()); succesful = false; } } catch (WorkflowExecutionException | ConfigurationException | IllegalArgumentException | IllegalAccessException ex) { LOGGER.info(" {} failed", xmlFile.getName()); LOGGER.info(ex); succesful = false; } } return succesful; } class DirectoryFilter implements FileFilter { @Override public boolean accept(File f) { return f.isDirectory(); } }; }