mirror of
https://github.com/gchq/CyberChef.git
synced 2024-11-02 14:11:02 +01:00
Added 'Intensive mode' to the Magic operation, where it brute-forces various simple encodings like XOR or bit rotates.
This commit is contained in:
parent
544d78f461
commit
99ade42e9a
@ -267,11 +267,12 @@ const FlowControl = {
|
|||||||
runMagic: async function(state) {
|
runMagic: async function(state) {
|
||||||
const ings = state.opList[state.progress].getIngValues(),
|
const ings = state.opList[state.progress].getIngValues(),
|
||||||
depth = ings[0],
|
depth = ings[0],
|
||||||
extLang = ings[1],
|
intensive = ings[1],
|
||||||
|
extLang = ings[2],
|
||||||
dish = state.dish,
|
dish = state.dish,
|
||||||
currentRecipeConfig = state.opList.map(op => op.getConfig()),
|
currentRecipeConfig = state.opList.map(op => op.getConfig()),
|
||||||
magic = new Magic(dish.get(Dish.ARRAY_BUFFER)),
|
magic = new Magic(dish.get(Dish.ARRAY_BUFFER)),
|
||||||
options = await magic.speculativeExecution(depth, extLang);
|
options = await magic.speculativeExecution(depth, extLang, intensive);
|
||||||
|
|
||||||
let output = `<table
|
let output = `<table
|
||||||
class='table table-hover table-condensed table-bordered'
|
class='table table-hover table-condensed table-bordered'
|
||||||
@ -319,6 +320,10 @@ const FlowControl = {
|
|||||||
});
|
});
|
||||||
|
|
||||||
output += "</table>";
|
output += "</table>";
|
||||||
|
|
||||||
|
if (!options.length) {
|
||||||
|
output = "Nothing of interest could be detected about the input data.\nHave you tried modifying the operation arguments?";
|
||||||
|
}
|
||||||
dish.set(output, Dish.HTML);
|
dish.set(output, Dish.HTML);
|
||||||
return state;
|
return state;
|
||||||
},
|
},
|
||||||
|
@ -83,7 +83,7 @@ import URL_ from "../operations/URL.js";
|
|||||||
const OperationConfig = {
|
const OperationConfig = {
|
||||||
"Magic": {
|
"Magic": {
|
||||||
module: "Default",
|
module: "Default",
|
||||||
description: "Attempts to detect what the input data is and which operations could help to make more sense of it.",
|
description: "The Magic operation attempts to detect various properties of the input data and suggests which operations could help to make more sense of it.<br><br><b>Options</b><br><u>Depth:</u> If an operation appears to match the data, it will be run and the result will be analysed further. This argument controls the maximum number of levels of recursion.<br><br><u>Intensive mode:</u> When this is turned on, various encodings like XOR and bit rotates are brute-forced to attempt to detect valid data underneath. To improve performance, only the first 100 bytes of the data is brute-forced.<br><br><u>Extensive language support:</u> At each stage, the relative byte frequencies of the data will be compared to average frequencies for a number of languages. The default set consists of ~40 of the most commonly used languages on the Internet. The extensive list consists of 284 languages and can result in many languages matching the data if their byte frequencies are similar.",
|
||||||
inputType: "ArrayBuffer",
|
inputType: "ArrayBuffer",
|
||||||
outputType: "html",
|
outputType: "html",
|
||||||
flowControl: true,
|
flowControl: true,
|
||||||
@ -93,6 +93,11 @@ const OperationConfig = {
|
|||||||
type: "number",
|
type: "number",
|
||||||
value: 3
|
value: 3
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Intensive mode",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "Extensive language support",
|
name: "Extensive language support",
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
@ -1146,7 +1151,7 @@ const OperationConfig = {
|
|||||||
args: [],
|
args: [],
|
||||||
patterns: [
|
patterns: [
|
||||||
{
|
{
|
||||||
match: "%[\\da-f]{2}",
|
match: ".*(?:%[\\da-f]{2}.*){4}",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: []
|
args: []
|
||||||
},
|
},
|
||||||
@ -1210,7 +1215,7 @@ const OperationConfig = {
|
|||||||
args: [],
|
args: [],
|
||||||
patterns: [
|
patterns: [
|
||||||
{
|
{
|
||||||
match: "(?:=[\\da-f]{2}|=\\n)(?:[\\x21-\\x3d\\x3f-\\x7e \\t]|=[\\da-f]{2}|=\\n)*$",
|
match: "^[\\x21-\\x3d\\x3f-\\x7e \\t]*(?:=[\\da-f]{2}|=\\r?\\n)(?:[\\x21-\\x3d\\x3f-\\x7e \\t]|=[\\da-f]{2}|=\\r?\\n)*$",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: []
|
args: []
|
||||||
},
|
},
|
||||||
|
@ -167,20 +167,58 @@ class Magic {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate various simple brute-forced encodings of the data (trucated to 100 bytes).
|
||||||
|
*
|
||||||
|
* @returns {Object[]} - The encoded data and an operation config to generate it.
|
||||||
|
*/
|
||||||
|
bruteForce() {
|
||||||
|
const sample = new Uint8Array(this.inputBuffer).slice(0, 100);
|
||||||
|
|
||||||
|
let results = [];
|
||||||
|
|
||||||
|
// 1-byte XOR
|
||||||
|
for (let i = 1; i < 256; i++) {
|
||||||
|
results.push({
|
||||||
|
data: sample.map(b => b ^ i).buffer,
|
||||||
|
conf: {
|
||||||
|
op: "XOR",
|
||||||
|
args: [{"option": "Hex", "string": i.toString(16)}, "Standard", false]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bit rotate
|
||||||
|
for (let i = 1; i < 8; i++) {
|
||||||
|
results.push({
|
||||||
|
data: sample.map(b => (b >> i) | ((b & (Math.pow(2, i) - 1)) << (8 - i))).buffer,
|
||||||
|
conf: {
|
||||||
|
op: "Rotate right",
|
||||||
|
args: [i, false]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Speculatively executes matching operations, recording metadata of each result.
|
* Speculatively executes matching operations, recording metadata of each result.
|
||||||
*
|
*
|
||||||
* @param {number} [depth=0] - How many levels to try to execute
|
* @param {number} [depth=0] - How many levels to try to execute
|
||||||
* @param {boolean} [extLang=false] - Extensive language support (false = only check the most
|
* @param {boolean} [extLang=false] - Extensive language support (false = only check the most
|
||||||
* common Internet languages)
|
* common Internet languages)
|
||||||
|
* @param {boolean} [intensive=false] - Run brute-forcing on each branch (significantly affects
|
||||||
|
* performance)
|
||||||
* @param {Object[]} [recipeConfig=[]] - The recipe configuration up to this point
|
* @param {Object[]} [recipeConfig=[]] - The recipe configuration up to this point
|
||||||
* @returns {Object[]} - A sorted list of the recipes most likely to result in correct decoding
|
* @returns {Object[]} - A sorted list of the recipes most likely to result in correct decoding
|
||||||
*/
|
*/
|
||||||
async speculativeExecution(depth = 0, extLang = false, recipeConfig = []) {
|
async speculativeExecution(depth = 0, extLang = false, intensive = false, recipeConfig = []) {
|
||||||
if (depth < 0) return [];
|
if (depth < 0) return [];
|
||||||
|
|
||||||
// Find any operations that can be run on this data
|
// Find any operations that can be run on this data
|
||||||
const matchingOps = this.findMatchingOps();
|
let matchingOps = this.findMatchingOps();
|
||||||
|
|
||||||
let results = [];
|
let results = [];
|
||||||
|
|
||||||
@ -194,8 +232,8 @@ class Magic {
|
|||||||
matchingOps: matchingOps
|
matchingOps: matchingOps
|
||||||
});
|
});
|
||||||
|
|
||||||
// Execute each of those operations, then recursively call the speculativeExecution() method
|
// Execute each of the matching operations, then recursively call the speculativeExecution()
|
||||||
// on the resulting data, recording the properties of each option.
|
// method on the resulting data, recording the properties of each option.
|
||||||
await Promise.all(matchingOps.map(async op => {
|
await Promise.all(matchingOps.map(async op => {
|
||||||
const dish = new Dish(this.inputBuffer, Dish.ARRAY_BUFFER),
|
const dish = new Dish(this.inputBuffer, Dish.ARRAY_BUFFER),
|
||||||
opConfig = {
|
opConfig = {
|
||||||
@ -209,11 +247,32 @@ class Magic {
|
|||||||
await recipe.execute(dish, 0);
|
await recipe.execute(dish, 0);
|
||||||
|
|
||||||
const magic = new Magic(dish.get(Dish.ARRAY_BUFFER), this.opPatterns),
|
const magic = new Magic(dish.get(Dish.ARRAY_BUFFER), this.opPatterns),
|
||||||
speculativeResults = await magic.speculativeExecution(depth-1, [...recipeConfig, opConfig]);
|
speculativeResults = await magic.speculativeExecution(
|
||||||
|
depth-1, extLang, intensive, [...recipeConfig, opConfig]);
|
||||||
|
|
||||||
results = results.concat(speculativeResults);
|
results = results.concat(speculativeResults);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
if (intensive) {
|
||||||
|
// Run brute forcing of various types on the data and create a new branch for each option
|
||||||
|
const bfEncodings = this.bruteForce();
|
||||||
|
|
||||||
|
await Promise.all(bfEncodings.map(async enc => {
|
||||||
|
const magic = new Magic(enc.data, this.opPatterns),
|
||||||
|
bfResults = await magic.speculativeExecution(
|
||||||
|
depth-1, extLang, false, [...recipeConfig, enc.conf]);
|
||||||
|
|
||||||
|
results = results.concat(bfResults);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prune branches that do not match anything
|
||||||
|
results = results.filter(r =>
|
||||||
|
r.languageScores[0].probability > 0 ||
|
||||||
|
r.fileType ||
|
||||||
|
r.isUTF8 ||
|
||||||
|
r.matchingOps.length);
|
||||||
|
|
||||||
// Return a sorted list of possible recipes along with their properties
|
// Return a sorted list of possible recipes along with their properties
|
||||||
return results.sort((a, b) => {
|
return results.sort((a, b) => {
|
||||||
// Each option is sorted based on its most likely language (lower is better)
|
// Each option is sorted based on its most likely language (lower is better)
|
||||||
|
@ -472,16 +472,16 @@ const FileType = {
|
|||||||
// Must be before Little-endian UTF-16 BOM
|
// Must be before Little-endian UTF-16 BOM
|
||||||
if (buf[0] === 0xFF && buf[1] === 0xFE && buf[2] === 0x00 && buf[3] === 0x00) {
|
if (buf[0] === 0xFF && buf[1] === 0xFE && buf[2] === 0x00 && buf[3] === 0x00) {
|
||||||
return {
|
return {
|
||||||
ext: "",
|
ext: "UTF32LE",
|
||||||
mime: "",
|
mime: "charset/utf32le",
|
||||||
desc: "Little-endian UTF-32 encoded Unicode byte order mark detected."
|
desc: "Little-endian UTF-32 encoded Unicode byte order mark detected."
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf[0] === 0xFF && buf[1] === 0xFE) {
|
if (buf[0] === 0xFF && buf[1] === 0xFE) {
|
||||||
return {
|
return {
|
||||||
ext: "",
|
ext: "UTF16LE",
|
||||||
mime: "",
|
mime: "charset/utf16le",
|
||||||
desc: "Little-endian UTF-16 encoded Unicode byte order mark detected."
|
desc: "Little-endian UTF-16 encoded Unicode byte order mark detected."
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user