mirror of
https://github.com/gchq/CyberChef.git
synced 2024-11-16 08:58:30 +01:00
167 lines
4.7 KiB
JavaScript
167 lines
4.7 KiB
JavaScript
|
/**
|
||
|
* @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;
|