diff --git a/package-lock.json b/package-lock.json index b374df4bc9..70919d14c3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -70,6 +70,7 @@ "lz-string": "^1.5.0", "lz4js": "^0.2.0", "markdown-it": "^14.1.0", + "minusonejs": "^0.4.2", "moment": "^2.30.1", "moment-timezone": "^0.5.45", "ngeohash": "^0.6.3", @@ -1842,6 +1843,11 @@ "lzma.js": "bin/lzma.js" } }, + "node_modules/@bytecodealliance/preview2-shim": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@bytecodealliance/preview2-shim/-/preview2-shim-0.17.4.tgz", + "integrity": "sha512-vRfxQ6ob5wCgXlpVNoeIUHrqJ2+JTcnQASNMpoi3OVPRYA2oUfhMJdWFP0u5JVL9FlC4YKe+QKqerr345B3T4A==" + }, "node_modules/@codemirror/commands": { "version": "6.8.0", "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.8.0.tgz", @@ -13384,6 +13390,14 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/minusonejs": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/minusonejs/-/minusonejs-0.4.2.tgz", + "integrity": "sha512-Uzk5xynwdLwL7c2l1/gooiDR94yI6IlIx2T91lwON8AUsEj3hjvRk/jaQWy71Fychde9bDYN+0buaqvgYfBTtw==", + "dependencies": { + "@bytecodealliance/preview2-shim": "^0.17.4" + } + }, "node_modules/mocha": { "version": "10.3.0", "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.3.0.tgz", diff --git a/package.json b/package.json index 9191ab6f03..133c2f0e1e 100644 --- a/package.json +++ b/package.json @@ -156,6 +156,7 @@ "lz-string": "^1.5.0", "lz4js": "^0.2.0", "markdown-it": "^14.1.0", + "minusonejs": "^0.4.2", "moment": "^2.30.1", "moment-timezone": "^0.5.45", "ngeohash": "^0.6.3", diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 434c8bb619..48a989d4eb 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -493,6 +493,7 @@ { "name": "Forensics", "ops": [ + "Deobfuscate", "Detect File Type", "Scan for Embedded Files", "Extract Files", diff --git a/src/core/operations/Deobfuscate.mjs b/src/core/operations/Deobfuscate.mjs new file mode 100644 index 0000000000..4520e693bc --- /dev/null +++ b/src/core/operations/Deobfuscate.mjs @@ -0,0 +1,54 @@ +/** + * @author dolphinau [me@dawl.fr] + * @copyright Crown Copyright 2025 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; + +import { deobfuscate, getLanguages } from "minusonejs"; + +/** + * Deobfuscate operation + */ +class Deobfuscate extends Operation { + /** + * Deobfuscate constructor + */ + constructor() { + super(); + + this.name = "Deobfuscate"; + this.module = "Obfuscation"; + this.description = + "Deobfuscate input with the minusone engine.
Supported languages:
- Powershell"; + this.infoURL = "https://github.com/airbus-cert/minusone"; // Usually a Wikipedia link. Remember to remove localisation (i.e. https://wikipedia.org/etc rather than https://en.wikipedia.org/etc) + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + name: "Language", + type: "option", + value: getLanguages(), + }, + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + if (!input) return ""; + + const [Language] = args; + const [res, err] = deobfuscate(input, Language); + + if (err) throw new OperationError(`Deobfuscate error: ${err}`); + return res; + } +} + +export default Deobfuscate; diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index f147e9e7c7..d2afa82e7d 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -60,6 +60,7 @@ import "./tests/Crypt.mjs"; import "./tests/CSV.mjs"; import "./tests/DateTime.mjs"; import "./tests/DefangIP.mjs"; +import "./tests/Deobfuscate.mjs"; import "./tests/DropNthBytes.mjs"; import "./tests/ECDSA.mjs"; import "./tests/ELFInfo.mjs"; diff --git a/tests/operations/tests/Deobfuscate.mjs b/tests/operations/tests/Deobfuscate.mjs new file mode 100644 index 0000000000..91cc513882 --- /dev/null +++ b/tests/operations/tests/Deobfuscate.mjs @@ -0,0 +1,33 @@ +/** + * Deobfuscate tests + * + * @author dolphinau [me@dawl.fr] + * @copyright Crown Copyright 2019 + * @license Apache-2.0 + */ +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + name: "Deobfuscate: Powershell empty deobfuscation", + input: "", + expectedOutput: "", + recipeConfig: [ + { + op: "Deobfuscate", + args: ["Powershell"], + }, + ], + }, + { + name: "Deobfuscate: Powershell deobfuscation", + input: "${Pop-pKkAp}=1;${Clear-OK3Emf}=4;${Push-Jh8ps}=9;${Format-qqM9C}=16;${Redo-kSQuo}=86;${Format-LyC}=51;${Pop-ASPJ}=74;${Join-pIuV}=112;${Hide-Rhpet}=100;${Copy-TWaj}=71;${Set-yYE}=85;${Exit-shq}=116;${Skip-5qa}=83;${Push-bAik}=57;${Split-f7hDr6}=122;${Open-YGi}=65;${Open-LPQk}=61;${Select-YUyq}=84;${Move-sS6mJ}=87;${Search-wa0}=108;${Join-YJq}=117;${Hide-iQ5}=88;${Select-iV0F7}=78;${Select-cI9j}=80;${Open-Hec}=98;${Reset-4QePz}=109;${Format-4e7UHy}=103;${Lock-UyaF}=97;${Select-ZGdxB}=77;${Move-FtkTLt}=104;${Push-VUUQsE}=73;${Add-LHgggw}=99;${Reset-sc3}=81;${Format-AlmdYS}=50;${Resize-mYqZ}=121;${Reset-hp9}=66;${Reset-qC3Yd}=48;${Find-6QywvV}=120;${Select-v7sja}=110;${Step-7WvUL}=82;$DJ2=[System.Text.Encoding];$1Ro=[System.Convert];${Step-xE2}=-join'8FTU'[-${Pop-pKkAp}..-${Clear-OK3Emf}];${Unlock-Zdbkvh}=-join'gnirtSteG'[-${Pop-pKkAp}..-${Push-Jh8ps}];${Close-yjy}=-join'gnirtS46esaBmorF'[-${Pop-pKkAp}..-${Format-qqM9C}];. ($DJ2::${Step-xE2}.${Unlock-Zdbkvh}($1Ro::${Close-yjy}(([char]${Redo-kSQuo}+[char]${Format-LyC}+[char]${Pop-ASPJ}+[char]${Join-pIuV}+[char]${Hide-Rhpet}+[char]${Copy-TWaj}+[char]${Set-yYE}+[char]${Exit-shq}+[char]${Skip-5qa}+[char]${Copy-TWaj}+[char]${Push-bAik}+[char]${Split-f7hDr6}+[char]${Hide-Rhpet}+[char]${Open-YGi}+[char]${Open-LPQk}+[char]${Open-LPQk})))) ($DJ2::${Step-xE2}.${Unlock-Zdbkvh}($1Ro::${Close-yjy}(([char]${Select-YUyq}+[char]${Move-sS6mJ}+[char]${Search-wa0}+[char]${Join-YJq}+[char]${Hide-Rhpet}+[char]${Hide-iQ5}+[char]${Select-iV0F7}+[char]${Select-cI9j}+[char]${Open-Hec}+[char]${Reset-4QePz}+[char]${Set-yYE}+[char]${Format-4e7UHy}+[char]${Lock-UyaF}+[char]${Hide-iQ5}+[char]${Select-ZGdxB}+[char]${Format-4e7UHy}+[char]${Hide-Rhpet}+[char]${Copy-TWaj}+[char]${Move-FtkTLt}+[char]${Search-wa0}+[char]${Push-VUUQsE}+[char]${Copy-TWaj}+[char]${Pop-ASPJ}+[char]${Search-wa0}+[char]${Add-LHgggw}+[char]${Format-LyC}+[char]${Reset-sc3}+[char]${Format-4e7UHy}+[char]${Add-LHgggw}+[char]${Format-AlmdYS}+[char]${Select-iV0F7}+[char]${Resize-mYqZ}+[char]${Lock-UyaF}+[char]${Hide-iQ5}+[char]${Reset-hp9}+[char]${Reset-qC3Yd}+[char]${Push-VUUQsE}+[char]${Copy-TWaj}+[char]${Find-6QywvV}+[char]${Join-pIuV}+[char]${Open-Hec}+[char]${Select-v7sja}+[char]${Step-7WvUL}+[char]${Search-wa0}+[char]${Add-LHgggw}+[char]${Format-4e7UHy}+[char]${Open-LPQk}+[char]${Open-LPQk}))))", + expectedOutput: '\n& "write-host" "MinusOne is the best script linter"', + recipeConfig: [ + { + op: "Deobfuscate", + args: ["Powershell"], + }, + ], + }, +]);