Merge a2adf40bf8fdef36ba696478df70b7adeae59b17 into 4290ea753912378913b1f3f54e0fc5720afeda5d

This commit is contained in:
Collin Laney 2026-08-07 09:51:37 +12:00 committed by GitHub
commit dccb475f65
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 376 additions and 1 deletions

View File

@ -300,7 +300,10 @@
"Decode NetBIOS Name", "Decode NetBIOS Name",
"Defang URL", "Defang URL",
"Fang URL", "Fang URL",
"Defang IP Addresses" "Defang IP Addresses",
"Fang IP Addresses",
"Defang email addresses",
"Fang email addresses"
] ]
}, },
{ {

View File

@ -0,0 +1,85 @@
/**
* @author Collin Laney [collin.laney@coldogstudios.com]
* @copyright Crown Copyright 2026
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import {EMAIL_REGEX} from "../lib/Extract.mjs";
/**
* Defang email addresses operation
*/
class DefangEmailAddresses extends Operation {
/**
* DefangEmailAddresses constructor
*/
constructor() {
super();
this.name = "Defang email addresses";
this.module = "Default";
this.description = "Takes email addresses and 'Defangs' them, meaning the addresses become invalid, removing the risk of accidentally using them as email links or indicators.";
this.infoURL = "https://isc.sans.edu/forums/diary/Defang+all+the+things/22744/";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "Escape @",
type: "boolean",
value: true
},
{
name: "Escape dots",
type: "boolean",
value: true
},
{
name: "Process",
type: "option",
value: ["Valid email addresses", "Everything"]
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [at, dots, process] = args;
switch (process) {
case "Valid email addresses":
input = input.replace(EMAIL_REGEX, x => {
return defangEmailAddress(x, at, dots);
});
break;
case "Everything":
input = defangEmailAddress(input, at, dots);
break;
}
return input;
}
}
/**
* Defangs a given email address
*
* @param {string} email
* @param {boolean} at
* @param {boolean} dots
* @returns {string}
*/
function defangEmailAddress(email, at, dots) {
if (at) email = email.replace(/@/g, "[@]");
if (dots) email = email.replace(/\./g, "[.]");
return email;
}
export default DefangEmailAddresses;

View File

@ -0,0 +1,68 @@
/**
* @author Collin Laney [collin.laney@coldogstudios.com]
* @copyright Crown Copyright 2026
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
/**
* Fang email addresses operation
*/
class FangEmailAddresses extends Operation {
/**
* FangEmailAddresses constructor
*/
constructor() {
super();
this.name = "Fang email addresses";
this.module = "Default";
this.description = "Takes 'Defanged' email addresses and 'Fangs' them, restoring the alterations that made them invalid.";
this.infoURL = "https://isc.sans.edu/forums/diary/Defang+all+the+things/22744/";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "Restore [@] and [at]",
type: "boolean",
value: true
},
{
name: "Restore [.]",
type: "boolean",
value: true
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [at, dots] = args;
return fangEmailAddress(input, at, dots);
}
}
/**
* Fangs a given email address
*
* @param {string} email
* @param {boolean} at
* @param {boolean} dots
* @returns {string}
*/
function fangEmailAddress(email, at, dots) {
if (at) email = email.replace(/\[@\]|\[at\]/gi, "@");
if (dots) email = email.replace(/\[\.\]/g, ".");
return email;
}
export default FangEmailAddresses;

View File

@ -0,0 +1,72 @@
/**
* @author Collin Laney [collin.laney@coldogstudios.com]
* @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 'Defanged' IPv4 or IPv6 addresses and 'Fangs' them, restoring the alterations that made them invalid.";
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;
input = input.replace(DEFANGED_IPV4_REGEX, x => {
return dots ? x.replace(/\[\.\]/g, ".") : x;
});
input = input.replace(DEFANGED_IPV6_REGEX, x => {
return colons ? x.replace(/\[:\]/g, ":") : x;
});
return input;
}
}
export default FangIPAddresses;
/**
* Defanged IPv4 regular expression
*/
const DEFANGED_IPV4_REGEX = new RegExp("(?:(?:\\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})?", "g");
/**
* Defanged IPv6 regular expression
*/
const DEFANGED_IPV6_REGEX = new RegExp("(?:[\\dA-Fa-f]{0,4}\\[:\\]){2,7}[\\dA-Fa-f]{0,4}(?:\\/\\d{1,3})?", "g");

View File

@ -0,0 +1,43 @@
/**
* Defang email address tests.
*
* @copyright Crown Copyright 2026
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
name: "Defang email addresses: valid email address",
input: "Contact security@example.com for details.",
expectedOutput: "Contact security[@]example[.]com for details.",
recipeConfig: [
{
op: "Defang email addresses",
args: [true, true, "Valid email addresses"],
},
],
},
{
name: "Defang email addresses: multiple addresses",
input: "one@example.com firstname.lastname@example.co.uk",
expectedOutput: "one[@]example[.]com firstname[.]lastname[@]example[.]co[.]uk",
recipeConfig: [
{
op: "Defang email addresses",
args: [true, true, "Valid email addresses"],
},
],
},
{
name: "Defang email addresses: everything",
input: "Use @ and . anywhere",
expectedOutput: "Use [@] and [.] anywhere",
recipeConfig: [
{
op: "Defang email addresses",
args: [true, true, "Everything"],
},
],
},
]);

View File

@ -0,0 +1,43 @@
/**
* Fang email address tests.
*
* @copyright Crown Copyright 2026
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
name: "Fang email addresses: defanged email address",
input: "Contact security[@]example[.]com for details.",
expectedOutput: "Contact security@example.com for details.",
recipeConfig: [
{
op: "Fang email addresses",
args: [true, true],
},
],
},
{
name: "Fang email addresses: defanged with [at]",
input: "Contact security[at]example[.]com for details.",
expectedOutput: "Contact security@example.com for details.",
recipeConfig: [
{
op: "Fang email addresses",
args: [true, true],
},
],
},
{
name: "Fang email addresses: restore at only",
input: "firstname[.]lastname[@]example[.]com",
expectedOutput: "firstname[.]lastname@example[.]com",
recipeConfig: [
{
op: "Fang email addresses",
args: [true, false],
},
],
},
]);

View File

@ -0,0 +1,61 @@
/**
* Fang IP address tests.
*
* @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 IPV4 CIDR",
input: "10[.]0[.]0[.]0/24",
expectedOutput: "10.0.0.0/24",
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: Does not fang defanged domain",
input: "example[.]com",
expectedOutput: "example[.]com",
recipeConfig: [
{
op: "Fang IP Addresses",
args: [true, true],
},
],
},
]);