diff --git a/src/core/operations/DefangIPAddresses.mjs b/src/core/operations/DefangIPAddresses.mjs index a869f114..9e672912 100644 --- a/src/core/operations/DefangIPAddresses.mjs +++ b/src/core/operations/DefangIPAddresses.mjs @@ -20,11 +20,17 @@ class DefangIPAddresses extends Operation { this.name = "Defang IP Addresses"; this.module = "Default"; - this.description = "Takes a IPv4 or IPv6 address and 'Defangs' it, meaning the IP becomes invalid, removing the risk of accidentally utilising it as an IP address."; + this.description = "Takes a IPv4 or IPv6 address and 'Defangs' it, meaning the IP becomes invalid, removing the risk of accidentally utilising it as an IP address.

When 'Last only' is enabled, only the final separator of each IP is replaced (e.g. 1.2.3.4 becomes 1.2.3[.]4), keeping the address visually closer to its original form while still rendering it invalid."; this.infoURL = "https://isc.sans.edu/forums/diary/Defang+all+the+things/22744/"; this.inputType = "string"; this.outputType = "string"; - this.args = []; + this.args = [ + { + name: "Last only", + type: "boolean", + value: false + } + ]; this.checks = [ { pattern: "^\\s*(([0-9]{1,3}\\.){3}[0-9]{1,3}|([0-9a-f]{4}:){7}[0-9a-f]{4})\\s*$", @@ -44,12 +50,14 @@ class DefangIPAddresses extends Operation { * @returns {string} */ run(input, args) { + const [lastOnly] = args; + input = input.replace(IPV4_REGEX, x => { - return x.replace(/\./g, "[.]"); + return defangSeparators(x, ".", "[.]", lastOnly); }); input = input.replace(IPV6_REGEX, x => { - return x.replace(/:/g, "[:]"); + return defangSeparators(x, ":", "[:]", lastOnly); }); return input; @@ -59,6 +67,26 @@ class DefangIPAddresses extends Operation { export default DefangIPAddresses; +/** + * Replaces a separator character with a defanged token. + * If lastOnly is true, only the final occurrence is replaced. + * + * @param {string} match + * @param {string} sep + * @param {string} token + * @param {boolean} lastOnly + * @returns {string} + */ +function defangSeparators(match, sep, token, lastOnly) { + if (!lastOnly) { + return match.split(sep).join(token); + } + const idx = match.lastIndexOf(sep); + if (idx === -1) return match; + return match.slice(0, idx) + token + match.slice(idx + sep.length); +} + + /** * IPV4 regular expression */ diff --git a/tests/operations/tests/DefangIP.mjs b/tests/operations/tests/DefangIP.mjs index 60005c54..8418f476 100644 --- a/tests/operations/tests/DefangIP.mjs +++ b/tests/operations/tests/DefangIP.mjs @@ -39,5 +39,45 @@ TestRegister.addTests([ args: [], }, ], + }, { + name: "Defang IP: Last only — IPV4", + input: "192.168.1.1", + expectedOutput: "192.168.1[.]1", + recipeConfig: [ + { + op: "Defang IP Addresses", + args: [true], + }, + ], + }, { + name: "Defang IP: Last only — IPV6", + input: "2001:0db8:85a3:0000:0000:8a2e:0370:7343", + expectedOutput: "2001:0db8:85a3:0000:0000:8a2e:0370[:]7343", + recipeConfig: [ + { + op: "Defang IP Addresses", + args: [true], + }, + ], + }, { + name: "Defang IP: Last only — IPV6 shorthand", + input: "2001:db8:3c4d:15::1a2f:1a2b", + expectedOutput: "2001:db8:3c4d:15::1a2f[:]1a2b", + recipeConfig: [ + { + op: "Defang IP Addresses", + args: [true], + }, + ], + }, { + name: "Defang IP: Last only — multiple IPs in text", + input: "From 10.0.0.1 to 192.168.1.254", + expectedOutput: "From 10.0.0[.]1 to 192.168.1[.]254", + recipeConfig: [ + { + op: "Defang IP Addresses", + args: [true], + }, + ], }, ]);