Работа над распаковкой TLS
This commit is contained in:
@@ -39,16 +39,18 @@ public class LivePcapWorker extends AbstractPcapWorker {
|
||||
|
||||
applyFilter();
|
||||
|
||||
try {
|
||||
log.info("Intercept started");
|
||||
pcap.loop(-1, this, loopExecutorService);
|
||||
} catch (InterruptedException ignored) {
|
||||
Thread.currentThread().interrupt();
|
||||
// выходим
|
||||
} catch (Exception e) {
|
||||
log.error("Error while capturing packet", e);
|
||||
stop();
|
||||
}
|
||||
loopExecutorService.execute(() -> {
|
||||
try {
|
||||
log.info("Intercept started");
|
||||
pcap.loop(-1, this);
|
||||
} catch (InterruptedException ignored) {
|
||||
Thread.currentThread().interrupt();
|
||||
// выходим
|
||||
} catch (Exception e) {
|
||||
log.error("Error while capturing packet", e);
|
||||
stop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
|
||||
@@ -33,6 +33,7 @@ public class RsaKeysHolder {
|
||||
|
||||
@EventListener(ApplicationReadyEvent.class)
|
||||
public void afterStartup(ApplicationReadyEvent event) {
|
||||
log.info("Loading RSA keys...");
|
||||
File dir = new File("rsa_keys");
|
||||
if (dir.exists() && dir.isDirectory()) {
|
||||
for (File keyFile : Objects.requireNonNull(dir.listFiles())) {
|
||||
|
||||
@@ -21,27 +21,57 @@ public class StreamOptimizer {
|
||||
*/
|
||||
public List<Packet> optimizeStream() {
|
||||
if (service.isDecryptTls()) {
|
||||
decryptTls();
|
||||
try {
|
||||
decryptTls();
|
||||
} catch (Exception e) {
|
||||
log.warn("Error optimizing stream (tls)", e);
|
||||
return packets;
|
||||
}
|
||||
}
|
||||
|
||||
if (service.isProcessChunkedEncoding()) {
|
||||
processChunkedEncoding();
|
||||
try {
|
||||
processChunkedEncoding();
|
||||
} catch (Exception e) {
|
||||
log.warn("Error optimizing stream (chunks)", e);
|
||||
return packets;
|
||||
}
|
||||
}
|
||||
|
||||
if (service.isUngzipHttp()) {
|
||||
unpackGzip();
|
||||
try {
|
||||
unpackGzip();
|
||||
} catch (Exception e) {
|
||||
log.warn("Error optimizing stream (gzip)", e);
|
||||
return packets;
|
||||
}
|
||||
}
|
||||
|
||||
if (service.isParseWebSockets()) {
|
||||
parseWebSockets();
|
||||
try {
|
||||
parseWebSockets();
|
||||
} catch (Exception e) {
|
||||
log.warn("Error optimizing stream (websocketss)", e);
|
||||
return packets;
|
||||
}
|
||||
}
|
||||
|
||||
if (service.isUrldecodeHttpRequests()) {
|
||||
urldecodeRequests();
|
||||
try {
|
||||
urldecodeRequests();
|
||||
} catch (Exception e) {
|
||||
log.warn("Error optimizing stream (urldecode)", e);
|
||||
return packets;
|
||||
}
|
||||
}
|
||||
|
||||
if (service.isMergeAdjacentPackets()) {
|
||||
mergeAdjacentPackets();
|
||||
try {
|
||||
mergeAdjacentPackets();
|
||||
} catch (Exception e) {
|
||||
log.warn("Error optimizing stream (adjacent)", e);
|
||||
return packets;
|
||||
}
|
||||
}
|
||||
|
||||
return packets;
|
||||
@@ -51,7 +81,7 @@ public class StreamOptimizer {
|
||||
final TlsDecryptor tlsDecryptor = new TlsDecryptor(packets, keysHolder);
|
||||
tlsDecryptor.decryptTls();
|
||||
|
||||
if(tlsDecryptor.isParsed()) {
|
||||
if (tlsDecryptor.isParsed()) {
|
||||
packets = tlsDecryptor.getParsedPackets();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,6 +99,7 @@ public class TlsDecryptor {
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private void decryptTlsRsa(String blockCipher, String hashAlgo) {
|
||||
Optional<RSAPublicKey> publicKeyOpt = getRsaPublicKey();
|
||||
|
||||
@@ -144,18 +145,8 @@ public class TlsDecryptor {
|
||||
bb.get(clientIV);
|
||||
bb.get(serverIV);
|
||||
|
||||
Optional<byte[]> clientFinishedOpt = getFinishedData(true);
|
||||
Optional<byte[]> serverFinishedOpt = getFinishedData(false);
|
||||
|
||||
if (clientFinishedOpt.isEmpty() || serverFinishedOpt.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] clientFinishedEncrypted = clientFinishedOpt.get();
|
||||
byte[] serverFinishedEncrypted = serverFinishedOpt.get();
|
||||
|
||||
Optional<Cipher> clientCipherOpt = createCipher(clientEncryptionKey, clientIV, clientFinishedEncrypted);
|
||||
Optional<Cipher> serverCipherOpt = createCipher(serverEncryptionKey, serverIV, serverFinishedEncrypted);
|
||||
Optional<Cipher> clientCipherOpt = createCipher(clientEncryptionKey, clientIV);
|
||||
Optional<Cipher> serverCipherOpt = createCipher(serverEncryptionKey, serverIV);
|
||||
|
||||
if (clientCipherOpt.isEmpty() || serverCipherOpt.isEmpty()) {
|
||||
return;
|
||||
@@ -174,13 +165,8 @@ public class TlsDecryptor {
|
||||
byte[] data = ((ApplicationDataRecord) tlsPacket.getRecord()).getData();
|
||||
boolean client = packet.isIncoming();
|
||||
|
||||
byte[] decoded;
|
||||
|
||||
if (client) {
|
||||
decoded = clientCipher.update(data);
|
||||
} else {
|
||||
decoded = serverCipher.update(data);
|
||||
}
|
||||
Cipher cipher = client ? clientCipher : serverCipher;
|
||||
byte[] decoded = cipher.doFinal(data);
|
||||
|
||||
decoded = clearDecodedData(decoded);
|
||||
|
||||
@@ -246,14 +232,13 @@ public class TlsDecryptor {
|
||||
}
|
||||
|
||||
@SneakyThrows(value = {NoSuchAlgorithmException.class, NoSuchPaddingException.class})
|
||||
private Optional<Cipher> createCipher(byte[] key, byte[] iv, byte[] initData) {
|
||||
private Optional<Cipher> createCipher(byte[] key, byte[] iv) {
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // TLS_RSA_WITH_AES_256_CBC_SHA
|
||||
SecretKeySpec serverSkeySpec = new SecretKeySpec(key, "AES");
|
||||
IvParameterSpec serverIvParameterSpec = new IvParameterSpec(iv);
|
||||
|
||||
try {
|
||||
cipher.init(Cipher.DECRYPT_MODE, serverSkeySpec, serverIvParameterSpec);
|
||||
cipher.update(initData);
|
||||
|
||||
return Optional.of(cipher);
|
||||
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
|
||||
@@ -263,26 +248,12 @@ public class TlsDecryptor {
|
||||
}
|
||||
|
||||
private byte[] clearDecodedData(byte[] decoded) {
|
||||
int start = 32;
|
||||
int end = decoded.length - 6; //FIXME
|
||||
int start = 16;
|
||||
int end = decoded.length - 21; // почему?)
|
||||
decoded = ByteArrays.getSubArray(decoded, start, end - start);
|
||||
return decoded;
|
||||
}
|
||||
|
||||
private Optional<byte[]> getFinishedData(boolean incoming) {
|
||||
var contentOpt = tlsPackets.asMap().entrySet().stream()
|
||||
.filter(ent -> ent.getKey().isIncoming() == incoming)
|
||||
.map(Map.Entry::getValue)
|
||||
.flatMap(Collection::stream)
|
||||
.filter(p -> p.getContentType() == ContentType.HANDSHAKE)
|
||||
.map(p -> ((HandshakeRecord) p.getRecord()))
|
||||
.filter(r -> r.getHandshakeType() == HandshakeType.ENCRYPTED_HANDSHAKE_MESSAGE)
|
||||
.map(r -> ((BasicHandshakeRecordContent) r.getContent()))
|
||||
.findFirst();
|
||||
|
||||
return contentOpt.map(BasicHandshakeRecordContent::getContent);
|
||||
}
|
||||
|
||||
private Optional<HandshakeRecordContent> getHandshake(HandshakeType handshakeType) {
|
||||
return tlsPackets.values().stream()
|
||||
.filter(p -> p.getContentType() == ContentType.HANDSHAKE)
|
||||
|
||||
Reference in New Issue
Block a user