mirror of
https://github.com/gchq/CyberChef.git
synced 2025-04-23 16:26:16 -04:00
merge upstream
This commit is contained in:
commit
97255bbb33
27 changed files with 971 additions and 710 deletions
|
@ -159,7 +159,8 @@
|
|||
"Change IP format",
|
||||
"Group IP addresses",
|
||||
"Encode NetBIOS Name",
|
||||
"Decode NetBIOS Name"
|
||||
"Decode NetBIOS Name",
|
||||
"Defang URL"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -167,6 +168,7 @@
|
|||
"ops": [
|
||||
"Encode text",
|
||||
"Decode text",
|
||||
"Remove Diacritics",
|
||||
"Unescape Unicode Characters"
|
||||
]
|
||||
},
|
||||
|
|
|
@ -39,3 +39,21 @@ export function search (input, searchRegex, removeRegex, includeTotal) {
|
|||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* URL regular expression
|
||||
*/
|
||||
const protocol = "[A-Z]+://",
|
||||
hostname = "[-\\w]+(?:\\.\\w[-\\w]*)+",
|
||||
port = ":\\d+",
|
||||
path = "/[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]*" +
|
||||
"(?:[.!,?]+[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]+)*";
|
||||
|
||||
export const URL_REGEX = new RegExp(protocol + hostname + "(?:" + port + ")?(?:" + path + ")?", "ig");
|
||||
|
||||
|
||||
/**
|
||||
* Domain name regular expression
|
||||
*/
|
||||
export const DOMAIN_REGEX = /\b((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}\b/ig;
|
||||
|
|
102
src/core/operations/DefangURL.mjs
Normal file
102
src/core/operations/DefangURL.mjs
Normal file
|
@ -0,0 +1,102 @@
|
|||
/**
|
||||
* @author arnydo [arnydo@protonmail.com]
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import {URL_REGEX, DOMAIN_REGEX} from "../lib/Extract";
|
||||
|
||||
/**
|
||||
* DefangURL operation
|
||||
*/
|
||||
class DefangURL extends Operation {
|
||||
|
||||
/**
|
||||
* DefangURL constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Defang URL";
|
||||
this.module = "Default";
|
||||
this.description = "Takes a Universal Resource Locator (URL) and 'Defangs' it; meaning the URL becomes invalid, neutralising the risk of accidentally clicking on a malicious link.<br><br>This is often used when dealing with malicious links or IOCs.<br><br>Works well when combined with the 'Extract URLs' operation.";
|
||||
this.infoURL = "https://isc.sans.edu/forums/diary/Defang+all+the+things/22744/";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Escape dots",
|
||||
type: "boolean",
|
||||
value: true
|
||||
},
|
||||
{
|
||||
name: "Escape http",
|
||||
type: "boolean",
|
||||
value: true
|
||||
},
|
||||
{
|
||||
name: "Escape ://",
|
||||
type: "boolean",
|
||||
value: true
|
||||
},
|
||||
{
|
||||
name: "Process",
|
||||
type: "option",
|
||||
value: ["Valid domains and full URLs", "Only full URLs", "Everything"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [dots, http, slashes, process] = args;
|
||||
|
||||
switch (process) {
|
||||
case "Valid domains and full URLs":
|
||||
input = input.replace(URL_REGEX, x => {
|
||||
return defangURL(x, dots, http, slashes);
|
||||
});
|
||||
input = input.replace(DOMAIN_REGEX, x => {
|
||||
return defangURL(x, dots, http, slashes);
|
||||
});
|
||||
break;
|
||||
case "Only full URLs":
|
||||
input = input.replace(URL_REGEX, x => {
|
||||
return defangURL(x, dots, http, slashes);
|
||||
});
|
||||
break;
|
||||
case "Everything":
|
||||
input = defangURL(input, dots, http, slashes);
|
||||
break;
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Defangs a given URL
|
||||
*
|
||||
* @param {string} url
|
||||
* @param {boolean} dots
|
||||
* @param {boolean} http
|
||||
* @param {boolean} slashes
|
||||
* @returns {string}
|
||||
*/
|
||||
function defangURL(url, dots, http, slashes) {
|
||||
if (dots) url = url.replace(/\./g, "[.]");
|
||||
if (http) url = url.replace(/http/gi, "hxxp");
|
||||
if (slashes) url = url.replace(/:\/\//g, "[://]");
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
export default DefangURL;
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import { search } from "../lib/Extract";
|
||||
import { search, DOMAIN_REGEX } from "../lib/Extract";
|
||||
|
||||
/**
|
||||
* Extract domains operation
|
||||
|
@ -38,10 +38,8 @@ class ExtractDomains extends Operation {
|
|||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const displayTotal = args[0],
|
||||
regex = /\b((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}\b/ig;
|
||||
|
||||
return search(input, regex, null, displayTotal);
|
||||
const displayTotal = args[0];
|
||||
return search(input, DOMAIN_REGEX, null, displayTotal);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import { search } from "../lib/Extract";
|
||||
import { search, URL_REGEX } from "../lib/Extract";
|
||||
|
||||
/**
|
||||
* Extract URLs operation
|
||||
|
@ -38,16 +38,8 @@ class ExtractURLs extends Operation {
|
|||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const displayTotal = args[0],
|
||||
protocol = "[A-Z]+://",
|
||||
hostname = "[-\\w]+(?:\\.\\w[-\\w]*)+",
|
||||
port = ":\\d+";
|
||||
let path = "/[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]*";
|
||||
|
||||
path += "(?:[.!,?]+[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]+)*";
|
||||
const regex = new RegExp(protocol + hostname + "(?:" + port +
|
||||
")?(?:" + path + ")?", "ig");
|
||||
return search(input, regex, null, displayTotal);
|
||||
const displayTotal = args[0];
|
||||
return search(input, URL_REGEX, null, displayTotal);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -71,6 +71,11 @@ class FromBase58 extends Operation {
|
|||
|
||||
if (input.length === 0) return [];
|
||||
|
||||
let zeroPrefix = 0;
|
||||
for (let i = 0; i < input.length && input[i] === alphabet[0]; i++) {
|
||||
zeroPrefix++;
|
||||
}
|
||||
|
||||
[].forEach.call(input, function(c, charIndex) {
|
||||
const index = alphabet.indexOf(c);
|
||||
|
||||
|
@ -98,6 +103,10 @@ class FromBase58 extends Operation {
|
|||
}
|
||||
});
|
||||
|
||||
while (zeroPrefix--) {
|
||||
result.push(0);
|
||||
}
|
||||
|
||||
return result.reverse();
|
||||
}
|
||||
|
||||
|
|
|
@ -29,38 +29,43 @@ class FromDecimal extends Operation {
|
|||
"name": "Delimiter",
|
||||
"type": "option",
|
||||
"value": DELIM_OPTIONS
|
||||
},
|
||||
{
|
||||
"name": "Support signed values",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
this.patterns = [
|
||||
{
|
||||
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?: (?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||
flags: "",
|
||||
args: ["Space"]
|
||||
args: ["Space", false]
|
||||
},
|
||||
{
|
||||
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:,(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||
flags: "",
|
||||
args: ["Comma"]
|
||||
args: ["Comma", false]
|
||||
},
|
||||
{
|
||||
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:;(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||
flags: "",
|
||||
args: ["Semi-colon"]
|
||||
args: ["Semi-colon", false]
|
||||
},
|
||||
{
|
||||
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?::(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||
flags: "",
|
||||
args: ["Colon"]
|
||||
args: ["Colon", false]
|
||||
},
|
||||
{
|
||||
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:\\n(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||
flags: "",
|
||||
args: ["Line feed"]
|
||||
args: ["Line feed", false]
|
||||
},
|
||||
{
|
||||
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:\\r\\n(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||
flags: "",
|
||||
args: ["CRLF"]
|
||||
args: ["CRLF", false]
|
||||
},
|
||||
];
|
||||
}
|
||||
|
@ -71,7 +76,11 @@ class FromDecimal extends Operation {
|
|||
* @returns {byteArray}
|
||||
*/
|
||||
run(input, args) {
|
||||
return fromDecimal(input, args[0]);
|
||||
let data = fromDecimal(input, args[0]);
|
||||
if (args[1]) { // Convert negatives
|
||||
data = data.map(v => v < 0 ? 0xFF + v + 1 : v);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,8 +28,9 @@ class HMAC extends Operation {
|
|||
this.args = [
|
||||
{
|
||||
"name": "Key",
|
||||
"type": "binaryString",
|
||||
"value": ""
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["Hex", "Decimal", "Base64", "UTF8", "Latin1"]
|
||||
},
|
||||
{
|
||||
"name": "Hashing function",
|
||||
|
@ -66,18 +67,11 @@ class HMAC extends Operation {
|
|||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const key = args[0],
|
||||
const key = Utils.convertToByteString(args[0].string || "", args[0].option),
|
||||
hashFunc = args[1].toLowerCase(),
|
||||
msg = Utils.arrayBufferToStr(input, false),
|
||||
hasher = CryptoApi.getHasher(hashFunc);
|
||||
|
||||
// Horrible shim to fix constructor bug. Reported in nf404/crypto-api#8
|
||||
hasher.reset = () => {
|
||||
hasher.state = {};
|
||||
const tmp = new hasher.constructor();
|
||||
hasher.state = tmp.state;
|
||||
};
|
||||
|
||||
const mac = CryptoApi.getHmac(CryptoApi.encoder.fromUtf(key), hasher);
|
||||
mac.update(msg);
|
||||
return CryptoApi.encoder.toHex(mac.finalize());
|
||||
|
|
|
@ -227,6 +227,7 @@ function regexList (input, regex, displayTotal, matches, captureGroups) {
|
|||
*/
|
||||
function regexHighlight (input, regex, displayTotal) {
|
||||
let output = "",
|
||||
title = "",
|
||||
m,
|
||||
hl = 1,
|
||||
i = 0,
|
||||
|
@ -241,8 +242,16 @@ function regexHighlight (input, regex, displayTotal) {
|
|||
// Add up to match
|
||||
output += Utils.escapeHtml(input.slice(i, m.index));
|
||||
|
||||
title = `Offset: ${m.index}\n`;
|
||||
if (m.length > 1) {
|
||||
title += "Groups:\n";
|
||||
for (let n = 1; n < m.length; ++n) {
|
||||
title += `\t${n}: ${m[n]}\n`;
|
||||
}
|
||||
}
|
||||
|
||||
// Add match with highlighting
|
||||
output += "<span class='hl"+hl+"'>" + Utils.escapeHtml(m[0]) + "</span>";
|
||||
output += "<span class='hl"+hl+"' title='"+title+"'>" + Utils.escapeHtml(m[0]) + "</span>";
|
||||
|
||||
// Switch highlight
|
||||
hl = hl === 1 ? 2 : 1;
|
||||
|
|
41
src/core/operations/RemoveDiacritics.mjs
Normal file
41
src/core/operations/RemoveDiacritics.mjs
Normal file
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* @author Klaxon [klaxon@veyr.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
|
||||
/**
|
||||
* Remove Diacritics operation
|
||||
*/
|
||||
class RemoveDiacritics extends Operation {
|
||||
|
||||
/**
|
||||
* RemoveDiacritics constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Remove Diacritics";
|
||||
this.module = "Default";
|
||||
this.description = "Replaces accented characters with their latin character equivalent.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Diacritic";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
// reference: https://stackoverflow.com/questions/990904/remove-accents-diacritics-in-a-string-in-javascript/37511463
|
||||
return input.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default RemoveDiacritics;
|
|
@ -62,7 +62,7 @@ class Scrypt extends Operation {
|
|||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const salt = Utils.convertToByteString(args[0].string || "", args[0].option),
|
||||
const salt = Buffer.from(Utils.convertToByteArray(args[0].string || "", args[0].option)),
|
||||
iterations = args[1],
|
||||
memFactor = args[2],
|
||||
parallelFactor = args[3],
|
||||
|
|
|
@ -38,7 +38,7 @@ class Sort extends Operation {
|
|||
{
|
||||
"name": "Order",
|
||||
"type": "option",
|
||||
"value": ["Alphabetical (case sensitive)", "Alphabetical (case insensitive)", "IP address", "Numeric"]
|
||||
"value": ["Alphabetical (case sensitive)", "Alphabetical (case insensitive)", "IP address", "Numeric", "Numeric (hexadecimal)"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
@ -62,6 +62,8 @@ class Sort extends Operation {
|
|||
sorted = sorted.sort(Sort._ipSort);
|
||||
} else if (order === "Numeric") {
|
||||
sorted = sorted.sort(Sort._numericSort);
|
||||
} else if (order === "Numeric (hexadecimal)") {
|
||||
sorted = sorted.sort(Sort._hexadecimalSort);
|
||||
}
|
||||
|
||||
if (sortReverse) sorted.reverse();
|
||||
|
@ -131,6 +133,44 @@ class Sort extends Operation {
|
|||
return a.localeCompare(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparison operation for sorting of hexadecimal values.
|
||||
*
|
||||
* @author Chris van Marle
|
||||
* @private
|
||||
* @param {string} a
|
||||
* @param {string} b
|
||||
* @returns {number}
|
||||
*/
|
||||
static _hexadecimalSort(a, b) {
|
||||
let a_ = a.split(/([^\da-f]+)/i),
|
||||
b_ = b.split(/([^\da-f]+)/i);
|
||||
|
||||
a_ = a_.map(v => {
|
||||
const t = parseInt(v, 16);
|
||||
return isNaN(t) ? v : t;
|
||||
});
|
||||
|
||||
b_ = b_.map(v => {
|
||||
const t = parseInt(v, 16);
|
||||
return isNaN(t) ? v : t;
|
||||
});
|
||||
|
||||
for (let i = 0; i < a_.length && i < b.length; ++i) {
|
||||
if (isNaN(a_[i]) && !isNaN(b_[i])) return 1; // Numbers after non-numbers
|
||||
if (!isNaN(a_[i]) && isNaN(b_[i])) return -1;
|
||||
if (isNaN(a_[i]) && isNaN(b_[i])) {
|
||||
const ret = a_[i].localeCompare(b_[i]); // Compare strings
|
||||
if (ret !== 0) return ret;
|
||||
}
|
||||
if (!isNaN(a_[i]) && !isNaN(a_[i])) { // Compare numbers
|
||||
if (a_[i] - b_[i] !== 0) return a_[i] - b_[i];
|
||||
}
|
||||
}
|
||||
|
||||
return a.localeCompare(b);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Sort;
|
||||
|
|
|
@ -53,6 +53,11 @@ class ToBase58 extends Operation {
|
|||
|
||||
if (input.length === 0) return "";
|
||||
|
||||
let zeroPrefix = 0;
|
||||
for (let i = 0; i < input.length && input[i] === 0; i++) {
|
||||
zeroPrefix++;
|
||||
}
|
||||
|
||||
input.forEach(function(b) {
|
||||
let carry = (result[0] << 8) + b;
|
||||
result[0] = carry % 58;
|
||||
|
@ -74,7 +79,7 @@ class ToBase58 extends Operation {
|
|||
return alphabet[b];
|
||||
}).reverse().join("");
|
||||
|
||||
while (result.length < input.length) {
|
||||
while (zeroPrefix--) {
|
||||
result = alphabet[0] + result;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,11 @@ class ToDecimal extends Operation {
|
|||
"name": "Delimiter",
|
||||
"type": "option",
|
||||
"value": DELIM_OPTIONS
|
||||
},
|
||||
{
|
||||
"name": "Support signed values",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
@ -40,7 +45,11 @@ class ToDecimal extends Operation {
|
|||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const delim = Utils.charRep(args[0]);
|
||||
const delim = Utils.charRep(args[0]),
|
||||
signed = args[1];
|
||||
if (signed) {
|
||||
input = input.map(v => v > 0x7F ? v - 0xFF - 1 : v);
|
||||
}
|
||||
return input.join(delim);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue