Browse Source

Merge pull request #2 from gchq/master

update
bwhitn 7 năm trước cách đây
mục cha
commit
caae0ec5ca

+ 1 - 1
package-lock.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "cyberchef",
   "name": "cyberchef",
-  "version": "6.4.6",
+  "version": "6.5.0",
   "lockfileVersion": 1,
   "lockfileVersion": 1,
   "requires": true,
   "requires": true,
   "dependencies": {
   "dependencies": {

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "cyberchef",
   "name": "cyberchef",
-  "version": "6.4.6",
+  "version": "6.5.0",
   "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
   "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
   "author": "n1474335 <n1474335@gmail.com>",
   "author": "n1474335 <n1474335@gmail.com>",
   "homepage": "https://gchq.github.io/CyberChef",
   "homepage": "https://gchq.github.io/CyberChef",

+ 1 - 0
src/core/config/Categories.js

@@ -288,6 +288,7 @@ const Categories = [
             "XPath expression",
             "XPath expression",
             "JPath expression",
             "JPath expression",
             "CSS selector",
             "CSS selector",
+            "PHP Deserialize",
             "Microsoft Script Decoder",
             "Microsoft Script Decoder",
             "Strip HTML tags",
             "Strip HTML tags",
             "Diff",
             "Diff",

+ 14 - 0
src/core/config/OperationConfig.js

@@ -26,6 +26,7 @@ import JS from "../operations/JS.js";
 import MAC from "../operations/MAC.js";
 import MAC from "../operations/MAC.js";
 import MorseCode from "../operations/MorseCode.js";
 import MorseCode from "../operations/MorseCode.js";
 import NetBIOS from "../operations/NetBIOS.js";
 import NetBIOS from "../operations/NetBIOS.js";
+import PHP from "../operations/PHP.js";
 import PublicKey from "../operations/PublicKey.js";
 import PublicKey from "../operations/PublicKey.js";
 import Punycode from "../operations/Punycode.js";
 import Punycode from "../operations/Punycode.js";
 import Rotate from "../operations/Rotate.js";
 import Rotate from "../operations/Rotate.js";
@@ -3845,6 +3846,19 @@ const OperationConfig = {
             }
             }
         ]
         ]
     },
     },
+    "PHP Deserialize": {
+        module: "Default",
+        description: "Deserializes PHP serialized data, outputting keyed arrays as JSON.<br><br>This function does not support <code>object</code> tags.<br><br>Example:<br><code>a:2:{s:1:&quot;a&quot;;i:10;i:0;a:1:{s:2:&quot;ab&quot;;b:1;}}</code><br>becomes<br><code>{&quot;a&quot;: 10,0: {&quot;ab&quot;: true}}</code><br><br><u>Output valid JSON:</u> JSON doesn't support integers as keys, whereas PHP serialization does. Enabling this will cast these integers to strings. This will also escape backslashes.",
+        inputType: "string",
+        outputType: "string",
+        args: [
+            {
+                name: "Output valid JSON",
+                type: "boolean",
+                value: PHP.OUTPUT_VALID_JSON
+            }
+        ]
+    },
 };
 };
 
 
 
 

+ 2 - 1
src/core/config/modules/Default.js

@@ -20,6 +20,7 @@ import NetBIOS from "../../operations/NetBIOS.js";
 import Numberwang from "../../operations/Numberwang.js";
 import Numberwang from "../../operations/Numberwang.js";
 import OS from "../../operations/OS.js";
 import OS from "../../operations/OS.js";
 import OTP from "../../operations/OTP.js";
 import OTP from "../../operations/OTP.js";
+import PHP from "../../operations/PHP.js";
 import QuotedPrintable from "../../operations/QuotedPrintable.js";
 import QuotedPrintable from "../../operations/QuotedPrintable.js";
 import Rotate from "../../operations/Rotate.js";
 import Rotate from "../../operations/Rotate.js";
 import SeqUtils from "../../operations/SeqUtils.js";
 import SeqUtils from "../../operations/SeqUtils.js";
@@ -28,7 +29,6 @@ import Tidy from "../../operations/Tidy.js";
 import Unicode from "../../operations/Unicode.js";
 import Unicode from "../../operations/Unicode.js";
 import UUID from "../../operations/UUID.js";
 import UUID from "../../operations/UUID.js";
 
 
