full encrypted convo to splash

This commit is contained in:
zefie
2021-07-12 19:48:35 -04:00
parent e3c5c15a7c
commit 6229567272
15 changed files with 426 additions and 219 deletions

View File

@@ -7,7 +7,6 @@ const strftime = require('strftime');
const net = require('net');
const CryptoJS = require('crypto-js');
const mime = require('mime-types');
var str2ab = require('string-to-arraybuffer')
var WTVNetworkSecurity = require('./wtvsec.js');
var zdebug = true;
@@ -17,8 +16,14 @@ var pubip = "192.168.11.8";
var port = 1615;
var sec_session = new Array();
var cookie_dat = new Array();
var socket_buffer = new Array();
var socket_session_data = new Array();
var overrides = new Array();
//overrides['initial_key'] = "CC5rWmRUE0o=";
//overrides['challenge'] = "0kjyqIYAu0ziFBbSERN6DGaZ6S0fT+DBUCtpHCJ4lpuM7CbXdAm+x83BIDoJYztd1Z+5KFZ7ghmb3LJCT/6mhWUYkqqKOyfPRW8ZIdbICK/CV+Kxm8EUjRXZSk/97tsmFpH3hcCJ7C2TBw+TX38uQQ==";
function getPublicIP() {
var options = {
host: 'www.planeptune.org',
@@ -35,6 +40,39 @@ function getPublicIP() {
});
}
function getFile(path, deps = false) {
var dir = null;
if (deps) dir = __dirname + "/ServiceDeps/";
else dir = __dirname + "/ServiceVault/";
if (fs.lstatSync(dir + path).isFile()) {
return fs.readFileSync(dir + path, {
encoding: null,
flags: 'r'
});
}
return null;
}
function issueWTVInitialKey(socket) {
if (overrides['initial_key']) {
sec_session[socket_session_data[socket.id].ssid].initial_shared_key = CryptoJS.enc.Base64.parse(overrides['initial_key']);
sec_session[socket_session_data[socket.id].ssid].current_shared_key = CryptoJS.enc.Base64.parse(overrides['initial_key']);
sec_session[socket_session_data[socket.id].ssid].challenge_key = CryptoJS.enc.Base64.parse(overrides['initial_key']);
return overrides['initial_key'];
} else {
return sec_session[socket_session_data[socket.id].ssid].challenge_key.toString(CryptoJS.enc.Base64);
}
}
function issueWTVChallenge(socket) {
if (overrides['challenge']) {
sec_session[socket_session_data[socket.id].ssid].challenge_response = sec_session[socket_session_data[socket.id].ssid].ProcessChallenge(overrides['challenge']);
return overrides['challenge'];
} else {
return sec_session[socket_session_data[socket.id].ssid].IssueChallenge();
}
}
function doErrorPage(code) {
var headers, data = null;
switch (code) {
@@ -62,6 +100,7 @@ function doErrorPage(code) {
function processPath(socket, path, initial_headers = new Array(), query = new Array()) {
var headers, data = null;
var request_is_direct_file = false;
path = path.replace(/\\/g, "/");
try {
try {
// try to see if the exact request exists
@@ -83,8 +122,17 @@ function processPath(socket, path, initial_headers = new Array(), query = new Ar
// raw text format, entire payload expected (headers and content)
console.log(" * Found " + path + ".txt to handle request (Raw TXT Mode)");
var fdat = fs.readFileSync(path + ".txt").toString();
headers = fdat.split("\n\n")[0];
data = fdat.split("\n\n")[1];
if (fdat.indexOf("\n\n") > 0) {
var fdata = fdat.split("\n\n");
headers = fdata[0];
fdata.shift();
data = fdata.join("\n");
} else if (fdat.indexOf("\r\n\r\n") > 0) {
var fdata = fdat.split("\r\n\r\n");
headers = fdata[0].replace(/\r/g, "");
fdata.shift();
data = fdata.join("\r\n");
}
} else if (fs.existsSync(path + ".js")) {
// js scripting, process with vars, must set 'headers' and 'data' appropriately.
// loaded script will have r/w access to any JavaScript vars this function does.
@@ -164,10 +212,14 @@ function processURL(socket, initial_headers) {
if (ssid == null) {
ssid = initial_headers['wtv-client-serial-number'];
}
var reqverb = "Request";
if (initial_headers['encrypted'] || initial_headers['secure']) {
reqverb = "Encrypted " + reqverb;
}
if (ssid != null) {
console.log(" * Request for " + initial_headers['request_url'] + " from WebTV SSID " + ssid);
console.log(" * "+reqverb+" for " + initial_headers['request_url'] + " from WebTV SSID " + ssid);
} else {
console.log(" * Request for " + initial_headers['request_url']);
console.log(" * "+reqverb+" for " + initial_headers['request_url']);
}
// assume webtv since there is a :/ in the GET
var urlToPath = __dirname + "/ServiceVault/" + shortURL.split(':/')[0] + "/" + shortURL.split(':/')[1];
@@ -226,11 +278,22 @@ function processURL(socket, initial_headers) {
// set wtv-encrypted and put it near the top of the headers (unknown if needed)
if (socket_session_data[socket.id].secure == true) {
console.log(" * encrypting response to client ...")
var clen = null;
if (typeof data.length !== 'undefined') {
clen = data.length;
} else if (typeof data.byteLength !== 'undefined') {
clen = data.byteLength;
}
headers_obj['wtv-encrypted'] = true;
headers_obj = moveObjectElement('wtv-encrypted', 'Connection', headers_obj);
var enc_data = sec_session[socket_session_data[socket.id].ssid].EncryptKey2(data);
var test = data;
if (clen > 0) {
console.log(" * Encrypting response to client ...")
if (typeof (data) === 'string') {
data = CryptoJS.enc.Utf8.parse(data);
}
var enc_data = sec_session[socket_session_data[socket.id].ssid].Encrypt(1,data);
data = enc_data;
}
}
headers = "";
@@ -252,7 +315,12 @@ function processURL(socket, initial_headers) {
toClient = headers + "\n" + data;
socket.write(toClient);
} else if (typeof data == 'object') {
socket.write(new Uint8Array(concatArrayBuffer(Buffer.from(headers + "\r\n"), data)));
if (socket_session_data[socket.id].secure_headers == true) {
var enc_headers = sec_session[socket_session_data[socket.id].ssid].Encrypt(1,headers+"\n");
socket.write(new Uint8Array(concatArrayBuffer(enc_headers, data)));
} else {
socket.write(new Uint8Array(concatArrayBuffer(Buffer.from(headers + "\n"), data)));
}
}
if (headers_obj['Connection']) {
if (headers_obj['Connection'].toLowerCase() == "close") {
@@ -297,28 +365,28 @@ function headersAreStandard(string) {
// is not suffuicent. This checks for characters expected in unecrypted headers, and returns
// true only if every character in the string matches the regex. Once we know the string is binary
// we can better process it with the raw base64 data in processHeaders() below.
var test = /^([A-Za-z0-9\+\/\=\-\.\ \;\:\?\&\r\n\(\)\%\<\>\_]{8,})$/.test(string);
var test = /^([A-Za-z0-9\+\/\=\-\.\,\ \;\:\?\&\r\n\(\)\%\<\>\_]{8,})$/.test(string);
if (zdebug) console.log("request is ascii: " + test);
if (zdebug) console.log("request as follows: " + string);
if (zdebug) console.log("request is SECURE ON: " + /^SECURE ON/.test(string));
return test;
}
function processHeaders(socket, data_b64, returnHeadersBeforeSecure = false) {
function processHeaders(socket, data_hex, returnHeadersBeforeSecure = false, encryptedRequest = false) {
var url = "";
var data = CryptoJS.enc.Latin1.stringify(CryptoJS.enc.Base64.parse(data_b64));
var data = CryptoJS.enc.Latin1.stringify(CryptoJS.enc.Hex.parse(data_hex));
var headers = new Array();
if (typeof data === "string") {
if (data.length > 1) {
data = data.split("\r\n\r\n")[0];
if (headersAreStandard(data)) {
data = data.split("\r\n\r\n")[0];
data.split('\n').forEach(function (d) {
if (d.length > 0) {
if (/^SECURE ON/.test(d)) {
console.log(data);
secure_mode = true;
headers['secure'] = true;
socket_session_data[socket.id].secure = true;
socket_session_data[socket.id].secure_headers = true;
}
if (d.indexOf(":") > 0 && d.indexOf(":/") == -1) {
headers[d.split(':')[0]] = (d.split(':')[1]).replace("\r", "");
@@ -332,10 +400,25 @@ function processHeaders(socket, data_b64, returnHeadersBeforeSecure = false) {
}
});
} else {
// failed the headersAreStandard test, so we think this is a binary blob
var encdata = CryptoJS.enc.Base64.parse(data_b64);
var decdata = sec_session[socket_session_data[socket.id].ssid].DecryptKey1(encdata);
var test = decdata;
if (!encryptedRequest) {
// failed the headersAreStandard test, so we think this is a binary blob
if (socket_session_data[socket.id].secure != true) {
// first time so reroll sessions
sec_session[socket_session_data[socket.id].ssid].SecureOn();
socket_session_data[socket.id].secure = true;
}
var enc_data = CryptoJS.enc.Hex.parse(data_hex.substring(header_length * 2));
if (enc_data.sigBytes > 0) {
var dec_data = CryptoJS.lib.WordArray.create(sec_session[socket_session_data[socket.id].ssid].Decrypt(0,enc_data));
var dec_data_text = dec_data.toString(CryptoJS.enc.Latin1);
var secure_headers = processHeaders(socket, dec_data.toString(CryptoJS.enc.Hex), true, true);
headers['encrypted'] = true;
console.log("Encrypted Request (Decrypted):", dec_data.toString(CryptoJS.enc.Latin1));
Object.keys(secure_headers).forEach(function (k, v) {
headers[k] = secure_headers[k];
});
}
}
}
if (headers['wtv-client-rom-type'] != null) {
socket_session_data[socket.id].romtype = headers['wtv-client-rom-type'];
@@ -354,16 +437,23 @@ function processHeaders(socket, data_b64, returnHeadersBeforeSecure = false) {
}
if (headers['secure'] === true) {
// assume we have an ssid if we are this far
sec_session[headers['wtv-client-serial-number']].SecureOn();
if (!sec_session[socket_session_data[socket.id].ssid]) {
sec_session[socket_session_data[socket.id].ssid] = new WTVNetworkSecurity();
sec_session[socket_session_data[socket.id].ssid].DecodeTicket(headers['wtv-ticket']);
sec_session[socket_session_data[socket.id].ssid].ticket_b64 = headers['wtv-ticket'];
sec_session[socket_session_data[socket.id].ssid].SecureOn();
}
if (!headers['request_url']) {
var header_length = data.length + 4;
var enc_data = CryptoJS.enc.Hex.parse(CryptoJS.enc.Base64.parse(data_b64).toString(CryptoJS.enc.Hex).substring(header_length * 2));
console.log(enc_data.toString(CryptoJS.enc.Hex));
var enc_data = CryptoJS.enc.Hex.parse(data_hex.substring(header_length * 2));
if (enc_data.sigBytes > 0) {
var dec_data = sec_session[socket_session_data[socket.id].ssid].DecryptKey1(enc_data);
console.log(dec_data);
console.log(headers);
var dec_data = CryptoJS.lib.WordArray.create(sec_session[socket_session_data[socket.id].ssid].Decrypt(0,enc_data))
//var dec_data_text = dec_data.toString(CryptoJS.enc.Latin1);
var secure_headers = processHeaders(socket, dec_data.toString(CryptoJS.enc.Hex), true);
console.log("Encrypted Request (Decrypted):", secure_headers.toString(CryptoJS.enc.Latin1));
Object.keys(secure_headers).forEach(function (k,v) {
headers[k] = secure_headers[k];
});
}
}
}
@@ -377,20 +467,31 @@ function processHeaders(socket, data_b64, returnHeadersBeforeSecure = false) {
}
var server = net.createServer(function (socket) {
socket.binaryType = 'arraybuffer';
socket.id = Math.floor(Math.random() * 1000);
socket_session_data[socket.id] = [];
socket.setEncoding('base64'); //set data encoding (either 'ascii', 'utf8', or 'base64')
socket.setEncoding('hex'); //set data encoding (either 'ascii', 'utf8', or 'base64')
socket.on('data', function (data_b64) {
processURL(this, processHeaders(this, data_b64));
socket.on('data', function (data_hex) {
socket.setTimeout(300);
if (socket_buffer[socket.id]) {
socket_buffer[socket.id].concat(CryptoJS.enc.Hex.parse(data_hex));
} else {
socket_buffer[socket.id] = CryptoJS.enc.Hex.parse(data_hex);
}
});
socket.on('timeout', function () {
socket.setTimeout(0);
processURL(this, processHeaders(this, socket_buffer[socket.id].toString(CryptoJS.enc.Hex)));
socket_buffer[socket.id] = null;
});
socket.on('error', (err, socket) => {
console.log('client socket error:', err);
});
socket.on('end', function () {
socket.on('end', function () {
socket_buffer[socket.id] = null;
secure_mode = false;
socket_session_data[socket.id] = null;
});