Skip to content

Commit df2ab9b

Browse files
authored
Merge pull request #411 from RUB-NDS/SSL2ClientMasterKey
Ssl2 client master key
2 parents 94bd12c + d6b0a1f commit df2ab9b

38 files changed

+1330
-183
lines changed

.gitignore

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,38 @@ pom.xml.next
66
release.properties
77
/apps/
88
nbproject/
9-
nbactions.xml
9+
nbactions.xml.project
10+
.settings/org.eclipse.core.resources.prefs
11+
Attacks/.classpath
12+
Attacks/.project
13+
Attacks/.settings/org.eclipse.core.resources.prefs
14+
Attacks/.settings/org.eclipse.jdt.core.prefs
15+
TLS-Client/.classpath
16+
TLS-Client/.project
17+
TLS-Client/.settings/org.eclipse.core.resources.prefs
18+
TLS-Client/.settings/org.eclipse.jdt.core.prefs
19+
TLS-Core/.classpath
20+
TLS-Core/.project
21+
TLS-Core/.settings/org.eclipse.core.resources.prefs
22+
TLS-Core/.settings/org.eclipse.jdt.core.prefs
23+
TLS-Mitm/.classpath
24+
TLS-Mitm/.project
25+
TLS-Mitm/.settings/org.eclipse.core.resources.prefs
26+
TLS-Mitm/.settings/org.eclipse.jdt.core.prefs
27+
TLS-Server/.classpath
28+
TLS-Server/.project
29+
TLS-Server/.settings/org.eclipse.core.resources.prefs
30+
TLS-Server/.settings/org.eclipse.jdt.core.prefs
31+
TraceTool/.classpath
32+
TraceTool/.project
33+
TraceTool/.settings/org.eclipse.core.resources.prefs
34+
TraceTool/.settings/org.eclipse.jdt.core.prefs
35+
Transport/.classpath
36+
Transport/.project
37+
Transport/.settings/org.eclipse.core.resources.prefs
38+
Transport/.settings/org.eclipse.jdt.core.prefs
39+
Utils/.classpath
40+
Utils/.project
41+
Utils/.settings/org.eclipse.core.resources.prefs
42+
Utils/.settings/org.eclipse.jdt.core.prefs
43+
.project

Attacks/early_finished.xml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2+
<workflowTrace>
3+
<Send>
4+
<messages>
5+
<ClientHello>
6+
<extensions>
7+
<ECPointFormat/>
8+
<EllipticCurves/>
9+
<RenegotiationInfoExtension/>
10+
</extensions>
11+
</ClientHello>
12+
</messages>
13+
</Send>
14+
<Receive>
15+
<expectedMessages>
16+
<ServerHello>
17+
<extensions>
18+
<ECPointFormat/>
19+
<RenegotiationInfoExtension/>
20+
</extensions>
21+
</ServerHello>
22+
<Certificate/>
23+
<ServerHelloDone/>
24+
</expectedMessages>
25+
</Receive>
26+
<Send>
27+
<messages>
28+
<RSAClientKeyExchange/>
29+
<ChangeCipherSpec/>
30+
</messages>
31+
</Send>
32+
<Receive>
33+
<expectedMessages>
34+
<ChangeCipherSpec/>
35+
<Finished/>
36+
</expectedMessages>
37+
</Receive>
38+
</workflowTrace>

