diff --git a/.gitignore b/.gitignore index 3b7449c4..42923f5d 100755 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ npm-debug.log travis.log build .vscode +.idea .*.swp src/core/config/modules/* src/core/config/OperationConfig.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 93944764..2d845a56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,12 @@ All major and minor version changes will be documented in this file. Details of ## Details +### [10.6.0] - 2024-02-03 +- Updated 'Forensics Wiki' URLs to new domain [@a3957273] | [#1703] +- Added 'LZNT1 Decompress' operation [@0xThiebaut] | [#1675] +- Updated 'Regex Expression' UUID matcher [@cnotin] | [#1678] +- Removed duplicate 'hover' message within baking info [@KevinSJ] | [#1541] + ### [10.5.0] - 2023-07-14 - Added GOST Encrypt, Decrypt, Sign, Verify, Key Wrap, and Key Unwrap operations [@n1474335] | [#592] @@ -373,7 +379,7 @@ All major and minor version changes will be documented in this file. Details of - Initial open source commit [@n1474335] | [b1d73a72](https://github.com/gchq/CyberChef/commit/b1d73a725dc7ab9fb7eb789296efd2b7e4b08306) - +[10.6.0]: https://github.com/gchq/CyberChef/releases/tag/v10.6.0 [10.5.0]: https://github.com/gchq/CyberChef/releases/tag/v10.5.0 [10.4.0]: https://github.com/gchq/CyberChef/releases/tag/v10.4.0 [10.3.0]: https://github.com/gchq/CyberChef/releases/tag/v10.3.0 @@ -528,6 +534,10 @@ All major and minor version changes will be documented in this file. Details of [@joostrijneveld]: https://github.com/joostrijneveld [@Xenonym]: https://github.com/Xenonym [@gchq77703]: https://github.com/gchq77703 +[@a3957273]: https://github.com/a3957273 +[@0xThiebaut]: https://github.com/0xThiebaut +[@cnotin]: https://github.com/cnotin +[@KevinSJ]: https://github.com/KevinSJ [8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7 [9a33498]: https://github.com/gchq/CyberChef/commit/9a33498fed26a8df9c9f35f39a78a174bf50a513 @@ -646,4 +656,7 @@ All major and minor version changes will be documented in this file. Details of [#661]: https://github.com/gchq/CyberChef/pull/661 [#493]: https://github.com/gchq/CyberChef/pull/493 [#592]: https://github.com/gchq/CyberChef/issues/592 - +[#1703]: https://github.com/gchq/CyberChef/issues/1703 +[#1675]: https://github.com/gchq/CyberChef/issues/1675 +[#1678]: https://github.com/gchq/CyberChef/issues/1678 +[#1541]: https://github.com/gchq/CyberChef/issues/1541 diff --git a/README.md b/README.md index 18e535ca..24f56e77 100755 --- a/README.md +++ b/README.md @@ -89,14 +89,14 @@ CyberChef is built to support ## Node.js support -CyberChef is built to fully support Node.js `v16`. For more information, see the Node API page in the project [wiki pages](https://github.com/gchq/CyberChef/wiki) +CyberChef is built to fully support Node.js `v16`. For more information, see the ["Node API" wiki page](https://github.com/gchq/CyberChef/wiki/Node-API) ## Contributing Contributing a new operation to CyberChef is super easy! The quickstart script will walk you through the process. If you can write basic JavaScript, you can write a CyberChef operation. -An installation walkthrough, how-to guides for adding new operations and themes, descriptions of the repository structure, available data types and coding conventions can all be found in the project [wiki pages](https://github.com/gchq/CyberChef/wiki). +An installation walkthrough, how-to guides for adding new operations and themes, descriptions of the repository structure, available data types and coding conventions can all be found in the ["Contributing" wiki page](https://github.com/gchq/CyberChef/wiki/Contributing). - Push your changes to your fork. - Submit a pull request. If you are doing this for the first time, you will be prompted to sign the [GCHQ Contributor Licence Agreement](https://cla-assistant.io/gchq/CyberChef) via the CLA assistant on the pull request. This will also ask whether you are happy for GCHQ to contact you about a token of thanks for your contribution, or about job opportunities at GCHQ. diff --git a/package-lock.json b/package-lock.json index 3cccfa6c..ae8e5889 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cyberchef", - "version": "10.5.2", + "version": "10.6.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cyberchef", - "version": "10.5.2", + "version": "10.6.0", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -112,7 +112,7 @@ "babel-plugin-dynamic-import-node": "^2.3.3", "babel-plugin-transform-builtin-extend": "1.1.2", "base64-loader": "^1.0.0", - "chromedriver": "^114.0.2", + "chromedriver": "^121.0.0", "cli-progress": "^3.12.0", "colors": "^1.4.0", "copy-webpack-plugin": "^11.0.0", @@ -2622,9 +2622,9 @@ "license": "BSD-3-Clause" }, "node_modules/@testim/chrome-version": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@testim/chrome-version/-/chrome-version-1.1.3.tgz", - "integrity": "sha512-g697J3WxV/Zytemz8aTuKjTGYtta9+02kva3C1xc7KXB8GdbfE1akGJIsZLyY/FSh2QrnE+fiB7vmWU3XNcb6A==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@testim/chrome-version/-/chrome-version-1.1.4.tgz", + "integrity": "sha512-kIhULpw9TrGYnHp/8VfdcneIcxKnLixmADtukQRtJUmsVlMg0niMkwV0xZmi8hqa57xqilIHjWFA0GKvEjVU5g==", "dev": true }, "node_modules/@tokenizer/token": { @@ -3347,12 +3347,12 @@ } }, "node_modules/axios": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", - "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", + "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", "dev": true, "dependencies": { - "follow-redirects": "^1.15.0", + "follow-redirects": "^1.15.4", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } @@ -4265,9 +4265,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001439", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz", - "integrity": "sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A==", + "version": "1.0.30001583", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001583.tgz", + "integrity": "sha512-acWTYaha8xfhA/Du/z4sNZjHUWjkiuoAi2LM+T/aL+kemKQgPT1xBb/YKjlQ0Qo8gvbHsGNplrEJ+9G3gL7i4Q==", "dev": true, "funding": [ { @@ -4277,6 +4277,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ] }, @@ -4375,25 +4379,25 @@ } }, "node_modules/chromedriver": { - "version": "114.0.2", - "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-114.0.2.tgz", - "integrity": "sha512-v0qrXRBknbxqmtklG7RWOe3TJ/dLaHhtB0jVxE7BAdYERxUjEaNRyqBwoGgVfQDibHCB0swzvzsj158nnfPgZw==", + "version": "121.0.0", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-121.0.0.tgz", + "integrity": "sha512-ZIKEdZrQAfuzT/RRofjl8/EZR99ghbdBXNTOcgJMKGP6N/UL6lHUX4n6ONWBV18pDvDFfQJ0x58h5AdOaXIOMw==", "dev": true, "hasInstallScript": true, "dependencies": { - "@testim/chrome-version": "^1.1.3", - "axios": "^1.4.0", - "compare-versions": "^5.0.3", + "@testim/chrome-version": "^1.1.4", + "axios": "^1.6.5", + "compare-versions": "^6.1.0", "extract-zip": "^2.0.1", "https-proxy-agent": "^5.0.1", "proxy-from-env": "^1.1.0", - "tcp-port-used": "^1.0.1" + "tcp-port-used": "^1.0.2" }, "bin": { "chromedriver": "bin/chromedriver" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/ci-info": { @@ -4564,9 +4568,9 @@ "license": "MIT" }, "node_modules/compare-versions": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-5.0.3.tgz", - "integrity": "sha512-4UZlZP8Z99MGEY+Ovg/uJxJuvoXuN4M6B3hKaiackiHrgzQFEe3diJi1mf1PNHbFujM7FvLrK2bpgIaImbtZ1A==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.0.tgz", + "integrity": "sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==", "dev": true }, "node_modules/compressible": { @@ -6793,9 +6797,9 @@ "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", "dev": true, "funding": [ { @@ -15605,9 +15609,9 @@ "version": "1.1.0" }, "@testim/chrome-version": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@testim/chrome-version/-/chrome-version-1.1.3.tgz", - "integrity": "sha512-g697J3WxV/Zytemz8aTuKjTGYtta9+02kva3C1xc7KXB8GdbfE1akGJIsZLyY/FSh2QrnE+fiB7vmWU3XNcb6A==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@testim/chrome-version/-/chrome-version-1.1.4.tgz", + "integrity": "sha512-kIhULpw9TrGYnHp/8VfdcneIcxKnLixmADtukQRtJUmsVlMg0niMkwV0xZmi8hqa57xqilIHjWFA0GKvEjVU5g==", "dev": true }, "@tokenizer/token": { @@ -16157,12 +16161,12 @@ "dev": true }, "axios": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", - "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", + "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", "dev": true, "requires": { - "follow-redirects": "^1.15.0", + "follow-redirects": "^1.15.4", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } @@ -16780,9 +16784,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001439", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz", - "integrity": "sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A==", + "version": "1.0.30001583", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001583.tgz", + "integrity": "sha512-acWTYaha8xfhA/Du/z4sNZjHUWjkiuoAi2LM+T/aL+kemKQgPT1xBb/YKjlQ0Qo8gvbHsGNplrEJ+9G3gL7i4Q==", "dev": true }, "cbor": { @@ -16846,18 +16850,18 @@ "dev": true }, "chromedriver": { - "version": "114.0.2", - "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-114.0.2.tgz", - "integrity": "sha512-v0qrXRBknbxqmtklG7RWOe3TJ/dLaHhtB0jVxE7BAdYERxUjEaNRyqBwoGgVfQDibHCB0swzvzsj158nnfPgZw==", + "version": "121.0.0", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-121.0.0.tgz", + "integrity": "sha512-ZIKEdZrQAfuzT/RRofjl8/EZR99ghbdBXNTOcgJMKGP6N/UL6lHUX4n6ONWBV18pDvDFfQJ0x58h5AdOaXIOMw==", "dev": true, "requires": { - "@testim/chrome-version": "^1.1.3", - "axios": "^1.4.0", - "compare-versions": "^5.0.3", + "@testim/chrome-version": "^1.1.4", + "axios": "^1.6.5", + "compare-versions": "^6.1.0", "extract-zip": "^2.0.1", "https-proxy-agent": "^5.0.1", "proxy-from-env": "^1.1.0", - "tcp-port-used": "^1.0.1" + "tcp-port-used": "^1.0.2" } }, "ci-info": { @@ -16972,9 +16976,9 @@ "dev": true }, "compare-versions": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-5.0.3.tgz", - "integrity": "sha512-4UZlZP8Z99MGEY+Ovg/uJxJuvoXuN4M6B3hKaiackiHrgzQFEe3diJi1mf1PNHbFujM7FvLrK2bpgIaImbtZ1A==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.0.tgz", + "integrity": "sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==", "dev": true }, "compressible": { @@ -18490,9 +18494,9 @@ "version": "3.2.5" }, "follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", "dev": true }, "for-in": { diff --git a/package.json b/package.json index 45328dd1..55b65312 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "10.5.2", + "version": "10.6.0", "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.", "author": "n1474335 ", "homepage": "https://gchq.github.io/CyberChef", @@ -55,7 +55,7 @@ "babel-plugin-dynamic-import-node": "^2.3.3", "babel-plugin-transform-builtin-extend": "1.1.2", "base64-loader": "^1.0.0", - "chromedriver": "^114.0.2", + "chromedriver": "^121.0.0", "cli-progress": "^3.12.0", "colors": "^1.4.0", "copy-webpack-plugin": "^11.0.0", diff --git a/src/core/Utils.mjs b/src/core/Utils.mjs index 787ef270..18b0e688 100755 --- a/src/core/Utils.mjs +++ b/src/core/Utils.mjs @@ -892,6 +892,23 @@ class Utils { } + /** + * Converts a string to it's title case equivalent. + * + * @param {string} str + * @returns string + * + * @example + * // return "A Tiny String" + * Utils.toTitleCase("a tIny String"); + */ + static toTitleCase(str) { + return str.replace(/\w\S*/g, function(txt) { + return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); + }); + } + + /** * Encodes a URI fragment (#) or query (?) using a minimal amount of percent-encoding. * diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index b76b93ac..0f9f9c8d 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -352,7 +352,8 @@ "LZMA Decompress", "LZMA Compress", "LZ4 Decompress", - "LZ4 Compress" + "LZ4 Compress", + "LZNT1 Decompress" ] }, { diff --git a/src/core/lib/LZNT1.mjs b/src/core/lib/LZNT1.mjs new file mode 100644 index 00000000..9a1c7fab --- /dev/null +++ b/src/core/lib/LZNT1.mjs @@ -0,0 +1,88 @@ +/** + * + * LZNT1 Decompress. + * + * @author 0xThiebaut [thiebaut.dev] + * @copyright Crown Copyright 2023 + * @license Apache-2.0 + * + * https://github.com/Velocidex/go-ntfs/blob/master/parser%2Flznt1.go + */ + +import Utils from "../Utils.mjs"; +import OperationError from "../errors/OperationError.mjs"; + +const COMPRESSED_MASK = 1 << 15, + SIZE_MASK = (1 << 12) - 1; + +/** + * @param {number} offset + * @returns {number} + */ +function getDisplacement(offset) { + let result = 0; + while (offset >= 0x10) { + offset >>= 1; + result += 1; + } + return result; +} + +/** + * @param {byteArray} compressed + * @returns {byteArray} + */ +export function decompress(compressed) { + const decompressed = Array(); + let coffset = 0; + + while (coffset + 2 <= compressed.length) { + const doffset = decompressed.length; + + const blockHeader = Utils.byteArrayToInt(compressed.slice(coffset, coffset + 2), "little"); + coffset += 2; + + const size = blockHeader & SIZE_MASK; + const blockEnd = coffset + size + 1; + + if (size === 0) { + break; + } else if (compressed.length < coffset + size) { + throw new OperationError("Malformed LZNT1 stream: Block too small! Has the stream been truncated?"); + } + + if ((blockHeader & COMPRESSED_MASK) !== 0) { + while (coffset < blockEnd) { + let header = compressed[coffset++]; + + for (let i = 0; i < 8 && coffset < blockEnd; i++) { + if ((header & 1) === 0) { + decompressed.push(compressed[coffset++]); + } else { + const pointer = Utils.byteArrayToInt(compressed.slice(coffset, coffset + 2), "little"); + coffset += 2; + + const displacement = getDisplacement(decompressed.length - doffset - 1); + const symbolOffset = (pointer >> (12 - displacement)) + 1; + const symbolLength = (pointer & (0xFFF >> displacement)) + 2; + const shiftOffset = decompressed.length - symbolOffset; + + for (let shiftDelta = 0; shiftDelta < symbolLength + 1; shiftDelta++) { + const shift = shiftOffset + shiftDelta; + if (shift < 0 || decompressed.length <= shift) { + throw new OperationError("Malformed LZNT1 stream: Invalid shift!"); + } + decompressed.push(decompressed[shift]); + } + } + header >>= 1; + } + } + } else { + decompressed.push(...compressed.slice(coffset, coffset + size + 1)); + coffset += size + 1; + } + } + + return decompressed; +} diff --git a/src/core/operations/CTPH.mjs b/src/core/operations/CTPH.mjs index 7394faaa..6b6a487d 100644 --- a/src/core/operations/CTPH.mjs +++ b/src/core/operations/CTPH.mjs @@ -21,7 +21,7 @@ class CTPH extends Operation { this.name = "CTPH"; this.module = "Crypto"; this.description = "Context Triggered Piecewise Hashing, also called Fuzzy Hashing, can match inputs that have homologies. Such inputs have sequences of identical bytes in the same order, although bytes in between these sequences may be different in both content and length.

CTPH was originally based on the work of Dr. Andrew Tridgell and a spam email detector called SpamSum. This method was adapted by Jesse Kornblum and published at the DFRWS conference in 2006 in a paper 'Identifying Almost Identical Files Using Context Triggered Piecewise Hashing'."; - this.infoURL = "https://forensicswiki.xyz/wiki/index.php?title=Context_Triggered_Piecewise_Hashing"; + this.infoURL = "https://forensics.wiki/context_triggered_piecewise_hashing/"; this.inputType = "string"; this.outputType = "string"; this.args = []; diff --git a/src/core/operations/CompareCTPHHashes.mjs b/src/core/operations/CompareCTPHHashes.mjs index 40fec472..91956220 100644 --- a/src/core/operations/CompareCTPHHashes.mjs +++ b/src/core/operations/CompareCTPHHashes.mjs @@ -24,7 +24,7 @@ class CompareCTPHHashes extends Operation { this.name = "Compare CTPH hashes"; this.module = "Crypto"; this.description = "Compares two Context Triggered Piecewise Hashing (CTPH) fuzzy hashes to determine the similarity between them on a scale of 0 to 100."; - this.infoURL = "https://forensicswiki.xyz/wiki/index.php?title=Context_Triggered_Piecewise_Hashing"; + this.infoURL = "https://forensics.wiki/context_triggered_piecewise_hashing/"; this.inputType = "string"; this.outputType = "Number"; this.args = [ diff --git a/src/core/operations/CompareSSDEEPHashes.mjs b/src/core/operations/CompareSSDEEPHashes.mjs index 806b048e..9937d7e6 100644 --- a/src/core/operations/CompareSSDEEPHashes.mjs +++ b/src/core/operations/CompareSSDEEPHashes.mjs @@ -24,7 +24,7 @@ class CompareSSDEEPHashes extends Operation { this.name = "Compare SSDEEP hashes"; this.module = "Crypto"; this.description = "Compares two SSDEEP fuzzy hashes to determine the similarity between them on a scale of 0 to 100."; - this.infoURL = "https://forensicswiki.xyz/wiki/index.php?title=Ssdeep"; + this.infoURL = "https://forensics.wiki/ssdeep/"; this.inputType = "string"; this.outputType = "Number"; this.args = [ diff --git a/src/core/operations/ExtractFiles.mjs b/src/core/operations/ExtractFiles.mjs index 4c6fd1df..3ff8ffb6 100644 --- a/src/core/operations/ExtractFiles.mjs +++ b/src/core/operations/ExtractFiles.mjs @@ -39,7 +39,7 @@ class ExtractFiles extends Operation { ${supportedExts.join("
  • ")}
  • Minimum File Size can be used to prune small false positives.`; - this.infoURL = "https://forensicswiki.xyz/wiki/index.php?title=File_Carving"; + this.infoURL = "https://forensics.wiki/file_carving"; this.inputType = "ArrayBuffer"; this.outputType = "List"; this.presentType = "html"; diff --git a/src/core/operations/ExtractIPAddresses.mjs b/src/core/operations/ExtractIPAddresses.mjs index 95e0a50f..97b52478 100644 --- a/src/core/operations/ExtractIPAddresses.mjs +++ b/src/core/operations/ExtractIPAddresses.mjs @@ -66,7 +66,7 @@ class ExtractIPAddresses extends Operation { run(input, args) { const [includeIpv4, includeIpv6, removeLocal, displayTotal, sort, unique] = args, ipv4 = "(?:(?:\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d|\\d)(?:\\/\\d{1,2})?", - ipv6 = "((?=.*::)(?!.*::.+::)(::)?([\\dA-F]{1,4}:(:|\\b)|){5}|([\\dA-F]{1,4}:){6})((([\\dA-F]{1,4}((?!\\3)::|:\\b|(?![\\dA-F])))|(?!\\2\\3)){2}|(((2[0-4]|1\\d|[1-9])?\\d|25[0-5])\\.?\\b){4})"; + ipv6 = "((?=.*::)(?!.*::.+::)(::)?([\\dA-F]{1,4}:(:|\\b)|){5}|([\\dA-F]{1,4}:){6})(([\\dA-F]{1,4}((?!\\3)::|:\\b|(?![\\dA-F])))|(?!\\2\\3)){2}"; let ips = ""; if (includeIpv4 && includeIpv6) { diff --git a/src/core/operations/LZNT1Decompress.mjs b/src/core/operations/LZNT1Decompress.mjs new file mode 100644 index 00000000..b5308e77 --- /dev/null +++ b/src/core/operations/LZNT1Decompress.mjs @@ -0,0 +1,41 @@ +/** + * @author 0xThiebaut [thiebaut.dev] + * @copyright Crown Copyright 2023 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import {decompress} from "../lib/LZNT1.mjs"; + +/** + * LZNT1 Decompress operation + */ +class LZNT1Decompress extends Operation { + + /** + * LZNT1 Decompress constructor + */ + constructor() { + super(); + + this.name = "LZNT1 Decompress"; + this.module = "Compression"; + this.description = "Decompresses data using the LZNT1 algorithm.

    Similar to the Windows API RtlDecompressBuffer."; + this.infoURL = "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-xca/5655f4a3-6ba4-489b-959f-e1f407c52f15"; + this.inputType = "byteArray"; + this.outputType = "byteArray"; + this.args = []; + } + + /** + * @param {byteArray} input + * @param {Object[]} args + * @returns {byteArray} + */ + run(input, args) { + return decompress(input); + } + +} + +export default LZNT1Decompress; diff --git a/src/core/operations/ParseASN1HexString.mjs b/src/core/operations/ParseASN1HexString.mjs index 14890186..35fd5ba4 100644 --- a/src/core/operations/ParseASN1HexString.mjs +++ b/src/core/operations/ParseASN1HexString.mjs @@ -20,7 +20,7 @@ class ParseASN1HexString extends Operation { this.name = "Parse ASN.1 hex string"; this.module = "PublicKey"; - this.description = "Abstract Syntax Notation One (ASN.1) is a standard and notation that describes rules and structures for representing, encoding, transmitting, and decoding data in telecommunications and computer networking.

    This operation parses arbitrary ASN.1 data and presents the resulting tree."; + this.description = "Abstract Syntax Notation One (ASN.1) is a standard and notation that describes rules and structures for representing, encoding, transmitting, and decoding data in telecommunications and computer networking.

    This operation parses arbitrary ASN.1 data (encoded as an hex string: use the 'To Hex' operation if necessary) and presents the resulting tree."; this.infoURL = "https://wikipedia.org/wiki/Abstract_Syntax_Notation_One"; this.inputType = "string"; this.outputType = "string"; diff --git a/src/core/operations/RegularExpression.mjs b/src/core/operations/RegularExpression.mjs index 1d8de9c4..18d3fda9 100644 --- a/src/core/operations/RegularExpression.mjs +++ b/src/core/operations/RegularExpression.mjs @@ -83,6 +83,10 @@ class RegularExpression extends Operation { name: "Strings", value: "[A-Za-z\\d/\\-:.,_$%\\x27\"()<>= !\\[\\]{}@]{4,}" }, + { + name: "UUID (any version)", + value: "[0-9a-fA-F]{8}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{12}" + }, ], "target": 1 }, diff --git a/src/core/operations/SSDEEP.mjs b/src/core/operations/SSDEEP.mjs index df1557d5..6a76a68b 100644 --- a/src/core/operations/SSDEEP.mjs +++ b/src/core/operations/SSDEEP.mjs @@ -21,7 +21,7 @@ class SSDEEP extends Operation { this.name = "SSDEEP"; this.module = "Crypto"; this.description = "SSDEEP is a program for computing context triggered piecewise hashes (CTPH). Also called fuzzy hashes, CTPH can match inputs that have homologies. Such inputs have sequences of identical bytes in the same order, although bytes in between these sequences may be different in both content and length.

    SSDEEP hashes are now widely used for simple identification purposes (e.g. the 'Basic Properties' section in VirusTotal). Although 'better' fuzzy hashes are available, SSDEEP is still one of the primary choices because of its speed and being a de facto standard.

    This operation is fundamentally the same as the CTPH operation, however their outputs differ in format."; - this.infoURL = "https://forensicswiki.xyz/wiki/index.php?title=Ssdeep"; + this.infoURL = "https://forensics.wiki/ssdeep"; this.inputType = "string"; this.outputType = "string"; this.args = []; diff --git a/src/web/HTMLOperation.mjs b/src/web/HTMLOperation.mjs index d0523aa4..ae61b58d 100755 --- a/src/web/HTMLOperation.mjs +++ b/src/web/HTMLOperation.mjs @@ -157,9 +157,9 @@ function titleFromWikiLink(urlStr) { pageTitle = ""; switch (urlObj.host) { - case "forensicswiki.xyz": + case "forensics.wiki": wikiName = "Forensics Wiki"; - pageTitle = urlObj.query.substr(6).replace(/_/g, " "); // Chop off 'title=' + pageTitle = Utils.toTitleCase(urlObj.path.replace(/\//g, "").replace(/_/g, " ")); break; case "wikipedia.org": wikiName = "Wikipedia"; diff --git a/src/web/html/index.html b/src/web/html/index.html index c602c275..5c3c3263 100755 --- a/src/web/html/index.html +++ b/src/web/html/index.html @@ -62,7 +62,8 @@ "Training branch predictor...", "Timing cache hits...", "Speculatively executing recipes...", - "Adding LLM hallucinations..." + "Adding LLM hallucinations...", + "Decompressing malware..." ]; // Shuffle array using Durstenfeld algorithm diff --git a/src/web/utils/statusBar.mjs b/src/web/utils/statusBar.mjs index 81728cd9..6469379a 100644 --- a/src/web/utils/statusBar.mjs +++ b/src/web/utils/statusBar.mjs @@ -275,7 +275,6 @@ class StatusBarPanel { bakingTime.textContent = this.timing.duration(this.tabNumGetter()); const info = this.timing.printStages(this.tabNumGetter()).replace(/\n/g, "
    "); - bakingTimeInfo.setAttribute("title", info); bakingTimeInfo.setAttribute("data-original-title", info); } else { bakingTimeInfo.style.display = "none"; diff --git a/tests/node/tests/operations.mjs b/tests/node/tests/operations.mjs index 8611ecb4..86dbee50 100644 --- a/tests/node/tests/operations.mjs +++ b/tests/node/tests/operations.mjs @@ -635,6 +635,10 @@ WWFkYSBZYWRh\r assert.strictEqual(chef.keccak("Flea Market").toString(), "c2a06880b19e453ee5440e8bd4c2024bedc15a6630096aa3f609acfd2b8f15f27cd293e1cc73933e81432269129ce954a6138889ce87831179d55dcff1cc7587"); }), + it("LZNT1 Decompress", () => { + assert.strictEqual(chef.LZNT1Decompress("\x1a\xb0\x00compress\x00edtestda\x04ta\x07\x88alot").toString(), "compressedtestdatacompressedalot"); + }), + it("MD6", () => { assert.strictEqual(chef.MD6("Head Over Heels", {key: "arty"}).toString(), "d8f7fe4931fbaa37316f76283d5f615f50ddd54afdc794b61da522556aee99ad"); }), diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index 570fbb6f..e61f542d 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -62,6 +62,7 @@ import "./tests/JSONtoCSV.mjs"; import "./tests/JWTDecode.mjs"; import "./tests/JWTSign.mjs"; import "./tests/JWTVerify.mjs"; +import "./tests/LZNT1Decompress.mjs"; import "./tests/MS.mjs"; import "./tests/Magic.mjs"; import "./tests/MorseCode.mjs"; diff --git a/tests/operations/tests/LZNT1Decompress.mjs b/tests/operations/tests/LZNT1Decompress.mjs new file mode 100644 index 00000000..dcfad01a --- /dev/null +++ b/tests/operations/tests/LZNT1Decompress.mjs @@ -0,0 +1,22 @@ +/** + * LZNT1 Decompress tests. + * + * @author 0xThiebaut [thiebaut.dev] + * @copyright Crown Copyright 2023 + * @license Apache-2.0 + */ +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + name: "LZNT1 Decompress", + input: "\x1a\xb0\x00compress\x00edtestda\x04ta\x07\x88alot", + expectedOutput: "compressedtestdatacompressedalot", + recipeConfig: [ + { + op: "LZNT1 Decompress", + args: [] + } + ], + } +]);