add "npm run irc", cleanup, more failure in unroll_rc4.js
This commit is contained in:
@@ -1,101 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
const path = require('path');
|
|
||||||
var classPath = path.resolve(__dirname + path.sep + "includes" + path.sep + "classes" + path.sep) + path.sep;
|
|
||||||
require(classPath + "Prototypes.js");
|
|
||||||
const WTVIRC = require(classPath + "WTVIRC.js");
|
|
||||||
const { WTVShared, clientShowAlert } = require(classPath + "WTVShared.js");
|
|
||||||
const wtvshared = new WTVShared(); // creates minisrv_config
|
|
||||||
const net = require('net');
|
|
||||||
|
|
||||||
var minisrv_config = wtvshared.readMiniSrvConfig(true, false, true);
|
|
||||||
|
|
||||||
if (!minisrv_config.config.irc || !minisrv_config.config.irc.enabled) {
|
|
||||||
console.error('IRC is not enabled in the configuration.');
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const HOST = 'localhost';
|
|
||||||
const PORT = minisrv_config.config.irc.port; // Example IRC port
|
|
||||||
|
|
||||||
const client = new net.Socket();
|
|
||||||
|
|
||||||
var lastLine = '';
|
|
||||||
|
|
||||||
client.connect(PORT, HOST, () => {
|
|
||||||
console.log(`Connected to ${HOST}:${PORT}`);
|
|
||||||
// You can send data here, e.g.:
|
|
||||||
// client.write('NICK testuser\r\n');
|
|
||||||
// client.write('USER testuser 0 * :Test User\r\n');
|
|
||||||
});
|
|
||||||
|
|
||||||
client.on('data', (data) => {
|
|
||||||
console.log('Received:', data.toString());
|
|
||||||
lastLine = data.toString();
|
|
||||||
});
|
|
||||||
|
|
||||||
client.on('close', () => {
|
|
||||||
console.log('Connection closed');
|
|
||||||
});
|
|
||||||
|
|
||||||
client.on('error', (err) => {
|
|
||||||
console.error('Connection error:', err);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
testCase4();
|
|
||||||
|
|
||||||
function testCase1() {
|
|
||||||
// Try to auth as a server when we are not allowed to
|
|
||||||
client.write('SERVER testserver 0 * :Test Server\r\n');
|
|
||||||
client.write('PASS \b\b\b\b\b\b\b\b\b\b\r\n');
|
|
||||||
client.write('SERVER testserver 0 * :Test Server\r\n');
|
|
||||||
client.write(`SVINFO 6 6 0 :-1\r\n`);
|
|
||||||
client.write('PASS \b\b\b\b\b\b\b\b\b\b\r\n');
|
|
||||||
// we should be disconnected here
|
|
||||||
}
|
|
||||||
|
|
||||||
function testCase2() {
|
|
||||||
// Malformed user authentication
|
|
||||||
client.write('NICK invaliduser\r\n');
|
|
||||||
client.write('USER invaliduser\r\n');
|
|
||||||
client.write('NICK invaliduser2\r\n');
|
|
||||||
client.write('NICK invaliduser\r\n');
|
|
||||||
client.write('USER invaliduser\r\n');
|
|
||||||
client.write('USER invaliduser\r\n');
|
|
||||||
client.write('USER invaliduser\r\n');
|
|
||||||
client.write('USER invaliduser\r\n');
|
|
||||||
// we should be disconnected here
|
|
||||||
}
|
|
||||||
|
|
||||||
async function waitFor(expectedResponse) {
|
|
||||||
while (!lastLine.includes(expectedResponse)) {
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 10)); // wait for 10ms
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function testCase3() {
|
|
||||||
// join, msg, quit
|
|
||||||
client.write('NICK testuser\r\n');
|
|
||||||
client.write('USER testuser 0 * :Test User\r\n');
|
|
||||||
await waitFor("005");
|
|
||||||
client.write('JOIN #testchannel\r\n');
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 10)); // wait for 10ms
|
|
||||||
client.write('PRIVMSG #testchannel :Hello, world!\r\n');
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 10)); // wait for 10ms
|
|
||||||
client.write('PART #testchannel\r\n');
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 10)); // wait for 10ms
|
|
||||||
client.write('QUIT :Goodbye\r\n');
|
|
||||||
// we should be disconnected here
|
|
||||||
}
|
|
||||||
|
|
||||||
function testCase4() {
|
|
||||||
// Arbitrary commands
|
|
||||||
client.write('NICK testuser\r\n');
|
|
||||||
client.write('MODE testuser +i\r\n');
|
|
||||||
client.write('TOPIC #testchannel :New topic\r\n');
|
|
||||||
client.write('KICK #testchannel testuser :You have been kicked\r\n');
|
|
||||||
client.write('NOTICE testuser :This is a notice\r\n');
|
|
||||||
client.write('INVITE testuser #testchannel\r\n');
|
|
||||||
client.write('WHO #testchannel\r\n');
|
|
||||||
client.write('LIST\r\n');
|
|
||||||
}
|
|
||||||
@@ -1,71 +1,98 @@
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const pcap = require('pcap-parser');
|
const pcap = require('pcap-parser');
|
||||||
const WTVSec = require('./includes/classes/WTVSec.js');
|
const WTVSec = require('./includes/classes/WTVSec.js');
|
||||||
const WTVLZPF = require('./includes/classes/WTVLzpf.js');
|
|
||||||
const httpHeaderParser = require('http-string-parser');
|
|
||||||
|
|
||||||
const server_ip = '192.168.11.26'; // 🔁 Replace with actual IP
|
// A map to hold the state of each TCP connection.
|
||||||
const connections = new Map(); // (key: `${srcIP}:${srcPort}<->${dstIP}:${dstPort}`)
|
const connections = new Map();
|
||||||
|
|
||||||
function connectionKey(src, sport, dst, dport) {
|
/**
|
||||||
return `${src}:${sport}<->${dst}:${dport}`;
|
* A simple, resilient function to parse HTTP headers from a buffer.
|
||||||
|
* @param {Buffer} buffer - The buffer containing HTTP headers.
|
||||||
|
* @returns {object|null} An object containing the headers, or null if headers are incomplete.
|
||||||
|
*/
|
||||||
|
function parseHeaders(buffer) {
|
||||||
|
const headers = {};
|
||||||
|
const headerString = buffer.toString('utf8');
|
||||||
|
const headersEnd = headerString.indexOf('\r\n\r\n');
|
||||||
|
if (headersEnd === -1) {
|
||||||
|
return null; // Incomplete headers
|
||||||
|
}
|
||||||
|
|
||||||
|
const lines = headerString.slice(0, headersEnd).split('\r\n');
|
||||||
|
for (const line of lines) {
|
||||||
|
const parts = line.split(':');
|
||||||
|
if (parts.length > 1) {
|
||||||
|
const key = parts.shift().trim().toLowerCase();
|
||||||
|
const value = parts.join(':').trim();
|
||||||
|
headers[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the state of a single direction of a TCP connection.
|
||||||
|
*/
|
||||||
class ConnectionState {
|
class ConnectionState {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.packets = [];
|
|
||||||
this.buffer = Buffer.alloc(0);
|
this.buffer = Buffer.alloc(0);
|
||||||
this.rc4 = null;
|
this.securityState = 'PLAINTEXT'; // PLAINTEXT, AWAITING_SECURE_RESPONSE, SECURE
|
||||||
this.secure = false;
|
this.wtvSec = null;
|
||||||
this.wtv = null;
|
this.initialKey = null;
|
||||||
|
this.challenge = null;
|
||||||
this.incarnation = null;
|
this.incarnation = null;
|
||||||
|
this.isClient = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends new data to the connection's buffer.
|
||||||
|
* @param {Buffer} data - The raw TCP payload data.
|
||||||
|
*/
|
||||||
feed(data) {
|
feed(data) {
|
||||||
this.buffer = Buffer.concat([this.buffer, data]);
|
this.buffer = Buffer.concat([this.buffer, data]);
|
||||||
this.packets.push(data);
|
}
|
||||||
|
|
||||||
// Parse headers if not done
|
/**
|
||||||
const text = this.buffer.toString();
|
* Initializes the WTVSec instance for this connection.
|
||||||
if (!this.wtv && text.includes('wtv-initial-key')) {
|
* @param {string} initialKey - The wtv-initial-key from the server.
|
||||||
const headers = httpHeaderParser.parseResponse(text).headers;
|
* @param {string} challenge - The wtv-challenge from the server.
|
||||||
if (headers['wtv-initial-key'] && headers['wtv-challenge']) {
|
*/
|
||||||
const initialKey = headers['wtv-initial-key'].trim();
|
initializeSecurity(initialKey, challenge) {
|
||||||
const challenge = headers['wtv-challenge'].trim();
|
this.wtvSec = new WTVSec({
|
||||||
|
config: {
|
||||||
this.wtv = new WTVSec({
|
keys: { initial_shared_key: initialKey },
|
||||||
config: {
|
debug_flags: { debug: false }
|
||||||
keys: {
|
|
||||||
initial_shared_key: initialKey,
|
|
||||||
},
|
|
||||||
debug_flags: {
|
|
||||||
debug: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.wtv.ProcessChallenge(challenge);
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
this.wtvSec.ProcessChallenge(challenge);
|
||||||
|
console.log("🔑 Security context initialized.");
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.secure && text.includes('SECURE ON')) {
|
/**
|
||||||
const headers = httpHeaderParser.parseRequest(text).headers;
|
* Sets up the RC4 keys for an encrypted session.
|
||||||
let incarnationHeader = Object.keys(headers).find(k => k.toLowerCase() === 'wtv-incarnation');
|
* @param {number} incarnation - The wtv-incarnation value.
|
||||||
let incarnationValue = incarnationHeader ? headers[incarnationHeader].trim() : "1";
|
*/
|
||||||
|
setupEncryption(incarnation) {
|
||||||
this.incarnation = parseInt(incarnationValue);
|
if (this.wtvSec) {
|
||||||
if (this.wtv) {
|
this.incarnation = incarnation;
|
||||||
this.wtv.set_incarnation(this.incarnation);
|
this.wtvSec.set_incarnation(this.incarnation);
|
||||||
this.secure = true;
|
console.log(`🔐 Encryption keys prepared for this stream (incarnation=${this.incarnation})`);
|
||||||
console.log("🔐 SECURE ON -- Starting decryption (incarnation =", this.incarnation + ")");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypts data using the appropriate RC4 key.
|
||||||
|
* @param {Buffer} data - The data to decrypt.
|
||||||
|
* @returns {Buffer} The decrypted or original data.
|
||||||
|
*/
|
||||||
decrypt(data) {
|
decrypt(data) {
|
||||||
if (this.secure && this.wtv) {
|
if (this.wtvSec && data.length > 0) {
|
||||||
try {
|
try {
|
||||||
return this.wtv.Decrypt(0, data); // Use key1 by default
|
// Client encrypts with key 0, server with key 1.
|
||||||
|
const keyNum = this.isClient ? 0 : 1;
|
||||||
|
const decrypted = this.wtvSec.Decrypt(keyNum, data);
|
||||||
|
console.log(`📦 Decrypted ${data.length} bytes for ${this.isClient ? 'client' : 'server'} stream.`);
|
||||||
|
return Buffer.from(decrypted);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Decryption failed:", e);
|
console.error("Decryption failed:", e);
|
||||||
return data;
|
return data;
|
||||||
@@ -75,54 +102,219 @@ class ConnectionState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main PCAP processing
|
/**
|
||||||
const parser = pcap.parse(fs.createReadStream('pcap.pcap'));
|
* Processes the reassembled buffer for a connection, handling state transitions.
|
||||||
|
* @param {ConnectionState} state - The state object for the current connection direction.
|
||||||
|
* @param {ConnectionState} oppositeState - The state for the opposite direction of the connection.
|
||||||
|
*/
|
||||||
|
function processConnectionBuffer(state, oppositeState) {
|
||||||
|
while (state.buffer.length > 0) {
|
||||||
|
switch (state.securityState) {
|
||||||
|
case 'AWAITING_SECURE_RESPONSE': {
|
||||||
|
const headersEndIndex = state.buffer.indexOf('\r\n\r\n');
|
||||||
|
if (headersEndIndex === -1) {
|
||||||
|
return; // Wait for the full headers.
|
||||||
|
}
|
||||||
|
|
||||||
parser.on('packet', packet => {
|
const bodyStartIndex = headersEndIndex + 4;
|
||||||
const data = packet.data;
|
const plaintextHeaders = state.buffer.slice(0, bodyStartIndex);
|
||||||
const ethType = data.readUInt16BE(12);
|
const encryptedBody = state.buffer.slice(bodyStartIndex);
|
||||||
if (ethType !== 0x0800) return; // Not IPv4
|
|
||||||
|
|
||||||
const ipHeader = data.slice(14, 34);
|
process.stdout.write(plaintextHeaders);
|
||||||
const protocol = ipHeader[9];
|
|
||||||
if (protocol !== 6) return; // Not TCP
|
|
||||||
|
|
||||||
const srcIP = ipHeader.slice(12, 16).join('.');
|
if (encryptedBody.length > 0) {
|
||||||
const dstIP = ipHeader.slice(16, 20).join('.');
|
const decryptedBody = state.decrypt(encryptedBody);
|
||||||
const tcpHeaderStart = 34;
|
process.stdout.write(decryptedBody);
|
||||||
const srcPort = data.readUInt16BE(tcpHeaderStart);
|
}
|
||||||
const dstPort = data.readUInt16BE(tcpHeaderStart + 2);
|
|
||||||
const tcpHeaderLen = (data[tcpHeaderStart + 12] >> 4) * 4;
|
|
||||||
const tcpPayloadOffset = tcpHeaderStart + tcpHeaderLen;
|
|
||||||
|
|
||||||
const payload = data.slice(tcpPayloadOffset);
|
state.buffer = Buffer.alloc(0);
|
||||||
|
state.securityState = 'SECURE';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'SECURE': {
|
||||||
|
const output = state.decrypt(state.buffer);
|
||||||
|
process.stdout.write(output);
|
||||||
|
state.buffer = Buffer.alloc(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'PLAINTEXT':
|
||||||
|
default: {
|
||||||
|
const headersEndIndex = state.buffer.indexOf('\r\n\r\n');
|
||||||
|
if (headersEndIndex === -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerSectionLength = headersEndIndex + 4;
|
||||||
|
const headerBuffer = state.buffer.slice(0, headerSectionLength);
|
||||||
|
const headers = parseHeaders(headerBuffer);
|
||||||
|
|
||||||
|
const requestLine = headerBuffer.toString('utf8').split('\r\n')[0];
|
||||||
|
if (state.isClient && requestLine.includes('SECURE ON')) {
|
||||||
|
console.log("▶️ Client sent SECURE ON. Transitioning to encrypted mode.");
|
||||||
|
let incarnation = headers['wtv-incarnation'] ? parseInt(headers['wtv-incarnation'].trim(), 10) : 1;
|
||||||
|
|
||||||
|
state.setupEncryption(incarnation);
|
||||||
|
state.securityState = 'SECURE';
|
||||||
|
if (oppositeState) {
|
||||||
|
oppositeState.setupEncryption(incarnation);
|
||||||
|
oppositeState.securityState = 'AWAITING_SECURE_RESPONSE';
|
||||||
|
}
|
||||||
|
|
||||||
|
process.stdout.write(headerBuffer);
|
||||||
|
const remainingData = state.buffer.slice(headerSectionLength);
|
||||||
|
|
||||||
|
if (remainingData.length > 0) {
|
||||||
|
const decryptedBody = state.decrypt(remainingData);
|
||||||
|
process.stdout.write(decryptedBody);
|
||||||
|
}
|
||||||
|
state.buffer = Buffer.alloc(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!state.isClient && headers) {
|
||||||
|
if (headers['wtv-initial-key']) {
|
||||||
|
state.initialKey = headers['wtv-initial-key'];
|
||||||
|
if(oppositeState) oppositeState.initialKey = headers['wtv-initial-key'];
|
||||||
|
console.log("Found wtv-initial-key.");
|
||||||
|
}
|
||||||
|
if (headers['wtv-challenge']) {
|
||||||
|
state.challenge = headers['wtv-challenge'];
|
||||||
|
if(oppositeState) oppositeState.challenge = headers['wtv-challenge'];
|
||||||
|
console.log("Found wtv-challenge.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.initialKey && state.challenge && !state.wtvSec) {
|
||||||
|
state.initializeSecurity(state.initialKey, state.challenge);
|
||||||
|
if (oppositeState) oppositeState.initializeSecurity(state.initialKey, state.challenge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let fullMessageLength = headerSectionLength;
|
||||||
|
if (headers && headers['content-length']) {
|
||||||
|
const bodyLength = parseInt(headers['content-length'], 10);
|
||||||
|
fullMessageLength += bodyLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.buffer.length < fullMessageLength) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fullMessage = state.buffer.slice(0, fullMessageLength);
|
||||||
|
process.stdout.write(fullMessage);
|
||||||
|
state.buffer = state.buffer.slice(fullMessageLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --- Main PCAP Processing Logic ---
|
||||||
|
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
const inputFile = args[args.indexOf('-i') + 1];
|
||||||
|
const serverIP = args[args.indexOf('-h') + 1];
|
||||||
|
|
||||||
|
if (!inputFile || !serverIP) {
|
||||||
|
console.error('Usage: node unroll_rc4.js -i <pcap_file> -h <server_ip>');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const parser = pcap.parse(fs.createReadStream(inputFile));
|
||||||
|
console.log(`🚀 Starting pcap parser for ${inputFile} with server IP ${serverIP}`);
|
||||||
|
|
||||||
|
let totalPackets = 0;
|
||||||
|
let processedPackets = 0;
|
||||||
|
let linkLayerType = -1;
|
||||||
|
let ipHeaderOffset = 14;
|
||||||
|
|
||||||
|
parser.on('globalHeader', (globalHeader) => {
|
||||||
|
linkLayerType = globalHeader.linkLayerType;
|
||||||
|
console.log(`[INFO] PCAP Link-Layer Header Type: ${linkLayerType}. Adjusting offsets.`);
|
||||||
|
switch (linkLayerType) {
|
||||||
|
case 0: ipHeaderOffset = 4; break;
|
||||||
|
case 1: ipHeaderOffset = 14; break;
|
||||||
|
case 101: ipHeaderOffset = 0; break;
|
||||||
|
case 113: ipHeaderOffset = 16; break;
|
||||||
|
default:
|
||||||
|
console.warn(`[WARN] Unsupported link-layer type: ${linkLayerType}. Assuming Ethernet.`);
|
||||||
|
ipHeaderOffset = 14;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
parser.on('packet', (packet) => {
|
||||||
|
totalPackets++;
|
||||||
|
|
||||||
|
let isIPv4 = false;
|
||||||
|
switch (linkLayerType) {
|
||||||
|
case 0: isIPv4 = (packet.data.length > 4) && (packet.data.readUInt32LE(0) === 2); break;
|
||||||
|
case 1: isIPv4 = packet.data.readUInt16BE(12) === 0x0800; break;
|
||||||
|
case 101: isIPv4 = (packet.data.length > 0) && ((packet.data[0] >> 4) === 4); break;
|
||||||
|
case 113: isIPv4 = packet.data.readUInt16BE(14) === 0x0800; break;
|
||||||
|
default: return;
|
||||||
|
}
|
||||||
|
if (!isIPv4) return;
|
||||||
|
|
||||||
|
const protocolOffset = ipHeaderOffset + 9;
|
||||||
|
if (packet.data.length <= protocolOffset || packet.data[protocolOffset] !== 6) return;
|
||||||
|
|
||||||
|
const ipHeaderLength = (packet.data[ipHeaderOffset] & 0x0F) * 4;
|
||||||
|
const tcpHeaderBase = ipHeaderOffset + ipHeaderLength;
|
||||||
|
const tcpHeaderLength = (packet.data[tcpHeaderBase + 12] >> 4) * 4;
|
||||||
|
const payloadOffset = tcpHeaderBase + tcpHeaderLength;
|
||||||
|
if (packet.data.length <= payloadOffset) return;
|
||||||
|
const payload = packet.data.slice(payloadOffset);
|
||||||
if (payload.length === 0) return;
|
if (payload.length === 0) return;
|
||||||
|
|
||||||
const isServer = srcIP === server_ip;
|
processedPackets++;
|
||||||
const connKey = connectionKey(srcIP, srcPort, dstIP, dstPort);
|
|
||||||
|
|
||||||
if (!connections.has(connKey)) {
|
const srcIP = packet.data.slice(ipHeaderOffset + 12, ipHeaderOffset + 16).join('.');
|
||||||
connections.set(connKey, new ConnectionState());
|
const dstIP = packet.data.slice(ipHeaderOffset + 16, ipHeaderOffset + 20).join('.');
|
||||||
|
const srcPort = packet.data.readUInt16BE(tcpHeaderBase);
|
||||||
|
const dstPort = packet.data.readUInt16BE(tcpHeaderBase + 2);
|
||||||
|
|
||||||
|
if (srcIP != serverIP && dstIP !== serverIP) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = connections.get(connKey);
|
const currentKey = `${srcIP}:${srcPort}->${dstIP}:${dstPort}`;
|
||||||
|
const oppositeKey = `${dstIP}:${dstPort}->${srcIP}:${srcPort}`;
|
||||||
|
|
||||||
|
if (!connections.has(currentKey)) {
|
||||||
|
let isClientToServer;
|
||||||
|
const payloadString = payload.toString('utf8');
|
||||||
|
console.log(payloadString);
|
||||||
|
if (srcIP === serverIP && dstIP === serverIP) {
|
||||||
|
isClientToServer = payloadString.startsWith('GET') || payloadString.startsWith('POST') || payloadString.startsWith('SECURE ON');
|
||||||
|
} else {
|
||||||
|
isClientToServer = dstIP === serverIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
connections.set(currentKey, new ConnectionState());
|
||||||
|
connections.set(oppositeKey, new ConnectionState());
|
||||||
|
connections.get(currentKey).isClient = isClientToServer;
|
||||||
|
connections.get(oppositeKey).isClient = !isClientToServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
const state = connections.get(currentKey);
|
||||||
|
const oppositeState = connections.get(oppositeKey);
|
||||||
|
|
||||||
state.feed(payload);
|
state.feed(payload);
|
||||||
|
processConnectionBuffer(state, oppositeState);
|
||||||
|
processConnectionBuffer(oppositeState, state);
|
||||||
|
|
||||||
const decrypted = state.decrypt(payload);
|
|
||||||
|
|
||||||
/* TODO
|
|
||||||
if (decrypted.includes("wtv-lzpf")) {
|
|
||||||
const headers = decrypted.toString('utf8').split("\n\n")[0];
|
|
||||||
const lzpf_data = decrypted.slice(headers.length + 2);
|
|
||||||
const lzpf = new WTVLZPF();
|
|
||||||
process.stdout.write(headers);
|
|
||||||
const decomp_data = lzpf.Decompress(lzpf_data);
|
|
||||||
process.stdout.write(decomp_data);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
process.stdout.write(decrypted);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
parser.on('end', () => {
|
parser.on('end', () => {
|
||||||
console.log('\n✅ Done parsing PCAP.');
|
console.log('\n[INFO] End of PCAP file reached. Processing any remaining buffered data...');
|
||||||
|
for(const [key, state] of connections.entries()){
|
||||||
|
const parts = key.split('->');
|
||||||
|
const oppositeKey = `${parts[1]}->${parts[0]}`;
|
||||||
|
if(connections.has(oppositeKey)) {
|
||||||
|
const oppositeState = connections.get(oppositeKey);
|
||||||
|
processConnectionBuffer(state, oppositeState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(`\n✅ Done parsing PCAP. Processed ${processedPackets} out of ${totalPackets} total packets.`);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user