mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-12-23 21:55:52 -05:00
Improved executable binary handling
This commit is contained in:
parent
4106b322d6
commit
65f99a3c31
@ -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.
@ -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;
|
||||
|
@ -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
308
exeHandler.js
Normal 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);
|
||||
}
|
||||
}
|
100
meshcentral.js
100
meshcentral.js
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "meshcentral",
|
||||
"version": "0.1.2-u",
|
||||
"version": "0.1.2-s",
|
||||
"keywords": [
|
||||
"Remote Management",
|
||||
"Intel AMT",
|
||||
|
@ -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
|
||||
|
39
webserver.js
39
webserver.js
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user