Improved executable binary handling

This commit is contained in:
Ylian Saint-Hilaire 2018-01-19 18:04:54 -08:00
parent 4106b322d6
commit 65f99a3c31
11 changed files with 410 additions and 64 deletions

View File

@ -28,6 +28,7 @@
<Compile Include="amtevents.js" />
<Compile Include="amtscanner.js" />
<Compile Include="amtscript.js" />
<Compile Include="exeHandler.js" />
<Compile Include="letsencrypt.js" />
<Compile Include="meshaccelerator.js" />
<Compile Include="meshmail.js" />

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -279,12 +279,12 @@ function startLms() {
//console.log("WebSocket for " + req.url.split('?')[0]);
switch (req.url.split('?')[0]) {
case '/lms.ashx': // MeshCommander control channel (PTHI)
socket.upgradeWebSocket();
socket.on('data', processLmsControlData);
socket.ws = socket.upgradeWebSocket();
socket.ws.on('data', processLmsControlData);
break;
case '/webrelay.ashx': // MeshCommander data channel (LME)
socket.upgradeWebSocket();
amtLms.bindDuplexStream(socket, 'IPv4', 16992);
socket.ws = socket.upgradeWebSocket();
amtLms.bindDuplexStream(socket.ws, 'IPv4', 16992);
break;
default:
socket.end();
@ -295,9 +295,8 @@ function startLms() {
//console.log("WebRequest for " + req.url.split('?')[0]);
switch (req.url.split('?')[0]) {
case '/': // Serve MeshCommander Web Application for LMS
rsp.writeHead(200, 'OK', { Server: 'JSLMS', 'Cache-Control': 'max-age=0, no-cache', 'X-Frame-Options': 'DENY', 'Content-Type': 'text/html', 'Content-Encoding': 'gzip', ETag: _IntelAmtWebApp_etag });
rsp.write(Buffer.from(_IntelAmtWebApp, 'base64'));
rsp.end();
rsp.writeHead(200, 'OK', { Server: 'JSLMS', 'Cache-Control': 'max-age=0, no-cache', 'X-Frame-Options': 'DENY', 'Content-Type': 'text/html', 'Content-Encoding': 'gzip', 'Transfer-Encoding': 'chunked', ETag: _IntelAmtWebApp_etag });
rsp.end(Buffer.from(_IntelAmtWebApp, 'base64'));
break;
default: // Unknown request
rsp.statusCode = 404;

View File

@ -692,7 +692,7 @@ function createMeshCore(agent) {
// Called when receiving control data on websocket
function onTunnelControlData(data) {
if (typeof data != 'string') return;
//sendConsoleText('onTunnelControlData: ' + data);
sendConsoleText('onTunnelControlData: ' + data);
//console.log('onTunnelControlData: ' + data);
var obj;
@ -729,7 +729,7 @@ function createMeshCore(agent) {
this.webrtc.on('connected', function () { sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC connected'); });
this.webrtc.on('disconnected', function () { sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC disconnected'); });
this.webrtc.on('dataChannel', function (rtcchannel) {
//sendConsoleText('WebRTC Datachannel open, protocol: ' + this.websocket.httprequest.protocol);
sendConsoleText('WebRTC Datachannel open, protocol: ' + this.websocket.httprequest.protocol);
rtcchannel.xrtc = this;
this.rtcchannel = rtcchannel;
this.rtcchannel.on('data', onTunnelWebRTCControlData);

308
exeHandler.js Normal file
View File

@ -0,0 +1,308 @@
/*
Copyright 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const exeJavaScriptGuid = 'B996015880544A19B7F7E9BE44914C18';
const exeMeshPolicyGuid = 'B996015880544A19B7F7E9BE44914C19';
// Changes a Windows Executable to add JavaScript inside of it.
// This method will write to destination stream and close it.
//
// options = {
// platform: 'win32' or 'linux',
// sourceFileName: 'pathToBinary',
// destinationStream: 'outputStream'
// js: 'jsContent',
// peinfo {} // Optional, if PE header already parsed place it here.
// }
//
module.exports.streamExeWithJavaScript = function (options) {
// Check all inputs
if (!options.platform) { throw ('platform not specified'); }
if (!options.destinationStream) { throw ('destination stream was not specified'); }
if (!options.sourceFileName) { throw ('source file not specified'); }
if (!options.js) { throw ('js content not specified'); }
// If a Windows binary, parse it if not already parsed
if ((options.platform == 'win32') && (!options.peinfo)) { options.peinfo = require('PE_Parser')(options.sourcePath); }
// If unsigned Windows or Linux, we merge at the end with the GUID and no padding.
if ((options.platform == 'win32' && options.peinfo.CertificateTableAddress == 0) || options.platform != 'win32') {
// This is not a signed binary, so we can just send over the EXE then the MSH
options.destinationStream.sourceStream = require('fs').createReadStream(options.sourceFileName, { flags: 'r' });
options.destinationStream.sourceStream.options = options;
options.destinationStream.sourceStream.on('end', function () {
// Once the binary is streamed, write the msh + length + guid in that order.
this.options.destinationStream.write(this.options.js); // JS content
var sz = Buffer.alloc(4);
sz.writeUInt32BE(this.options.js.length, 0);
this.options.destinationStream.write(sz); // Length in small endian
this.options.destinationStream.end(Buffer.from(exeJavaScriptGuid, 'hex')); // GUID
});
// Pipe the entire source binary without ending the stream.
options.destinationStream.sourceStream.pipe(options.destinationStream, { end: false });
} else {
throw ('js content not specified');
}
}
// Changes a Windows Executable to add the MSH inside of it.
// This method will write to destination stream and close it.
//
// options = {
// platform: 'win32' or 'linux',
// sourceFileName: 'pathToBinary',
// destinationStream: 'outputStream'
// msh: 'mshContent',
// peinfo {} // Optional, if PE header already parsed place it here.
// }
//
module.exports.streamExeWithMeshPolicy = function (options) {
// Check all inputs
if (!options.platform) { throw ('platform not specified'); }
if (!options.destinationStream) { throw ('destination stream was not specified'); }
if (!options.sourceFileName) { throw ('source file not specified'); }
if (!options.msh) { throw ('msh content not specified'); }
// If a Windows binary, parse it if not already parsed
if ((options.platform == 'win32') && (!options.peinfo)) { options.peinfo = require('PE_Parser')(options.sourcePath); }
// If unsigned Windows or Linux, we merge at the end with the GUID and no padding.
if ((options.platform == 'win32' && options.peinfo.CertificateTableAddress == 0) || options.platform != 'win32') {
// This is not a signed binary, so we can just send over the EXE then the MSH
options.destinationStream.sourceStream = require('fs').createReadStream(options.sourceFileName, { flags: 'r' });
options.destinationStream.sourceStream.options = options;
options.destinationStream.sourceStream.on('end', function () {
// Once the binary is streamed, write the msh + length + guid in that order.
this.options.destinationStream.write(this.options.msh); // MSH
var sz = Buffer.alloc(4);
sz.writeUInt32BE(this.options.msh.length, 0);
this.options.destinationStream.write(sz); // Length in small endian
this.options.destinationStream.end(Buffer.from(exeMeshPolicyGuid, 'hex')); // Guid
});
// Pipe the entire source binary without ending the stream.
options.destinationStream.sourceStream.pipe(options.destinationStream, { end: false });
} else if (options.platform == 'win32' && options.peinfo.CertificateTableAddress != 0) {
// This is a signed windows binary, so we need to do some magic
options.mshPadding = (8 - ((options.peinfo.certificateDwLength + options.msh.length + 20) % 8)) % 8; // Compute the padding with quad-align
//console.log('old table size = ' + options.peinfo.CertificateTableSize);
options.peinfo.CertificateTableSize += (options.msh.length + 20 + options.mshPadding); // Add to the certificate table size
//console.log('new table size = ' + options.peinfo.CertificateTableSize);
//console.log('old certificate dwLength = ' + options.peinfo.certificateDwLength);
options.peinfo.certificateDwLength += (options.msh.length + 20 + options.mshPadding); // Add to the certificate size
//console.log('new certificate dwLength = ' + options.peinfo.certificateDwLength);
//console.log('values were padded with ' + options.mshPadding + ' bytes');
// Read up to the certificate table size and stream that out
options.destinationStream.sourceStream = require('fs').createReadStream(options.sourceFileName, { flags: 'r', start: 0, end: options.peinfo.CertificateTableSizePos - 1 });
options.destinationStream.sourceStream.options = options;
options.destinationStream.sourceStream.on('end', function () {
// We sent up to the CertificateTableSize, now we need to send the updated certificate table size
//console.log('read first block');
var sz = Buffer.alloc(4);
sz.writeUInt32LE(this.options.peinfo.CertificateTableSize, 0);
this.options.destinationStream.write(sz); // New cert table size
// Stream everything up to the start of the certificate table entry
var source2 = require('fs').createReadStream(options.sourceFileName, { flags: 'r', start: this.options.peinfo.CertificateTableSizePos + 4, end: this.options.peinfo.CertificateTableAddress - 1 });
source2.options = this.options;
source2.on('end', function () {
// We've sent up to the Certificate DWLength, which we need to update
//console.log('read second block');
var sz = Buffer.alloc(4);
sz.writeUInt32LE(this.options.peinfo.certificateDwLength, 0);
this.options.destinationStream.write(sz); // New certificate length
// Stream the entire binary until the end
var source3 = require('fs').createReadStream(options.sourceFileName, { flags: 'r', start: this.options.peinfo.CertificateTableAddress + 4 });
source3.options = this.options;
source3.on('end', function () {
// We've sent the entire binary... Now send: Padding + MSH + MSHLength + GUID
//console.log('read third block');
if (this.options.mshPadding > 0) { this.options.destinationStream.write(Buffer.alloc(this.options.mshPadding)); } // Padding
this.options.destinationStream.write(this.options.msh); // MSH content
var sz = Buffer.alloc(4);
sz.writeUInt32BE(this.options.msh.length, 0);
this.options.destinationStream.write(sz); // MSH Length, small-endian
this.options.destinationStream.end(Buffer.from(exeMeshPolicyGuid, 'hex')); // MSH GUID
});
source3.pipe(this.options.destinationStream, { end: false });
this.options.sourceStream = source3;
});
source2.pipe(this.options.destinationStream, { end: false });
this.options.destinationStream.sourceStream = source2;
});
this.options.destinationStream.sourceStream.pipe(this.options.destinationStream, { end: false });
}
}
// Return information about this executable
// This works only on Windows binaries
module.exports.parseWindowsExecutable = function (exePath) {
var retVal = {};
var fs = require('fs');
var fd = fs.openSync(exePath, 'r');
var bytesRead;
var dosHeader = Buffer.alloc(64);
var ntHeader = Buffer.alloc(24);
var optHeader;
// Read the DOS header
bytesRead = fs.readSync(fd, dosHeader, 0, 64, 0);
if (dosHeader.readUInt16LE(0).toString(16).toUpperCase() != '5A4D') { throw ('unrecognized binary format'); }
// Read the NT header
bytesRead = fs.readSync(fd, ntHeader, 0, ntHeader.length, dosHeader.readUInt32LE(60));
if (ntHeader.slice(0, 4).toString('hex') != '50450000') {
throw ('not a PE file');
}
switch (ntHeader.readUInt16LE(4).toString(16)) {
case '14c': // 32 bit
retVal.format = 'x86';
break;
case '8664': // 64 bit
retVal.format = 'x64';
break;
default: // Unknown
retVal.format = undefined;
break;
}
retVal.optionalHeaderSize = ntHeader.readUInt16LE(20);
retVal.optionalHeaderSizeAddress = dosHeader.readUInt32LE(60) + 20;
// Read the optional header
optHeader = Buffer.alloc(ntHeader.readUInt16LE(20));
bytesRead = fs.readSync(fd, optHeader, 0, optHeader.length, dosHeader.readUInt32LE(60) + 24);
var numRVA = undefined;
retVal.CheckSumPos = dosHeader.readUInt32LE(60) + 24 + 64;
retVal.SizeOfCode = optHeader.readUInt32LE(4);
retVal.SizeOfInitializedData = optHeader.readUInt32LE(8);
retVal.SizeOfUnInitializedData = optHeader.readUInt32LE(12);
switch (optHeader.readUInt16LE(0).toString(16).toUpperCase()) {
case '10B': // 32 bit binary
numRVA = optHeader.readUInt32LE(92);
retVal.CertificateTableAddress = optHeader.readUInt32LE(128);
retVal.CertificateTableSize = optHeader.readUInt32LE(132);
retVal.CertificateTableSizePos = dosHeader.readUInt32LE(60) + 24 + 132;
retVal.rvaStartAddress = dosHeader.readUInt32LE(60) + 24 + 96;
break;
case '20B': // 64 bit binary
numRVA = optHeader.readUInt32LE(108);
retVal.CertificateTableAddress = optHeader.readUInt32LE(144);
retVal.CertificateTableSize = optHeader.readUInt32LE(148);
retVal.CertificateTableSizePos = dosHeader.readUInt32LE(60) + 24 + 148;
retVal.rvaStartAddress = dosHeader.readUInt32LE(60) + 24 + 112;
break;
default:
throw ('Unknown Value found for Optional Magic: ' + ntHeader.readUInt16LE(24).toString(16).toUpperCase());
}
retVal.rvaCount = numRVA;
if (retVal.CertificateTableAddress) {
// Read the authenticode certificate, only one cert (only the first entry)
var hdr = Buffer.alloc(8);
fs.readSync(fd, hdr, 0, hdr.length, retVal.CertificateTableAddress);
retVal.certificate = Buffer.alloc(hdr.readUInt32LE(0));
fs.readSync(fd, retVal.certificate, 0, retVal.certificate.length, retVal.CertificateTableAddress + hdr.length);
retVal.certificate = retVal.certificate.toString('base64');
retVal.certificateDwLength = hdr.readUInt32LE(0);
}
fs.closeSync(fd);
return (retVal);
}
//
// Hash a executable file. Works on both Windows and Linux.
// On Windows, will hash so that signature or .msh addition will not change the hash. Adding a .js on un-signed executable will change the hash.
//
// options = {
// sourcePath: <string> Executable Path
// targetStream: <stream.writeable> Hashing Stream
// platform: <string> Optional. Same value as process.platform ('win32' | 'linux' | 'darwin')
// }
//
module.exports.hashExecutableFile = function (options) {
if (!options.sourcePath || !options.targetStream) { throw ('Please specify sourcePath and targetStream'); }
var fs = require('fs');
// If not specified, try to determine platform type
if (!options.platform) {
try {
// If we can parse the executable, we know it's windows.
options.peinfo = module.exports.parseWindowsExecutable(options.sourcePath);
options.platform = 'win32';
} catch (e) {
options.platform = 'other';
}
}
// Setup initial state
options.state = { endIndex: 0, checkSumIndex: 0, tableIndex: 0, stats: fs.statSync(options.sourcePath) };
if (options.platform == 'win32')
{
if (options.peinfo.CertificateTableAddress != 0) { options.state.endIndex = options.peinfo.CertificateTableAddress; }
options.state.tableIndex = options.peinfo.CertificateTableSizePos - 4;
options.state.checkSumIndex = options.peinfo.CheckSumPos;
}
if (options.state.endIndex == 0) {
// We just need to check for Embedded MSH file
var fd = fs.openSync(options.sourcePath, 'r');
var guid = Buffer.alloc(16);
var bytesRead;
bytesRead = fs.readSync(fd, guid, 0, guid.length, options.state.stats.size - 16);
if (guid.toString('hex') == exeMeshPolicyGuid) {
bytesRead = fs.readSync(fd, guid, 0, 4, options.state.stats.size - 20);
options.state.endIndex = options.state.stats.size - 20 - guid.readUInt32LE(0);
} else {
options.state.endIndex = options.state.stats.size;
}
fs.closeSync(fd);
}
// Linux does not have a checksum
if (options.state.checkSumIndex != 0) {
// Windows
options.state.source = fs.createReadStream(options.sourcePath, { flags: 'r', start: 0, end: options.state.checkSumIndex - 1 });
options.state.source.on('end', function () {
options.targetStream.write(Buffer.alloc(4));
var source = fs.createReadStream(options.sourcePath, { flags: 'r', start: options.state.checkSumIndex + 4, end: options.state.tableIndex - 1 });
source.on('end', function () {
options.targetStream.write(Buffer.alloc(8));
var source = fs.createReadStream(options.sourcePath, { flags: 'r', start: options.state.tableIndex + 8, end: options.state.endIndex - 1 });
options.state.source = source;
options.state.source.pipe(options.targetStream);
});
options.state.source = source;
options.state.source.pipe(options.targetStream, { end: false });
});
options.state.source.pipe(options.targetStream, { end: false });
} else {
// Linux
options.state.source = fs.createReadStream(options.sourcePath, { flags: 'r', start: 0, end: options.state.endIndex - 1 });
options.state.source.pipe(options.targetStream);
}
}

View File

@ -25,6 +25,7 @@ function CreateMeshCentralServer() {
obj.fs = require('fs');
obj.path = require('path');
obj.crypto = require('crypto');
obj.exeHandler = require('./exeHandler.js');
obj.platform = require('os').platform();
obj.args = require('minimist')(process.argv.slice(2));
obj.common = require('./common.js');
@ -854,64 +855,65 @@ function CreateMeshCentralServer() {
// List of possible mesh agents
obj.meshAgentsArchitectureNumbers = {
0: { id: 0, localname: 'Unknown', rname: 'meshconsole.exe', desc: 'Unknown agent', update: false, amt: true },
1: { id: 1, localname: 'MeshConsole.exe', rname: 'meshconsole.exe', desc: 'Windows x86-32 console', update: true, amt: true },
2: { id: 2, localname: 'MeshConsole64.exe', rname: 'meshconsole.exe', desc: 'Windows x86-64 console', update: true, amt: true },
3: { id: 3, localname: 'MeshService.exe', rname: 'meshagent.exe', desc: 'Windows x86-32 service', update: true, amt: true },
4: { id: 4, localname: 'MeshService64.exe', rname: 'meshagent.exe', desc: 'Windows x86-64 service', update: true, amt: true },
5: { id: 5, localname: 'meshagent_x86', rname: 'meshagent', desc: 'Linux x86-32', update: true, amt: true },
6: { id: 6, localname: 'meshagent_x86-64', rname: 'meshagent', desc: 'Linux x86-64', update: true, amt: true },
7: { id: 7, localname: 'meshagent_mips', rname: 'meshagent', desc: 'Linux MIPS', update: true, amt: false },
8: { id: 8, localname: 'MeshAgent-Linux-XEN-x86-32', rname: 'meshagent', desc: 'XEN x86-64', update: true, amt: false },
9: { id: 9, localname: 'meshagent_arm', rname: 'meshagent', desc: 'Linux ARM5', update: true, amt: false },
10: { id: 10, localname: 'MeshAgent-Linux-ARM-PlugPC', rname: 'meshagent', desc: 'Linux ARM PlugPC', update: true, amt: false },
11: { id: 11, localname: 'MeshAgent-OSX-x86-32', rname: 'meshosx', desc: 'Apple OSX x86-32', update: true, amt: false },
12: { id: 12, localname: 'MeshAgent-Android-x86', rname: 'meshandroid', desc: 'Android x86-32', update: true, amt: false },
13: { id: 13, localname: 'meshagent_pogo', rname: 'meshagent', desc: 'Linux ARM PogoPlug', update: true, amt: false },
14: { id: 14, localname: 'MeshAgent-Android-APK', rname: 'meshandroid', desc: 'Android Market', update: false, amt: false }, // Get this one from Google Play
15: { id: 15, localname: 'meshagent_poky', rname: 'meshagent', desc: 'Linux Poky x86-32', update: true, amt: false },
16: { id: 16, localname: 'MeshAgent-OSX-x86-64', rname: 'meshagent', desc: 'Apple OSX x86-64', update: true, amt: false },
17: { id: 17, localname: 'MeshAgent-ChromeOS', rname: 'meshagent', desc: 'Google ChromeOS', update: false, amt: false }, // Get this one from Chrome store
18: { id: 18, localname: 'meshagent_poky64', rname: 'meshagent', desc: 'Linux Poky x86-64', update: true, amt: false },
19: { id: 19, localname: 'meshagent_x86_nokvm', rname: 'meshagent', desc: 'Linux x86-32 NoKVM', update: true, amt: true },
20: { id: 20, localname: 'meshagent_x86-64_nokvm', rname: 'meshagent', desc: 'Linux x86-64 NoKVM', update: true, amt: true },
21: { id: 21, localname: 'MeshAgent-WinMinCore-Console-x86-32.exe', rname: 'meshagent.exe', desc: 'Windows MinCore Console x86-32', update: true, amt: false },
22: { id: 22, localname: 'MeshAgent-WinMinCore-Service-x86-64.exe', rname: 'meshagent.exe', desc: 'Windows MinCore Service x86-32', update: true, amt: false },
23: { id: 23, localname: 'MeshAgent-NodeJS', rname: 'meshagent', desc: 'NodeJS', update: false, amt: false }, // Get this one from NPM
24: { id: 24, localname: 'meshagent_arm-linaro', rname: 'meshagent', desc: 'Linux ARM Linaro', update: true, amt: false },
25: { id: 25, localname: 'meshagent_pi', rname: 'meshagent', desc: 'Linux ARM - Raspberry Pi', update: true, amt: false } // "armv6l" and "armv7l"
0: { id: 0, localname: 'Unknown', rname: 'meshconsole.exe', desc: 'Unknown agent', update: false, amt: true, platform: 'unknown' },
1: { id: 1, localname: 'MeshConsole.exe', rname: 'meshconsole.exe', desc: 'Windows x86-32 console', update: true, amt: true, platform: 'win32' },
2: { id: 2, localname: 'MeshConsole64.exe', rname: 'meshconsole.exe', desc: 'Windows x86-64 console', update: true, amt: true, platform: 'win32' },
3: { id: 3, localname: 'MeshService.exe', rname: 'meshagent.exe', desc: 'Windows x86-32 service', update: true, amt: true, platform: 'win32' },
4: { id: 4, localname: 'MeshService64.exe', rname: 'meshagent.exe', desc: 'Windows x86-64 service', update: true, amt: true, platform: 'win32' },
5: { id: 5, localname: 'meshagent_x86', rname: 'meshagent', desc: 'Linux x86-32', update: true, amt: true, platform: 'linux' },
6: { id: 6, localname: 'meshagent_x86-64', rname: 'meshagent', desc: 'Linux x86-64', update: true, amt: true, platform: 'linux' },
7: { id: 7, localname: 'meshagent_mips', rname: 'meshagent', desc: 'Linux MIPS', update: true, amt: false, platform: 'linux' },
8: { id: 8, localname: 'MeshAgent-Linux-XEN-x86-32', rname: 'meshagent', desc: 'XEN x86-64', update: true, amt: false, platform: 'linux' },
9: { id: 9, localname: 'meshagent_arm', rname: 'meshagent', desc: 'Linux ARM5', update: true, amt: false, platform: 'linux' },
10: { id: 10, localname: 'MeshAgent-Linux-ARM-PlugPC', rname: 'meshagent', desc: 'Linux ARM PlugPC', update: true, amt: false, platform: 'linux' },
11: { id: 11, localname: 'MeshAgent-OSX-x86-32', rname: 'meshosx', desc: 'Apple OSX x86-32', update: true, amt: false, platform: 'linux' },
12: { id: 12, localname: 'MeshAgent-Android-x86', rname: 'meshandroid', desc: 'Android x86-32', update: true, amt: false, platform: 'linux' },
13: { id: 13, localname: 'meshagent_pogo', rname: 'meshagent', desc: 'Linux ARM PogoPlug', update: true, amt: false, platform: 'linux' },
14: { id: 14, localname: 'MeshAgent-Android-APK', rname: 'meshandroid', desc: 'Android Market', update: false, amt: false, platform: 'android' }, // Get this one from Google Play
15: { id: 15, localname: 'meshagent_poky', rname: 'meshagent', desc: 'Linux Poky x86-32', update: true, amt: false, platform: 'linux' },
16: { id: 16, localname: 'MeshAgent-OSX-x86-64', rname: 'meshagent', desc: 'Apple OSX x86-64', update: true, amt: false, platform: 'osx' },
17: { id: 17, localname: 'MeshAgent-ChromeOS', rname: 'meshagent', desc: 'Google ChromeOS', update: false, amt: false, platform: 'chromeos' }, // Get this one from Chrome store
18: { id: 18, localname: 'meshagent_poky64', rname: 'meshagent', desc: 'Linux Poky x86-64', update: true, amt: false, platform: 'linux' },
19: { id: 19, localname: 'meshagent_x86_nokvm', rname: 'meshagent', desc: 'Linux x86-32 NoKVM', update: true, amt: true, platform: 'linux' },
20: { id: 20, localname: 'meshagent_x86-64_nokvm', rname: 'meshagent', desc: 'Linux x86-64 NoKVM', update: true, amt: true, platform: 'linux' },
21: { id: 21, localname: 'MeshAgent-WinMinCore-Console-x86-32.exe', rname: 'meshagent.exe', desc: 'Windows MinCore Console x86-32', update: true, amt: false, platform: 'win32' },
22: { id: 22, localname: 'MeshAgent-WinMinCore-Service-x86-64.exe', rname: 'meshagent.exe', desc: 'Windows MinCore Service x86-32', update: true, amt: false, platform: 'win32' },
23: { id: 23, localname: 'MeshAgent-NodeJS', rname: 'meshagent', desc: 'NodeJS', update: false, amt: false, platform: 'node' }, // Get this one from NPM
24: { id: 24, localname: 'meshagent_arm-linaro', rname: 'meshagent', desc: 'Linux ARM Linaro', update: true, amt: false, platform: 'linux' },
25: { id: 25, localname: 'meshagent_pi', rname: 'meshagent', desc: 'Linux ARM - Raspberry Pi', update: true, amt: false, platform: 'linux' } // "armv6l" and "armv7l"
};
// Update the list of available mesh agents
obj.updateMeshAgentsTable = function (func) {
var archcount = 0;
for (var archid in obj.meshAgentsArchitectureNumbers) { archcount++; }
for (var archid in obj.meshAgentsArchitectureNumbers) {
var agentpath = obj.path.join(__dirname, 'agents', obj.meshAgentsArchitectureNumbers[archid].localname);
var stream = null;
try {
stream = obj.fs.createReadStream(agentpath);
stream.on('data', function (data) { this.hash.update(data, 'binary') });
stream.on('error', function (data) {
// If there is an error reading this file, make sure this agent is not in the agent table
if (obj.meshAgentBinaries[this.info.id] != null) { delete obj.meshAgentBinaries[this.info.id]; }
// Fetch all the agent binary information
obj.meshAgentBinaries[archid] = obj.common.Clone(obj.meshAgentsArchitectureNumbers[archid]);
obj.meshAgentBinaries[archid].path = agentpath;
obj.meshAgentBinaries[archid].url = ((obj.args.notls == true) ? 'http://' : 'https://') + obj.certificates.CommonName + ':' + obj.args.port + '/meshagents?id=' + archid;
var stats = null;
try { stats = obj.fs.statSync(agentpath) } catch (e) { }
if ((stats != null)) {
// If file exists
archcount++;
obj.meshAgentBinaries[archid].size = stats.size;
// If this is a windows binary, pull binary information
if (obj.meshAgentsArchitectureNumbers[archid].platform == 'win32') {
try { obj.meshAgentBinaries[archid].pe = obj.exeHandler.parseWindowsExecutable(agentpath); } catch (e) { }
}
// Hash the binary
var hashStream = obj.crypto.createHash('sha384');
hashStream.archid = archid;
hashStream.on('data', function (data) {
obj.meshAgentBinaries[this.archid].hash = data.toString('hex');
if ((--archcount == 0) && (func != null)) { func(); }
});
stream.on('end', function () {
// Add the agent to the agent table with all information and the hash
obj.meshAgentBinaries[this.info.id] = obj.common.Clone(this.info);
obj.meshAgentBinaries[this.info.id].hash = this.hash.digest('hex');
obj.meshAgentBinaries[this.info.id].path = this.agentpath;
obj.meshAgentBinaries[this.info.id].url = ((obj.args.notls == true) ? 'http://' : 'https://') + obj.certificates.CommonName + ':' + obj.args.port + '/meshagents?id=' + this.info.id;
var stats = null;
try { stats = obj.fs.statSync(this.agentpath) } catch (e) { }
if (stats != null) { obj.meshAgentBinaries[this.info.id].size = stats.size; }
if ((--archcount == 0) && (func != null)) { func(); }
});
stream.info = obj.meshAgentsArchitectureNumbers[archid];
stream.agentpath = agentpath;
stream.hash = obj.crypto.createHash('sha384', stream);
} catch (e) { if ((--archcount == 0) && (func != null)) { func(); } }
var options = { sourcePath: agentpath, targetStream: hashStream, platform: obj.meshAgentsArchitectureNumbers[archid].platform };
if (obj.meshAgentBinaries[archid].pe != null) { options.peinfo = obj.meshAgentBinaries[archid].pe; }
obj.exeHandler.hashExecutableFile(options);
}
}
}

View File

@ -1,6 +1,6 @@
{
"name": "meshcentral",
"version": "0.1.2-u",
"version": "0.1.2-s",
"keywords": [
"Remote Management",
"Intel AMT",

View File

@ -1577,9 +1577,10 @@
x += addHtmlValue('Operating System', '<select id=aginsSelect onchange=addAgentToMeshClick() style=width:236px><option value=0>Windows</option><option value=1>Linux</option><option value=2>Windows (UnInstall)</option><option value=3>Linux (UnInstall)</option></select>') + '<hr>';
// Windows agent install
x += "<div id=agins_windows>To add a new computer to mesh " + EscapeHtml(mesh.name) + ", download the mesh agent and configuration file and install the agent on the computer to manage.<br /><br />";
x += addHtmlValue('Mesh Agent', '<a href="meshagents?id=3" target="_blank">Windows executable (.exe)</a>');
x += addHtmlValue('Settings File', '<a href="meshsettings?id=' + meshid.split('/')[2] + '" target="_blank">' + EscapeHtml(mesh.name) + ' settings (.msh)</a>');
//x += "<div id=agins_windows>To add a new computer to mesh " + EscapeHtml(mesh.name) + ", download the mesh agent and configuration file and install the agent on the computer to manage.<br /><br />";
x += "<div id=agins_windows>To add a new computer to mesh " + EscapeHtml(mesh.name) + ", download the mesh agent and install it the computer to manage. This agent has server and mesh information embedded within it.<br /><br />";
x += addHtmlValue('Mesh Agent', '<a href="meshagents?id=3&meshid=' + meshid.split('/')[2] + '" target="_blank">Windows executable (.exe)</a>');
//x += addHtmlValue('Settings File', '<a href="meshsettings?id=' + meshid.split('/')[2] + '" target="_blank">' + EscapeHtml(mesh.name) + ' settings (.msh)</a>');
x += "</div>";
// Linux agent install

View File

@ -1397,12 +1397,40 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
// Handle a request to download a mesh agent
obj.handleMeshAgentRequest = function (req, res) {
var domain = checkUserIpAddress(req, res);
if (domain == null) return;
if (req.query.id != null) {
// Send a specific mesh agent back
var argentInfo = obj.parent.meshAgentBinaries[req.query.id];
if (argentInfo == null) { res.sendStatus(404); return; }
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=' + argentInfo.rname });
res.sendFile(argentInfo.path);
if ((req.query.meshid == null) || (argentInfo.platform != 'win32')) {
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=' + argentInfo.rname });
res.sendFile(argentInfo.path);
} else {
// We are going to embed the .msh file into the Windows executable (signed or not).
// First, query the meshid to build the .msh file
obj.db.Get('mesh/' + domain.id + '/' + req.query.meshid, function (err, meshes) {
if (meshes.length != 1) { res.sendStatus(401); return; }
var mesh = meshes[0];
// Check if this user has rights to do this
//var user = obj.users[req.session.userid];
//if ((user == null) || (mesh.links[user._id] == null) || ((mesh.links[user._id].rights & 1) == 0)) { res.sendStatus(401); return; }
//if (domain.id != mesh.domain) { res.sendStatus(401); return; }
var meshidhex = new Buffer(req.query.meshid.replace(/\@/g, '+').replace(/\$/g, '/'), 'base64').toString('hex').toUpperCase();
var serveridhex = new Buffer(obj.agentCertificateHashBase64.replace(/\@/g, '+').replace(/\$/g, '/'), 'base64').toString('hex').toUpperCase();
// Build the agent connection URL. If we are using a sub-domain or one with a DNS, we need to craft the URL correctly.
var xdomain = (domain.dns == null) ? domain.id : '';
if (xdomain != '') xdomain += "/";
var meshsettings = "MeshName=" + mesh.name + "\r\nMeshType=" + mesh.mtype + "\r\nMeshID=0x" + meshidhex + "\r\nServerID=" + serveridhex + "\r\n";
if (obj.args.lanonly != true) { meshsettings += "MeshServer=ws" + (obj.args.notls ? '' : 's') + "://" + getWebServerName(domain) + ":" + obj.args.port + "/" + xdomain + "agent.ashx\r\n"; } else { meshsettings += "MeshServer=local"; }
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=' + argentInfo.rname });
obj.parent.exeHandler.streamExeWithMeshPolicy({ platform: 'win32', sourceFileName: obj.parent.meshAgentBinaries[req.query.id].path, destinationStream: res, msh: meshsettings, peinfo: obj.parent.meshAgentBinaries[req.query.id].pe });
});
}
} else if (req.query.script != null) {
// Send a specific mesh install script back
var scriptInfo = obj.parent.meshAgentInstallScripts[req.query.script];
@ -1413,6 +1441,11 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
// Send meshcmd for a specific platform back
var argentInfo = obj.parent.meshAgentBinaries[req.query.meshcmd];
if ((argentInfo == null) || (obj.parent.defaultMeshCmd == null)) { res.sendStatus(404); return; }
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=meshcmd' + ((req.query.meshcmd <= 4) ? '.exe' : '') });
res.statusCode = 200;
obj.parent.exeHandler.streamExeWithJavaScript({ platform: argentInfo.platform, sourceFileName: argentInfo.path, destinationStream: res, js: new Buffer(obj.parent.defaultMeshCmd, 'utf8'), peinfo: argentInfo.pe });
/*
// Load the agent
obj.fs.readFile(argentInfo.path, function (err, agentexe) {
if (err != null) { res.sendStatus(404); return; }
@ -1423,6 +1456,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
tail.writeInt32BE(agentexe.length + meshcmdbuf.length + 8, 4);
res.send(Buffer.concat([agentexe, meshcmdbuf, tail]));
});
*/
} else if (req.query.meshaction != null) {
var domain = checkUserIpAddress(req, res);
if (domain == null) { res.sendStatus(404); return; }
@ -1773,3 +1807,4 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
return obj;
}