-
 /**
 /**
  * Default module.
  * Default module.
  *
  *
@@ -155,6 +155,7 @@ OpModules.Default = {
     "Conditional Jump":     FlowControl.runCondJump,
     "Conditional Jump":     FlowControl.runCondJump,
     "Return":               FlowControl.runReturn,
     "Return":               FlowControl.runReturn,
     "Comment":              FlowControl.runComment,
     "Comment":              FlowControl.runComment,
+    "PHP Deserialize":      PHP.runDeserialize,
 
 
 
 
     /*
     /*

+ 160 - 0
src/core/operations/PHP.js

@@ -0,0 +1,160 @@
+/**
+ * PHP operations.
+ *
+ * @author Jarmo van Lenthe [github.com/jarmovanlenthe]
+ * @copyright Jarmo van Lenthe
+ * @license Apache-2.0
+ *
+ * @namespace
+ */
+const PHP = {
+
+    /**
+     * @constant
+     * @default
+     */
+    OUTPUT_VALID_JSON: true,
+
+    /**
+     * PHP Deserialize operation.
+     *
+     * This Javascript implementation is based on the Python implementation by
+     * Armin Ronacher (2016), who released it under the 3-Clause BSD license.
+     * See: https://github.com/mitsuhiko/phpserialize/
+     *
+     * @param {string} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    runDeserialize: function (input, args) {
+        /**
+         * Recursive method for deserializing.
+         * @returns {*}
+         */
+        function handleInput() {
+            /**
+             * Read `length` characters from the input, shifting them out the input.
+             * @param length
+             * @returns {string}
+             */
+            function read(length) {
+                let result = "";
+                for (let idx = 0; idx < length; idx++) {
+                    let char = inputPart.shift();
+                    if (char === undefined) {
+                        throw "End of input reached before end of script";
+                    }
+                    result += char;
+                }
+                return result;
+            }
+
+            /**
+             * Read characters from the input until `until` is found.
+             * @param until
+             * @returns {string}
+             */
+            function readUntil(until) {
+                let result = "";
+                for (;;) {
+                    let char = read(1);
+                    if (char === until) {
+                        break;
+                    } else {
+                        result += char;
+                    }
+                }
+                return result;
+
+            }
+
+            /**
+             * Read characters from the input that must be equal to `expect`
+             * @param expect
+             * @returns {string}
+             */
+            function expect(expect) {
+                let result = read(expect.length);
+                if (result !== expect) {
+                    throw "Unexpected input found";
+                }
+                return result;
+            }
+
+            /**
+             * Helper function to handle deserialized arrays.
+             * @returns {Array}
+             */
+            function handleArray() {
+                let items = parseInt(readUntil(":"), 10) * 2;
+                expect("{");
+                let result = [];
+                let isKey = true;
+                let lastItem = null;
+                for (let idx = 0; idx < items; idx++) {
+                    let item = handleInput();
+                    if (isKey) {
+                        lastItem = item;
+                        isKey = false;
+                    } else {
+                        let numberCheck = lastItem.match(/[0-9]+/);
+                        if (args[0] && numberCheck && numberCheck[0].length === lastItem.length) {
+                            result.push("\"" + lastItem + "\": " + item);
+                        } else {
+                            result.push(lastItem + ": " + item);
+                        }
+                        isKey = true;
+                    }
+                }
+                expect("}");
+                return result;
+            }
+
+
+            let kind = read(1).toLowerCase();
+
+            switch (kind) {
+                case "n":
+                    expect(";");
+                    return "";
+
+                case "i":
+                case "d":
+                case "b": {
+                    expect(":");
+                    let data = readUntil(";");
+                    if (kind === "b") {
+                        return (parseInt(data, 10) !== 0);
+                    }
+                    return data;
+                }
+
+                case "a":
+                    expect(":");
+                    return "{" + handleArray() + "}";
+
+                case "s": {
+                    expect(":");
+                    let length = readUntil(":");
+                    expect("\"");
+                    let value = read(length);
+                    expect("\";");
+                    if (args[0]) {
+                        return "\"" + value.replace(/"/g, "\\\"") + "\"";
+                    } else {
+                        return "\"" + value + "\"";
+                    }
+                }
+
+                default:
+                    throw "Unknown type: " + kind;
+            }
+        }
+
+        let inputPart = input.split("");
+        return handleInput();
+    }
+
+};
+
+export default PHP;

+ 1 - 0
test/index.js

@@ -25,6 +25,7 @@ import "./tests/operations/Hash.js";
 import "./tests/operations/Image.js";
 import "./tests/operations/Image.js";
 import "./tests/operations/MorseCode.js";
 import "./tests/operations/MorseCode.js";
 import "./tests/operations/MS.js";
 import "./tests/operations/MS.js";
+import "./tests/operations/PHP.js";
 import "./tests/operations/StrUtils.js";
 import "./tests/operations/StrUtils.js";
 import "./tests/operations/SeqUtils.js";
 import "./tests/operations/SeqUtils.js";
 
 

+ 68 - 0
test/tests/operations/PHP.js

@@ -0,0 +1,68 @@
+/**
+ * PHP tests.
+ *
+ * @author Jarmo van Lenthe
+ *
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+import TestRegister from "../../TestRegister.js";
+
+TestRegister.addTests([
+    {
+        name: "PHP Deserialize empty array",
+        input: "a:0:{}",
+        expectedOutput: "{}",
+        recipeConfig: [
+            {
+                op: "PHP Deserialize",
+                args: [true],
+            },
+        ],
+    },
+    {
+        name: "PHP Deserialize integer",
+        input: "i:10;",
+        expectedOutput: "10",
+        recipeConfig: [
+            {
+                op: "PHP Deserialize",
+                args: [true],
+            },
+        ],
+    },
+    {
+        name: "PHP Deserialize string",
+        input: "s:17:\"PHP Serialization\";",
+        expectedOutput: "\"PHP Serialization\"",
+        recipeConfig: [
+            {
+                op: "PHP Deserialize",
+                args: [true],
+            },
+        ],
+    },
+    {
+        name: "PHP Deserialize array (JSON)",
+        input: "a:2:{s:1:\"a\";i:10;i:0;a:1:{s:2:\"ab\";b:1;}}",
+        expectedOutput: "{\"a\": 10,\"0\": {\"ab\": true}}",
+        recipeConfig: [
+            {
+                op: "PHP Deserialize",
+                args: [true],
+            },
+        ],
+    },
+    {
+        name: "PHP Deserialize array (non-JSON)",
+        input: "a:2:{s:1:\"a\";i:10;i:0;a:1:{s:2:\"ab\";b:1;}}",
+        expectedOutput: "{\"a\": 10,0: {\"ab\": true}}",
+        recipeConfig: [
+            {
+                op: "PHP Deserialize",
+                args: [false],
+            },
+        ],
+    },
+]);