Attacks/src/main/java/de/rub/nds/tlsattacker/attacks/Main.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import de.rub.nds.tlsattacker.attacks.config.PskBruteForcerAttackServerCommandConfig;
1414
import de.rub.nds.tlsattacker.attacks.config.PskBruteForcerAttackClientCommandConfig;
1515
import de.rub.nds.tlsattacker.attacks.config.Cve20162107CommandConfig;
16+
import de.rub.nds.tlsattacker.attacks.config.DrownCommandConfig;
1617
import de.rub.nds.tlsattacker.attacks.config.EarlyCCSCommandConfig;
1718
import de.rub.nds.tlsattacker.attacks.config.HeartbleedCommandConfig;
1819
import de.rub.nds.tlsattacker.attacks.config.InvalidCurveAttackConfig;
@@ -28,6 +29,7 @@
2829
import de.rub.nds.tlsattacker.attacks.impl.PskBruteForcerAttackServer;
2930
import de.rub.nds.tlsattacker.attacks.impl.PskBruteForcerAttackClient;
3031
import de.rub.nds.tlsattacker.attacks.impl.Cve20162107Attacker;
32+
import de.rub.nds.tlsattacker.attacks.impl.DrownAttacker;
3133
import de.rub.nds.tlsattacker.attacks.impl.EarlyCCSAttacker;
3234
import de.rub.nds.tlsattacker.attacks.impl.HeartbleedAttacker;
3335
import de.rub.nds.tlsattacker.attacks.impl.InvalidCurveAttacker;
@@ -88,6 +90,8 @@ public static void main(String[] args) {
8890
jc.addCommand(SimpleMitmProxyCommandConfig.ATTACK_COMMAND, simpleMitmProxy);
8991
TooManyAlgorithmsAttackConfig tooManyAlgorithms = new TooManyAlgorithmsAttackConfig(generalDelegate);
9092
jc.addCommand(TooManyAlgorithmsAttackConfig.ATTACK_COMMAND, tooManyAlgorithms);
93+
DrownCommandConfig drownConfig = new DrownCommandConfig(generalDelegate);
94+
jc.addCommand(DrownCommandConfig.COMMAND, drownConfig);
9195
// TokenBindingMitmCommandConfig tokenBindingMitm = new
9296
// TokenBindingMitmCommandConfig(generalDelegate);
9397
// jc.addCommand(TokenBindingMitmCommandConfig.ATTACK_COMMAND,
@@ -149,7 +153,9 @@ public static void main(String[] args) {
149153
case PskBruteForcerAttackServerCommandConfig.ATTACK_COMMAND:
150154
attacker = new PskBruteForcerAttackServer(pskBruteForcerAttackServerTest);
151155
break;
152-
156+
case DrownCommandConfig.COMMAND:
157+
attacker = new DrownAttacker(drownConfig);
158+
break;
153159
// case TokenBindingMitmCommandConfig.ATTACK_COMMAND:
154160
// attacker = new TokenBindingMitm(tokenBindingMitm);
155161
// break;
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* TLS-Attacker - A Modular Penetration Testing Framework for TLS
3+
*
4+
* Copyright 2014-2017 Ruhr University Bochum / Hackmanit GmbH
5+
*
6+
* Licensed under Apache License 2.0
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*/
9+
package de.rub.nds.tlsattacker.attacks.config;
10+
11+
import com.beust.jcommander.ParametersDelegate;
12+
import de.rub.nds.tlsattacker.core.config.Config;
13+
import de.rub.nds.tlsattacker.core.config.delegate.ClientDelegate;
14+
import de.rub.nds.tlsattacker.core.config.delegate.GeneralDelegate;
15+
import de.rub.nds.tlsattacker.core.constants.HeartbeatMode;
16+
import de.rub.nds.tlsattacker.core.constants.ProtocolVersion;
17+
import de.rub.nds.tlsattacker.core.record.layer.RecordLayerType;
18+
import de.rub.nds.tlsattacker.core.workflow.factory.WorkflowTraceType;
19+
20+
public class DrownCommandConfig extends AttackConfig {
21+
22+
public static final String COMMAND = "drown";
23+
24+
@ParametersDelegate
25+
private ClientDelegate clientDelegate;
26+
27+
public DrownCommandConfig(GeneralDelegate delegate) {
28+
super(delegate);
29+
clientDelegate = new ClientDelegate();
30+
addDelegate(clientDelegate);
31+
}
32+
33+
@Override
34+
public boolean isExecuteAttack() {
35+
return false;
36+
}
37+
38+
@Override
39+
public Config createConfig() {
40+
Config config = super.createConfig();
41+
config.setRecordLayerType(RecordLayerType.BLOB);
42+
config.setHighestProtocolVersion(ProtocolVersion.SSL2);
43+
return config;
44+
}
45+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* TLS-Attacker - A Modular Penetration Testing Framework for TLS
3+
*
4+
* Copyright 2014-2017 Ruhr University Bochum / Hackmanit GmbH
5+
*
6+
* Licensed under Apache License 2.0
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*/
9+
package de.rub.nds.tlsattacker.attacks.constants;
10+
11+
/**
12+
*
13+
* @author Robert Merget <robert.merget@rub.de>
14+
*/
15+
public enum DrownVulnerabilityType {
16+
FULL,
17+
SSL2,
18+
NONE,
19+
UNKNOWN
20+
}

Attacks/src/main/java/de/rub/nds/tlsattacker/attacks/impl/Attacker.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ public Boolean checkVulnerability() {
5252
if (!canConnect()) {
5353
LOGGER.log(LogLevel.CONSOLE_OUTPUT, "Cannot reach Server. Is the server online?");
5454
return null;
55+
} else {
56+
LOGGER.debug("Can connect to server. Running vulnerability scan");
5557
}
5658
}
5759
return isVulnerable();
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/**
2+
* TLS-Attacker - A Modular Penetration Testing Framework for TLS
3+
*
4+
* Copyright 2014-2017 Ruhr University Bochum / Hackmanit GmbH
5+
*
6+
* Licensed under Apache License 2.0
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*/
9+
package de.rub.nds.tlsattacker.attacks.impl;
10+
11+
import de.rub.nds.modifiablevariable.bytearray.ByteArrayModificationFactory;
12+
import de.rub.nds.modifiablevariable.bytearray.ModifiableByteArray;
13+
import de.rub.nds.modifiablevariable.integer.IntegerModificationFactory;
14+
import de.rub.nds.modifiablevariable.integer.ModifiableInteger;
15+
import de.rub.nds.modifiablevariable.singlebyte.ModifiableByte;
16+
import de.rub.nds.tlsattacker.attacks.config.DrownCommandConfig;
17+
import de.rub.nds.tlsattacker.attacks.config.HeartbleedCommandConfig;
18+
import de.rub.nds.tlsattacker.attacks.constants.DrownVulnerabilityType;
19+
import static de.rub.nds.tlsattacker.attacks.impl.Attacker.LOGGER;
20+
import de.rub.nds.tlsattacker.core.config.Config;
21+
import de.rub.nds.tlsattacker.core.constants.HandshakeMessageType;
22+
import de.rub.nds.tlsattacker.core.constants.ProtocolMessageType;
23+
import de.rub.nds.tlsattacker.core.constants.RunningModeType;
24+
import de.rub.nds.tlsattacker.core.constants.SSL2CipherSuite;
25+
import de.rub.nds.tlsattacker.core.exceptions.WorkflowExecutionException;
26+
import de.rub.nds.tlsattacker.core.protocol.message.HeartbeatMessage;
27+
import de.rub.nds.tlsattacker.core.protocol.message.SSL2ClientMasterKeyMessage;
28+
import de.rub.nds.tlsattacker.core.protocol.message.SSL2ServerHelloMessage;
29+
import de.rub.nds.tlsattacker.core.protocol.message.SSL2ServerVerifyMessage;
30+
import de.rub.nds.tlsattacker.core.protocol.preparator.SSL2ClientMasterKeyPreparator;
31+
import de.rub.nds.tlsattacker.core.state.State;
32+
import de.rub.nds.tlsattacker.core.state.TlsContext;
33+
import de.rub.nds.tlsattacker.core.util.LogLevel;
34+
import de.rub.nds.tlsattacker.core.workflow.WorkflowExecutor;
35+
import de.rub.nds.tlsattacker.core.workflow.WorkflowExecutorFactory;
36+
import de.rub.nds.tlsattacker.core.workflow.WorkflowTrace;
37+
import de.rub.nds.tlsattacker.core.workflow.WorkflowTraceUtil;
38+
import de.rub.nds.tlsattacker.core.workflow.action.GenericReceiveAction;
39+
import de.rub.nds.tlsattacker.core.workflow.action.ReceiveAction;
40+
import de.rub.nds.tlsattacker.core.workflow.action.SendAction;
41+
import de.rub.nds.tlsattacker.core.workflow.factory.WorkflowConfigurationFactory;
42+
import de.rub.nds.tlsattacker.core.workflow.factory.WorkflowTraceType;
43+
import java.util.Arrays;
44+
import java.util.List;
45+
46+
import org.bouncycastle.crypto.digests.MD5Digest;
47+
import org.bouncycastle.crypto.engines.RC4Engine;
48+
import org.bouncycastle.crypto.params.KeyParameter;
49+
50+
public class DrownAttacker extends Attacker<DrownCommandConfig> {
51+
52+
public DrownAttacker(DrownCommandConfig config) {
53+
super(config);
54+
}
55+
56+
@Override
57+
public void executeAttack() {
58+
throw new UnsupportedOperationException("Not implemented yet");
59+
}
60+
61+
@Override
62+
public Boolean isVulnerable() {
63+
DrownVulnerabilityType type = getDrownVulnerabilityType();
64+
switch (type) {
65+
case FULL:
66+
LOGGER.log(LogLevel.CONSOLE_OUTPUT, "Server is vulnerable to the full DROWN attack");
67+
return true;
68+
case NONE:
69+
return false;
70+
case SSL2:
71+
LOGGER.log(LogLevel.CONSOLE_OUTPUT, "Server supports SSL2, but not any weak ciphersuites, "
72+
+ "so is not vulnerable to DROWN");
73+
return false;
74+
case UNKNOWN:
75+
LOGGER.warn("Could not execute Workflow - something went wrong. Check the Debug output to be certain");
76+
return null;
77+
}
78+
return null;
79+
}
80+
81+
public DrownVulnerabilityType getDrownVulnerabilityType() {
82+
Config tlsConfig = config.createConfig();
83+
WorkflowTrace trace = new WorkflowConfigurationFactory(tlsConfig).createWorkflowTrace(
84+
WorkflowTraceType.SSL2_HELLO, RunningModeType.CLIENT);
85+
trace.addTlsAction(new SendAction(new SSL2ClientMasterKeyMessage()));
86+
trace.addTlsAction(new ReceiveAction(new SSL2ServerVerifyMessage()));
87+
State state = new State(tlsConfig, trace);
88+
try {
89+
WorkflowExecutor workflowExecutor = WorkflowExecutorFactory.createWorkflowExecutor(
90+
tlsConfig.getWorkflowExecutorType(), state);
91+
workflowExecutor.executeWorkflow();
92+
} catch (WorkflowExecutionException ex) {
93+
LOGGER.info("The TLS protocol flow was not executed completely, follow the debug messages for more information.");
94+
LOGGER.debug(ex);
95+
return DrownVulnerabilityType.UNKNOWN;
96+
}
97+
98+
if (!WorkflowTraceUtil.didReceiveMessage(HandshakeMessageType.SSL2_SERVER_HELLO, trace)) {
99+
return DrownVulnerabilityType.NONE;
100+
}
101+
102+
SSL2ServerHelloMessage serverHello = (SSL2ServerHelloMessage) WorkflowTraceUtil.getFirstReceivedMessage(
103+
HandshakeMessageType.SSL2_SERVER_HELLO, trace);
104+
List<SSL2CipherSuite> serverCipherSuites = SSL2CipherSuite.getCiphersuites(serverHello.getCipherSuites()
105+
.getValue());
106+
for (SSL2CipherSuite cipherSuite : serverCipherSuites) {
107+
if (cipherSuite.isWeak()) {
108+
LOGGER.debug("Declaring host as vulnerable based on weak ciphersuite in ServerHello.");
109+
return DrownVulnerabilityType.FULL;
110+
}
111+
}
112+
SSL2ServerVerifyMessage message = (SSL2ServerVerifyMessage) WorkflowTraceUtil.getFirstReceivedMessage(
113+
HandshakeMessageType.SSL2_SERVER_VERIFY, trace);
114+
if (message != null && checkServerVerifyMessage(message, state.getTlsContext())) {
115+
LOGGER.debug("Declaring host as vulnerable based on ServerVerify.");
116+
return DrownVulnerabilityType.FULL;
117+
}
118+
return DrownVulnerabilityType.SSL2;
119+
}
120+
121+
private boolean checkServerVerifyMessage(SSL2ServerVerifyMessage message, TlsContext context) {
122+
byte[] md5Output = getMD5Output(context);
123+
124+
RC4Engine rc4 = new RC4Engine();
125+
rc4.init(false, new KeyParameter(md5Output));
126+
byte[] encrypted = message.getEncryptedPart().getValue();
127+
int len = encrypted.length;
128+
if (len < 16) {
129+
return false;
130+
}
131+
132+
byte[] decrypted = new byte[len];
133+
rc4.processBytes(encrypted, 0, len, decrypted, 0);
134+
135+
if (Arrays.equals(Arrays.copyOfRange(decrypted, len - 16, len), context.getClientRandom())) {
136+
return true;
137+
} else {
138+
return false;
139+
}
140+
}
141+
142+
private byte[] getMD5Output(TlsContext tlsContext) {
143+
MD5Digest md5 = new MD5Digest();
144+
byte[] clearKey = new byte[SSL2ClientMasterKeyPreparator.EXPORT_RC4_NUM_OF_CLEAR_KEY_BYTES];
145+
md5Update(md5, clearKey);
146+
md5Update(md5, tlsContext.getPreMasterSecret());
147+
md5.update((byte) '0');
148+
md5Update(md5, tlsContext.getClientRandom());
149+
md5Update(md5, tlsContext.getServerRandom());
150+
byte[] md5Output = new byte[md5.getDigestSize()];
151+
md5.doFinal(md5Output, 0);
152+
return md5Output;
153+
}
154+
155+
private static void md5Update(MD5Digest md5, byte[] bytes) {
156+
md5.update(bytes, 0, bytes.length);
157+
}
158+
}

TLS-Core/src/main/java/de/rub/nds/tlsattacker/core/constants/HandshakeMessageType.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,14 @@ public enum HandshakeMessageType {
1919
UNKNOWN((byte) 255),
2020
HELLO_REQUEST((byte) 0),
2121
CLIENT_HELLO((byte) 1),
22+
SSL2_CLIENT_HELLO((byte) 1),
2223
SERVER_HELLO((byte) 2),
24+
SSL2_CLIENT_MASTER_KEY((byte) 2),
2325
HELLO_VERIFY_REQUEST((byte) 3),
2426
NEW_SESSION_TICKET((byte) 4),
27+
SSL2_SERVER_HELLO((byte) 4),
2528
END_OF_EARLY_DATA((byte) 5),
29+
SSL2_SERVER_VERIFY((byte) 5),
2630
HELLO_RETRY_REQUEST((byte) 6),
2731
ENCRYPTED_EXTENSIONS((byte) 8),
2832
CERTIFICATE((byte) 11),

0 commit comments

Comments
 (0)