CyberChef/src/core/operations/PhpSerialization.js

136 lines
3.9 KiB
JavaScript
Raw Normal View History

2017-11-12 21:37:29 -05:00
/**
* Php Serialization operations.
* This Javascript implementation is based on the Python
* implementation by Armin Ronacher (2016).
* See: https://github.com/mitsuhiko/phpserialize/
*
* @author Jarmo van Lenthe [github.com/jarmovanlenthe]
* @copyright Crown Copyright 2017
* @license BSD-3-Clause
*
* @namespace
*/
const PhpSerialization = {
/**
* @constant
* @default
*/
OUTPUT_VALID_JSON: true,
2017-11-12 22:11:16 -05:00
/**
* Deserializes a PHP serialized input
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
2017-11-12 21:37:29 -05:00
PhpDeserialize: function (input, args) {
function handleInput() {
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;
}
function readUntil(until) {
let result = "";
while (true) {
let char = read(1);
if (char === until) {
break;
2017-11-12 22:11:16 -05:00
} else {
2017-11-12 21:37:29 -05:00
result += char;
}
}
return result;
}
function expect(expect) {
let result = read(expect.length);
if (result !== expect) {
throw "Unexpected input found";
}
return result;
}
function handleArray() {
2017-11-12 22:11:16 -05:00
let items = parseInt(readUntil(":"), 10) * 2;
expect("{");
2017-11-12 21:37:29 -05:00
let result = [];
let isKey = true;
2017-11-12 22:11:16 -05:00
let lastItem = null;
2017-11-12 21:37:29 -05:00
for (let idx = 0; idx < items; idx++) {
let item = handleInput();
if (isKey) {
2017-11-12 22:11:16 -05:00
lastItem = item;
2017-11-12 21:37:29 -05:00
isKey = false;
} else {
2017-11-12 22:11:16 -05:00
let numberCheck = lastItem.match(/[0-9]+/);
if (args[0] && numberCheck && numberCheck[0].length === lastItem.length) {
result.push("\"" + lastItem + "\": " + item);
2017-11-12 21:37:29 -05:00
} else {
2017-11-12 22:11:16 -05:00
result.push(lastItem + ": " + item);
2017-11-12 21:37:29 -05:00
}
isKey = true;
}
}
2017-11-12 22:11:16 -05:00
expect("}");
2017-11-12 21:37:29 -05:00
return result;
}
let kind = read(1).toLowerCase();
switch (kind) {
2017-11-12 22:11:16 -05:00
case "n":
expect(";");
return "";
case "i":
case "d":
case "b": {
expect(":");
let data = readUntil(";");
if (kind === "b") {
return (parseInt(data, 10) !== 0);
}
2017-11-12 21:37:29 -05:00
return data;
2017-11-12 22:11:16 -05:00
}
2017-11-12 21:37:29 -05:00
2017-11-12 22:11:16 -05:00
case "a":
expect(":");
return "{" + handleArray() + "}";
2017-11-12 21:37:29 -05:00
2017-11-12 22:11:16 -05:00
case "s": {
expect(":");
let length = readUntil(":");
expect("\"");
2017-11-12 21:37:29 -05:00
let value = read(length);
2017-11-12 22:11:16 -05:00
expect("\";");
if (args[0]) {
return "\"" + value.replace(/"/g, "\\\"") + "\"";
} else {
return "\"" + value + "\"";
}
}
2017-11-12 21:37:29 -05:00
default:
throw "Unknown type: " + kind;
}
}
2017-11-12 22:11:16 -05:00
let inputPart = input.split("");
2017-11-12 21:37:29 -05:00
return handleInput();
}
};
export default PhpSerialization;