瀏覽代碼

Added HASSH operations

n1474335 4 年之前
父節點
當前提交
e9ca4dc9ca

+ 2 - 0
src/core/config/Categories.json

@@ -195,6 +195,8 @@
             "VarInt Decode",
             "JA3 Fingerprint",
             "JA3S Fingerprint",
+            "HASSH Client Fingerprint",
+            "HASSH Server Fingerprint",
             "Format MAC addresses",
             "Change IP format",
             "Group IP addresses",

+ 166 - 0
src/core/operations/HASSHClientFingerprint.mjs

@@ -0,0 +1,166 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2021
+ * @license Apache-2.0
+ *
+ * HASSH created by Salesforce
+ *   Ben Reardon (@benreardon)
+ *   Adel Karimi (@0x4d31)
+ *   and the JA3 crew:
+ *     John B. Althouse
+ *     Jeff Atkinson
+ *     Josh Atkins
+ *
+ * Algorithm released under the BSD-3-clause licence
+ */
+
+import Operation from "../Operation.mjs";
+import OperationError from "../errors/OperationError.mjs";
+import Utils from "../Utils.mjs";
+import Stream from "../lib/Stream.mjs";
+import {runHash} from "../lib/Hash.mjs";
+
+/**
+ * HASSH Client Fingerprint operation
+ */
+class HASSHClientFingerprint extends Operation {
+
+    /**
+     * HASSHClientFingerprint constructor
+     */
+    constructor() {
+        super();
+
+        this.name = "HASSH Client Fingerprint";
+        this.module = "Crypto";
+        this.description = "Generates a HASSH fingerprint to help identify SSH clients based on hashing together values from the Client Key Exchange Init message.<br><br>Input: A hex stream of the SSH_MSG_KEXINIT packet application layer from Client to Server.";
+        this.infoURL = "https://engineering.salesforce.com/open-sourcing-hassh-abed3ae5044c";
+        this.inputType = "string";
+        this.outputType = "string";
+        this.args = [
+            {
+                name: "Input format",
+                type: "option",
+                value: ["Hex", "Base64", "Raw"]
+            },
+            {
+                name: "Output format",
+                type: "option",
+                value: ["Hash digest", "HASSH algorithms string", "Full details"]
+            }
+        ];
+    }
+
+    /**
+     * @param {string} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    run(input, args) {
+        const [inputFormat, outputFormat] = args;
+
+        input = Utils.convertToByteArray(input, inputFormat);
+        const s = new Stream(new Uint8Array(input));
+
+        // Length
+        const length = s.readInt(4);
+        if (s.length !== length + 4)
+            throw new OperationError("Incorrect packet length.");
+
+        // Padding length
+        const paddingLength = s.readInt(1);
+
+        // Message code
+        const messageCode = s.readInt(1);
+        if (messageCode !== 20)
+            throw new OperationError("Not a Key Exchange Init.");
+
+        // Cookie
+        s.moveForwardsBy(16);
+
+        // KEX Algorithms
+        const kexAlgosLength = s.readInt(4);
+        const kexAlgos = s.readString(kexAlgosLength);
+
+        // Server Host Key Algorithms
+        const serverHostKeyAlgosLength = s.readInt(4);
+        s.moveForwardsBy(serverHostKeyAlgosLength);
+
+        // Encryption Algorithms Client to Server
+        const encAlgosC2SLength = s.readInt(4);
+        const encAlgosC2S = s.readString(encAlgosC2SLength);
+
+        // Encryption Algorithms Server to Client
+        const encAlgosS2CLength = s.readInt(4);
+        s.moveForwardsBy(encAlgosS2CLength);
+
+        // MAC Algorithms Client to Server
+        const macAlgosC2SLength = s.readInt(4);
+        const macAlgosC2S = s.readString(macAlgosC2SLength);
+
+        // MAC Algorithms Server to Client
+        const macAlgosS2CLength = s.readInt(4);
+        s.moveForwardsBy(macAlgosS2CLength);
+
+        // Compression Algorithms Client to Server
+        const compAlgosC2SLength = s.readInt(4);
+        const compAlgosC2S = s.readString(compAlgosC2SLength);
+
+        // Compression Algorithms Server to Client
+        const compAlgosS2CLength = s.readInt(4);
+        s.moveForwardsBy(compAlgosS2CLength);
+
+        // Languages Client to Server
+        const langsC2SLength = s.readInt(4);
+        s.moveForwardsBy(langsC2SLength);
+
+        // Languages Server to Client
+        const langsS2CLength = s.readInt(4);
+        s.moveForwardsBy(langsS2CLength);
+
+        // First KEX packet follows
+        s.moveForwardsBy(1);
+
+        // Reserved
+        s.moveForwardsBy(4);
+
+        // Padding string
+        s.moveForwardsBy(paddingLength);
+
+        // Output
+        const hassh = [
+            kexAlgos,
+            encAlgosC2S,
+            macAlgosC2S,
+            compAlgosC2S
+        ];
+        const hasshStr = hassh.join(";");
+        const hasshHash = runHash("md5", Utils.strToArrayBuffer(hasshStr));
+
+        switch (outputFormat) {
+            case "HASSH algorithms string":
+                return hasshStr;
+            case "Full details":
+                return `Hash digest:
+${hasshHash}
+
+Full HASSH algorithms string:
+${hasshStr}
+
+Key Exchange Algorithms:
+${kexAlgos}
+Encryption Algorithms Client to Server:
+${encAlgosC2S}
+MAC Algorithms Client to Server:
+${macAlgosC2S}
+Compression Algorithms Client to Server:
+${compAlgosC2S}`;
+            case "Hash digest":
+            default:
+                return hasshHash;
+        }
+    }
+
+}
+
+export default HASSHClientFingerprint;

+ 166 - 0
src/core/operations/HASSHServerFingerprint.mjs

@@ -0,0 +1,166 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2021
+ * @license Apache-2.0
+ *
+ * HASSH created by Salesforce
+ *   Ben Reardon (@benreardon)
+ *   Adel Karimi (@0x4d31)
+ *   and the JA3 crew:
+ *     John B. Althouse
+ *     Jeff Atkinson
+ *     Josh Atkins
+ *
+ * Algorithm released under the BSD-3-clause licence
+*/
+
+import Operation from "../Operation.mjs";
+import OperationError from "../errors/OperationError.mjs";
+import Utils from "../Utils.mjs";
+import Stream from "../lib/Stream.mjs";
+import {runHash} from "../lib/Hash.mjs";
+
+/**
+ * HASSH Server Fingerprint operation
+ */
+class HASSHServerFingerprint extends Operation {
+
+    /**
+     * HASSHServerFingerprint constructor
+     */
+    constructor() {
+        super();
+
+        this.name = "HASSH Server Fingerprint";
+        this.module = "Crypto";
+        this.description = "Generates a HASSH fingerprint to help identify SSH servers based on hashing together values from the Server Key Exchange Init message.<br><br>Input: A hex stream of the SSH_MSG_KEXINIT packet application layer from Server to Client.";
+        this.infoURL = "https://engineering.salesforce.com/open-sourcing-hassh-abed3ae5044c";
+        this.inputType = "string";
+        this.outputType = "string";
+        this.args = [
+            {
+                name: "Input format",
+                type: "option",
+                value: ["Hex", "Base64", "Raw"]
+            },
+            {
+                name: "Output format",
+                type: "option",
+                value: ["Hash digest", "HASSH algorithms string", "Full details"]
+            }
+        ];
+    }
+
+    /**
+     * @param {string} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    run(input, args) {
+        const [inputFormat, outputFormat] = args;
+
+        input = Utils.convertToByteArray(input, inputFormat);
+        const s = new Stream(new Uint8Array(input));
+
+        // Length
+        const length = s.readInt(4);
+        if (s.length !== length + 4)
+            throw new OperationError("Incorrect packet length.");
+
+        // Padding length
+        const paddingLength = s.readInt(1);
+
+        // Message code
+        const messageCode = s.readInt(1);
+        if (messageCode !== 20)
+            throw new OperationError("Not a Key Exchange Init.");
+
+        // Cookie
+        s.moveForwardsBy(16);
+
+        // KEX Algorithms
+        const kexAlgosLength = s.readInt(4);
+        const kexAlgos = s.readString(kexAlgosLength);
+
+        // Server Host Key Algorithms
+        const serverHostKeyAlgosLength = s.readInt(4);
+        s.moveForwardsBy(serverHostKeyAlgosLength);
+
+        // Encryption Algorithms Client to Server
+        const encAlgosC2SLength = s.readInt(4);
+        s.moveForwardsBy(encAlgosC2SLength);
+
+        // Encryption Algorithms Server to Client
+        const encAlgosS2CLength = s.readInt(4);
+        const encAlgosS2C = s.readString(encAlgosS2CLength);
+
+        // MAC Algorithms Client to Server
+        const macAlgosC2SLength = s.readInt(4);
+        s.moveForwardsBy(macAlgosC2SLength);
+
+        // MAC Algorithms Server to Client
+        const macAlgosS2CLength = s.readInt(4);
+        const macAlgosS2C = s.readString(macAlgosS2CLength);
+
+        // Compression Algorithms Client to Server
+        const compAlgosC2SLength = s.readInt(4);
+        s.moveForwardsBy(compAlgosC2SLength);
+
+        // Compression Algorithms Server to Client
+        const compAlgosS2CLength = s.readInt(4);
+        const compAlgosS2C = s.readString(compAlgosS2CLength);
+
+        // Languages Client to Server
+        const langsC2SLength = s.readInt(4);
+        s.moveForwardsBy(langsC2SLength);
+
+        // Languages Server to Client
+        const langsS2CLength = s.readInt(4);
+        s.moveForwardsBy(langsS2CLength);
+
+        // First KEX packet follows
+        s.moveForwardsBy(1);
+
+        // Reserved
+        s.moveForwardsBy(4);
+
+        // Padding string
+        s.moveForwardsBy(paddingLength);
+
+        // Output
+        const hassh = [
+            kexAlgos,
+            encAlgosS2C,
+            macAlgosS2C,
+            compAlgosS2C
+        ];
+        const hasshStr = hassh.join(";");
+        const hasshHash = runHash("md5", Utils.strToArrayBuffer(hasshStr));
+
+        switch (outputFormat) {
+            case "HASSH algorithms string":
+                return hasshStr;
+            case "Full details":
+                return `Hash digest:
+${hasshHash}
+
+Full HASSH algorithms string:
+${hasshStr}
+
+Key Exchange Algorithms:
+${kexAlgos}
+Encryption Algorithms Server to Client:
+${encAlgosS2C}
+MAC Algorithms Server to Client:
+${macAlgosS2C}
+Compression Algorithms Server to Client:
+${compAlgosS2C}`;
+            case "Hash digest":
+            default:
+                return hasshHash;
+        }
+    }
+
+}
+
+export default HASSHServerFingerprint;

+ 1 - 1
src/core/operations/JA3Fingerprint.mjs

@@ -30,7 +30,7 @@ class JA3Fingerprint extends Operation {
 
         this.name = "JA3 Fingerprint";
         this.module = "Crypto";
-        this.description = "Generates a JA3 fingerprint to help identify TLS clients based on hashing together values from the Client Hello.<br><br>Input: A hex stream of the TLS Client Hello application layer.";
+        this.description = "Generates a JA3 fingerprint to help identify TLS clients based on hashing together values from the Client Hello.<br><br>Input: A hex stream of the TLS Client Hello packet application layer.";
         this.infoURL = "https://engineering.salesforce.com/tls-fingerprinting-with-ja3-and-ja3s-247362855967";
         this.inputType = "string";
         this.outputType = "string";

+ 1 - 1
src/core/operations/JA3SFingerprint.mjs

@@ -30,7 +30,7 @@ class JA3SFingerprint extends Operation {
 
         this.name = "JA3S Fingerprint";
         this.module = "Crypto";
-        this.description = "Generates a JA3S fingerprint to help identify TLS servers based on hashing together values from the Server Hello.<br><br>Input: A hex stream of the TLS Server Hello record in the application layer.";
+        this.description = "Generates a JA3S fingerprint to help identify TLS servers based on hashing together values from the Server Hello.<br><br>Input: A hex stream of the TLS Server Hello record application layer.";
         this.infoURL = "https://engineering.salesforce.com/tls-fingerprinting-with-ja3-and-ja3s-247362855967";
         this.inputType = "string";
         this.outputType = "string";

+ 2 - 0
tests/operations/index.mjs

@@ -105,6 +105,8 @@ import "./tests/RSA.mjs";
 import "./tests/CBOREncode.mjs";
 import "./tests/CBORDecode.mjs";
 import "./tests/JA3Fingerprint.mjs";
+import "./tests/JA3SFingerprint.mjs";
+import "./tests/HASSH.mjs";
 
 
 // Cannot test operations that use the File type yet

+ 33 - 0
tests/operations/tests/HASSH.mjs

@@ -0,0 +1,33 @@
+/**
+ * HASSH tests.
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2021
+ * @license Apache-2.0
+ */
+import TestRegister from "../../lib/TestRegister.mjs";
+
+TestRegister.addTests([
+    {
+        name: "HASSH Client Fingerprint",
+        input: "000003140814c639665f5425dcb80bf9f0a048380a410000007e6469666669652d68656c6c6d616e2d67726f75702d65786368616e67652d7368613235362c6469666669652d68656c6c6d616e2d67726f75702d65786368616e67652d736861312c6469666669652d68656c6c6d616e2d67726f757031342d736861312c6469666669652d68656c6c6d616e2d67726f7570312d736861310000000f7373682d7273612c7373682d6473730000009d6165733132382d6374722c6165733139322d6374722c6165733235362d6374722c617263666f75723235362c617263666f75723132382c6165733132382d6362632c336465732d6362632c626c6f77666973682d6362632c636173743132382d6362632c6165733139322d6362632c6165733235362d6362632c617263666f75722c72696a6e6461656c2d636263406c797361746f722e6c69752e73650000009d6165733132382d6374722c6165733139322d6374722c6165733235362d6374722c617263666f75723235362c617263666f75723132382c6165733132382d6362632c336465732d6362632c626c6f77666973682d6362632c636173743132382d6362632c6165733139322d6362632c6165733235362d6362632c617263666f75722c72696a6e6461656c2d636263406c797361746f722e6c69752e736500000069686d61632d6d64352c686d61632d736861312c756d61632d3634406f70656e7373682e636f6d2c686d61632d726970656d643136302c686d61632d726970656d64313630406f70656e7373682e636f6d2c686d61632d736861312d39362c686d61632d6d64352d393600000069686d61632d6d64352c686d61632d736861312c756d61632d3634406f70656e7373682e636f6d2c686d61632d726970656d643136302c686d61632d726970656d64313630406f70656e7373682e636f6d2c686d61632d736861312d39362c686d61632d6d64352d39360000001a6e6f6e652c7a6c6962406f70656e7373682e636f6d2c7a6c69620000001a6e6f6e652c7a6c6962406f70656e7373682e636f6d2c7a6c6962000000000000000000000000000000000000000000",
+        expectedOutput: "21b457a327ce7a2d4fce5ef2c42400bd",
+        recipeConfig: [
+            {
+                "op": "HASSH Client Fingerprint",
+                "args": ["Hex", "Hash digest"]
+            }
+        ],
+    },
+    {
+        name: "HASSH Server Fingerprint",
+        input: "0000027c0b142c7bb93a1da21c9e54f5862e60a5597c000000596469666669652d68656c6c6d616e2d67726f75702d65786368616e67652d736861312c6469666669652d68656c6c6d616e2d67726f757031342d736861312c6469666669652d68656c6c6d616e2d67726f7570312d736861310000000f7373682d7273612c7373682d647373000000876165733132382d6362632c336465732d6362632c626c6f77666973682d6362632c636173743132382d6362632c617263666f75722c6165733139322d6362632c6165733235362d6362632c72696a6e6461656c2d636263406c797361746f722e6c69752e73652c6165733132382d6374722c6165733139322d6374722c6165733235362d637472000000876165733132382d6362632c336465732d6362632c626c6f77666973682d6362632c636173743132382d6362632c617263666f75722c6165733139322d6362632c6165733235362d6362632c72696a6e6461656c2d636263406c797361746f722e6c69752e73652c6165733132382d6374722c6165733139322d6374722c6165733235362d63747200000055686d61632d6d64352c686d61632d736861312c686d61632d726970656d643136302c686d61632d726970656d64313630406f70656e7373682e636f6d2c686d61632d736861312d39362c686d61632d6d64352d393600000055686d61632d6d64352c686d61632d736861312c686d61632d726970656d643136302c686d61632d726970656d64313630406f70656e7373682e636f6d2c686d61632d736861312d39362c686d61632d6d64352d3936000000096e6f6e652c7a6c6962000000096e6f6e652c7a6c6962000000000000000000000000000000000000000000000000",
+        expectedOutput: "f430cd6761697a6a658ee1d45ed22e49",
+        recipeConfig: [
+            {
+                "op": "HASSH Server Fingerprint",
+                "args": ["Hex", "Hash digest"]
+            }
+        ],
+    }
+]);

+ 13 - 11
tests/operations/tests/JA3SFingerprint.mjs

@@ -41,15 +41,17 @@ TestRegister.addTests([
             }
         ],
     },
-    {
-        name: "JA3S Fingerprint: TLS 1.3",
-        input: "16030100520200004e7f123ef1609fd3f4fa8668aac5822d500fb0639b22671d0fb7258597355795511bf61301002800280024001d0020ae0e282a3b7a463e71064ecbaf671586e979b0edbebf7a4735c31678c70f660c",
-        expectedOutput: "986ae432c402479fe7a0c6fbe02164c1",
-        recipeConfig: [
-            {
-                "op": "JA3S Fingerprint",
-                "args": ["Hex", "Hash digest"]
-            }
-        ],
-    },
+    // This Server Hello was based on draft 18 of the TLS1.3 spec which does not include a Session ID field, leading it to fail.
+    // The published version of TLS1.3 does require a legacy Session ID field (even if it is empty).
+    // {
+    //     name: "JA3S Fingerprint: TLS 1.3",
+    //     input: "16030100520200004e7f123ef1609fd3f4fa8668aac5822d500fb0639b22671d0fb7258597355795511bf61301002800280024001d0020ae0e282a3b7a463e71064ecbaf671586e979b0edbebf7a4735c31678c70f660c",
+    //     expectedOutput: "986ae432c402479fe7a0c6fbe02164c1",
+    //     recipeConfig: [
+    //         {
+    //             "op": "JA3S Fingerprint",
+    //             "args": ["Hex", "Hash digest"]
+    //         }
+    //     ],
+    // },
 ]);