From 1719ee84da882f78dbda9ba295ff144b9d2313e0 Mon Sep 17 00:00:00 2001 From: HarelKatz <34490550+HarelKatz@users.noreply.github.com> Date: Fri, 15 May 2026 17:36:35 +0300 Subject: [PATCH] feat: add Fang IP Addresses operation Adds the inverse of "Defang IP Addresses": restores defanged IPv4 and IPv6 addresses (e.g. 192[.]168[.]1[.]1 -> 192.168.1.1, 2001[:]db8[:][:]1 -> 2001:db8::1). Mirrors the pattern of the existing "Fang URL" op, with independent toggles for restoring [.] and [:]. The "Defang IP Addresses" operation already exists; this fills the missing inverse so defanged IPs in IOC lists, threat reports, etc. can be round-tripped through CyberChef. --- src/core/config/Categories.json | 3 +- src/core/operations/FangIPAddresses.mjs | 56 ++++++++++++++ tests/operations/tests/FangIPAddresses.mjs | 88 ++++++++++++++++++++++ 3 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 src/core/operations/FangIPAddresses.mjs create mode 100644 tests/operations/tests/FangIPAddresses.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 2879a13a..2064d9d4 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -286,7 +286,8 @@ "Decode NetBIOS Name", "Defang URL", "Fang URL", - "Defang IP Addresses" + "Defang IP Addresses", + "Fang IP Addresses" ] }, { diff --git a/src/core/operations/FangIPAddresses.mjs b/src/core/operations/FangIPAddresses.mjs new file mode 100644 index 00000000..9ebf498b --- /dev/null +++ b/src/core/operations/FangIPAddresses.mjs @@ -0,0 +1,56 @@ +/** + * @author HarelKatz [github.com/HarelKatz] + * @copyright Crown Copyright 2026 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; + +/** + * Fang IP Addresses operation + */ +class FangIPAddresses extends Operation { + + /** + * FangIPAddresses constructor + */ + constructor() { + super(); + + this.name = "Fang IP Addresses"; + this.module = "Default"; + this.description = "Takes a defanged IPv4 or IPv6 address and 'Fangs' it, restoring it to a valid address. The inverse of Defang IP Addresses.

e.g. 192[.]168[.]1[.]1 becomes 192.168.1.1."; + this.infoURL = "https://isc.sans.edu/forums/diary/Defang+all+the+things/22744/"; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + name: "Restore [.]", + type: "boolean", + value: true + }, + { + name: "Restore [:]", + type: "boolean", + value: true + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const [dots, colons] = args; + + if (dots) input = input.replace(/\[\.\]/g, "."); + if (colons) input = input.replace(/\[:\]/g, ":"); + + return input; + } + +} + +export default FangIPAddresses; diff --git a/tests/operations/tests/FangIPAddresses.mjs b/tests/operations/tests/FangIPAddresses.mjs new file mode 100644 index 00000000..abb46483 --- /dev/null +++ b/tests/operations/tests/FangIPAddresses.mjs @@ -0,0 +1,88 @@ +/** + * Fang IP Addresses tests + * + * @author HarelKatz [github.com/HarelKatz] + * @copyright Crown Copyright 2026 + * @license Apache-2.0 + */ +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + name: "Fang IP: Valid IPV4", + input: "192[.]168[.]1[.]1", + expectedOutput: "192.168.1.1", + recipeConfig: [ + { + op: "Fang IP Addresses", + args: [true, true], + }, + ], + }, + { + name: "Fang IP: Valid IPV6", + input: "2001[:]0db8[:]85a3[:]0000[:]0000[:]8a2e[:]0370[:]7343", + expectedOutput: "2001:0db8:85a3:0000:0000:8a2e:0370:7343", + recipeConfig: [ + { + op: "Fang IP Addresses", + args: [true, true], + }, + ], + }, + { + name: "Fang IP: Valid IPV6 Shorthand", + input: "2001[:]db8[:]3c4d[:]15[:][:]1a2f[:]1a2b", + expectedOutput: "2001:db8:3c4d:15::1a2f:1a2b", + recipeConfig: [ + { + op: "Fang IP Addresses", + args: [true, true], + }, + ], + }, + { + name: "Fang IP: Multiple defanged IPs in surrounding text", + input: "Connect to 10[.]0[.]0[.]1 or 192[.]168[.]1[.]254", + expectedOutput: "Connect to 10.0.0.1 or 192.168.1.254", + recipeConfig: [ + { + op: "Fang IP Addresses", + args: [true, true], + }, + ], + }, + { + name: "Fang IP: Plain IP input is unchanged", + input: "192.168.1.1", + expectedOutput: "192.168.1.1", + recipeConfig: [ + { + op: "Fang IP Addresses", + args: [true, true], + }, + ], + }, + { + name: "Fang IP: Restore dots only", + input: "192[.]168[.]1[.]1 ::[:]1", + expectedOutput: "192.168.1.1 ::[:]1", + recipeConfig: [ + { + op: "Fang IP Addresses", + args: [true, false], + }, + ], + }, + { + name: "Fang IP: Restore colons only", + input: "192[.]168[.]1[.]1 2001[:]db8[:][:]1", + expectedOutput: "192[.]168[.]1[.]1 2001:db8::1", + recipeConfig: [ + { + op: "Fang IP Addresses", + args: [false, true], + }, + ], + }, +]);