Improved MeshCmd, added audit log support.

Ylian Saint-Hilaire committed Mar 20, 2018 at 17:48 UTC 2f3a02d1fddba8be596bb590811cf568ab8f7476
10 files changed +107 -78
agents/MeshCmd-signed.exe
Binary files a/agents/MeshCmd-signed.exe and b/agents/MeshCmd-signed.exe differ
agents/MeshCmd64-signed.exe
Binary files a/agents/MeshCmd64-signed.exe and b/agents/MeshCmd64-signed.exe differ
agents/meshcmd.js
+70 -38
@@ -91,7 +91,7 @@ function run(argv) {
91 //console.log('addedModules = ' + JSON.stringify(addedModules));
92 var actionpath = 'meshaction.txt';
93 if (args.actionfile != null) { actionpath = args.actionfile; }
94 - var actions = ['HELP', 'ROUTE', 'AMTLMS', 'AMTLOADWEBAPP', 'AMTLOADSMALLWEBAPP', 'AMTLOADLARGEWEBAPP', 'AMTCLEARWEBAPP', 'AMTSTORAGESTATE', 'AMTINFO', 'AMTVERSIONS', 'AMTHASHES', 'AMTSAVESTATE', 'AMTSCRIPT', 'AMTUUID', 'AMTCCM', 'AMTDEACTIVATE', 'SMBIOS', 'RAWSMBIOS', 'MESHCOMMANDER'];
94 + var actions = ['HELP', 'ROUTE', 'AMTLMS', 'AMTLOADWEBAPP', 'AMTLOADSMALLWEBAPP', 'AMTLOADLARGEWEBAPP', 'AMTCLEARWEBAPP', 'AMTSTORAGESTATE', 'AMTINFO', 'AMTVERSIONS', 'AMTHASHES', 'AMTSAVESTATE', 'AMTSCRIPT', 'AMTUUID', 'AMTCCM', 'AMTDEACTIVATE', 'SMBIOS', 'RAWSMBIOS', 'MESHCOMMANDER', 'AMTAUDITLOG'];
95
96 // Load the action file
97 var actionfile = null;
@@ -142,6 +142,7 @@ function run(argv) {
142 console.log('\r\nValid local or remote actions:');
143 console.log(' MeshCommander - Launch a local MeshCommander web server.');
144 console.log(' AmtUUID - Show Intel AMT unique identifier.');
145 + console.log(' AmtAuditLog - Show the Intel AMT audit log.');
146 console.log(' AmtLoadWebApp - Load MeshCommander in Intel AMT 11.6+ firmware.');
147 console.log(' AmtClearWebApp - Clear everything from Intel AMT web storage.');
148 console.log(' AmtStorageState - Show contents of the Intel AMT web storage.');
@@ -230,6 +231,14 @@ function run(argv) {
231 console.log('This action launched a local web server that hosts MeshCommander, a Intel AMT management console.');
232 console.log('\r\nPossible arguments:\r\n');
233 console.log(' --localport [port] Local port used for the web server, 3000 is default.');
234 + } else if (action == 'amtauditlog') {
235 + console.log('AmtAuditLog action will fetch the local or remote audit log. If used localy, no username/password is required. Example usage:\r\n\r\n meshcmd amtauditlog --host 1.2.3.4 --user admin --pass mypassword --tls --output audit.json');
236 + console.log('\r\nPossible arguments:\r\n');
237 + console.log(' --output [filename] The output file for the Intel AMT state in JSON format.');
238 + console.log(' --host [hostname] The IP address or DNS name of Intel AMT, 127.0.0.1 is default.');
239 + console.log(' --user [username] The Intel AMT login username, admin is default.');
240 + console.log(' --pass [password] The Intel AMT login password.');
241 + console.log(' --tls Specifies that TLS must be used.');
242 } else {
243 actions.shift();
244 console.log('Invalid action, usage:\r\n\r\n meshcmd help [action]\r\n\r\nValid actions are: ' + actions.join(', ') + '.');
@@ -373,15 +382,61 @@ function run(argv) {
382 // Deactivate CCM
383 debug(1, "Settings: " + JSON.stringify(settings));
384 deactivateCCM();
376 - } else if (settings.action == 'meshcommander') {
377 - // Start MeshCommander
385 + } else if (settings.action == 'meshcommander') { // Start MeshCommander
386 startMeshCommander();
387 + } else if (settings.action == 'amtauditlog') { // Read the Intel AMT audit log
388 + if (settings.hostname != null) {
389 + if ((settings.password == null) || (typeof settings.password != 'string') || (settings.password == '')) { console.log('No or invalid \"password\" specified, use --password [password].'); exit(1); return; }
390 + if ((settings.username == null) || (typeof settings.username != 'string') || (settings.username == '')) { settings.username = 'admin'; }
391 + } else { settings.hostname = '127.0.0.1'; }
392 + readAmtAuditLog();
393 } else {
394 console.log('Invalid \"action\" specified.'); exit(1); return;
395 }
396 }
397
398
399 +//
400 +// Intel AMT Audit Log
401 +//
402 +
403 +function readAmtAuditLog() {
404 + // See if MicroLMS needs to be started
405 + if ((settings.hostname == '127.0.0.1') || (settings.hostname.toLowerCase() == 'localhost')) {
406 + settings.noconsole = true; startLms(readAmtAuditLogEx);
407 + } else {
408 + readAmtAuditLogEx(9999);
409 + }
410 +}
411 +
412 +function readAmtAuditLogEx(x) {
413 + if (x == 9999) {
414 + var transport = require('amt-wsman-duk');
415 + var wsman = require('amt-wsman');
416 + var amt = require('amt');
417 + wsstack = new wsman(transport, settings.hostname, settings.tls ? 16993 : 16992, settings.username, settings.password, settings.tls);
418 + amtstack = new amt(wsstack);
419 + amtstack.GetAuditLog(readAmtAuditLogEx2);
420 + } else {
421 + osamtstack.GetAuditLog(readAmtAuditLogEx2);
422 + }
423 +}
424 +
425 +function readAmtAuditLogEx2(stack, response, status) {
426 + if (status != 200) {
427 + console.log('Unable to get audit log, status = ' + status + '.');
428 + } else {
429 + var out = '';
430 + for (var i in response) {
431 + var name = ((response[i].Initiator != '')?(response[i].Initiator + ': '):'')
432 + out += (response[i].Time + ' - ' + name + response[i].Event + '\r\n');
433 + }
434 + if (settings.output == null) { console.log(out); } else { var file = fs.openSync(settings.output, 'w'); fs.writeSync(file, new Buffer(out, 'utf8')); fs.closeSync(file); }
435 + }
436 + exit(1);
437 +}
438 +
439 +
440 //
441 // MeshCommander local web server
442 //
@@ -397,27 +452,18 @@ function startMeshCommander() {
452 var http = require('http');
453 webServer = http.createServer();
454 webServer.listen(settings.localport);
455 + webServer.wsList = {};
456 + webServer.wsListIndex = 0;
457 webServer.on('upgrade', function (req, socket, head) {
458 //console.log("WebSocket for " + req.url.split('?')[0]);
459 switch (req.url.split('?')[0]) {
460 case '/webrelay.ashx': // MeshCommander relay channel
461 var ws = socket.upgradeWebSocket();
462 socket.ws = ws;
463 + ws.wsIndex = ++webServer.wsListIndex;
464 + webServer.wsList[ws.wsIndex] = ws;
465 ws.pause();
466
408 - // When data is received from the web socket, forward the data into the associated TCP connection.
409 - // If the TCP connection is pending, buffer up the data until it connects.
410 - ws.on('data', function (data) {
411 - //console.log('Data relay --> ' + data.length + ': ' + data.toString() + '\r\n');
412 - ws.forwardclient.write(data); // Forward data to the associated TCP connection.
413 - });
414 -
415 - // If the web socket is closed, close the associated TCP connection.
416 - ws.on('close', function (req) {
417 - //console.log('Closed websocket.');
418 - if (ws.forwardclient) { try { ws.forwardclient.destroy(); } catch (e) { } }
419 - });
420 -
467 // We got a new web socket connection, initiate a TCP connection to the target Intel AMT host/port.
468 var webargs = parseUrlArguments(req.url);
469 if (webargs.p) { webargs.p = parseInt(webargs.p); }
@@ -429,36 +475,16 @@ function startMeshCommander() {
475 // If this is TCP (without TLS) set a normal TCP socket
476 var net = require('net');
477 ws.forwardclient = net.connect({ host: webargs.host, port: webargs.port })
478 + ws.forwardclient.on('connect', function () { this.pipe(this.ws); this.ws.pipe(this); });
479 ws.forwardclient.ws = ws;
433 - ws.forwardclient.on('connect', function () { this.ws.resume(); });
480 } else {
481 // If TLS is going to be used, setup a TLS socket
482 var tls = require('tls');
483 var tlsoptions = { host: webargs.host, port: webargs.port, secureProtocol: ((webargs.tls1only == 1) ? 'TLSv1_method' : 'SSLv23_method'), rejectUnauthorized: false };
438 - ws.forwardclient = tls.connect(tlsoptions, function () { this.ws.resume(); });
484 + ws.forwardclient = tls.connect(tlsoptions, function () { this.pipe(this.ws); this.ws.pipe(this); });
485 ws.forwardclient.ws = ws;
486 }
487
442 - // When we receive data on the TCP connection, forward it back into the web socket connection.
443 - ws.forwardclient.on('data', function (data) {
444 - //console.log('Data relay <-- ' + data.length + ': ' + data.toString() + '\r\n');
445 - try { this.ws.write(data); } catch (e) { }
446 - });
447 -
448 - // If the TCP connection closes, disconnect the associated web socket.
449 - ws.forwardclient.on('close', function () {
450 - //console.log('TCP/TLS disconnected.');
451 - try { this.ws.end(); } catch (e) { }
452 - try { this.end(); } catch (e) { }
453 - });
454 -
455 - // If the TCP connection causes an error, disconnect the associated web socket.
456 - ws.forwardclient.on('error', function (err) {
457 - //console.log('TCP/TLS disconnected with error', err);
458 - try { this.ws.end(); } catch (e) { }
459 - try { this.end(); } catch (e) { }
460 - });
461 -
488 break;
489 default:
490 socket.end();
@@ -1129,5 +1155,11 @@ function parseUrlArguments(url) {
1155 return r;
1156 }
1157
1158 +// Remove a element from a array
1159 +function removeItemFromArray(array, element) {
1160 + const index = array.indexOf(element);
1161 + if (index !== -1) { array.splice(index, 1); }
1162 +}
1163 +
1164 // Run MeshCmd
1165 try { run(process.argv); } catch (e) { console.log('ERROR: ' + e); }
agents/meshcore.js
+11 -7
@@ -75,10 +75,10 @@ function createMeshCore(agent) {
75 // Try to load up the MEI module
76 try {
77 var amtMeiLib = require('amt-mei');
78 - amtMeiConnected = 1;
78 amtMei = new amtMeiLib();
79 amtMei.on('error', function (e) { amtMeiLib = null; amtMei = null; sendPeriodicServerUpdate(); });
81 - amtMei.on('connect', function () { amtMeiConnected = 2; sendPeriodicServerUpdate(); });
80 + amtMeiConnected = 2;
81 + //amtMei.on('connect', function () { amtMeiConnected = 2; sendPeriodicServerUpdate(); });
82 } catch (e) { amtMeiLib = null; amtMei = null; amtMeiConnected = -1; }
83
84 // Try to load up the WIFI scanner
@@ -869,11 +869,11 @@ function createMeshCore(agent) {
869 break;
870 }
871 case 'selfinfo': { // Return self information block
872 - buildSelfInfo(function (info) { sendConsoleText(objToString(info, 0, ' '), sessionid); });
872 + buildSelfInfo(function (info) { sendConsoleText(objToString(info, 0, ' ', true), sessionid); });
873 break;
874 }
875 case 'args': { // Displays parsed command arguments
876 - response = 'args ' + objToString(args, 0, ' ');
876 + response = 'args ' + objToString(args, 0, ' ', true);
877 break;
878 }
879 case 'print': { // Print a message on the mesh agent console, does nothing when running in the background
@@ -1045,7 +1045,7 @@ function createMeshCore(agent) {
1045 case 'amt': { // Show Intel AMT status
1046 getAmtInfo(function (state) {
1047 var resp = 'Intel AMT not detected.';
1048 - if (state != null) { resp = objToString(state, 0, ' '); }
1048 + if (state != null) { resp = objToString(state, 0, ' ', true); }
1049 sendConsoleText(resp, sessionid);
1050 });
1051 break;
@@ -1053,7 +1053,11 @@ function createMeshCore(agent) {
1053 case 'netinfo': { // Show network interface information
1054 //response = objToString(mesh.NetInfo, 0, ' ');
1055 var interfaces = require('os').networkInterfaces();
1056 - response = objToString(interfaces, 0, ' ');
1056 + response = objToString(interfaces, 0, ' ', true);
1057 + break;
1058 + }
1059 + case 'netinfo2': { // Show network interface information
1060 + response = objToString(mesh.NetInfo, 0, ' ', true);
1061 break;
1062 }
1063 case 'wakeonlan': { // Send wake-on-lan
@@ -1215,7 +1219,7 @@ function createMeshCore(agent) {
1219 amtMei.getVersion(function (val) { amtMeiTmpState.Versions = {}; for (var version in val.Versions) { amtMeiTmpState.Versions[val.Versions[version].Description] = val.Versions[version].Version; } });
1220 amtMei.getProvisioningMode(function (result) { amtMeiTmpState.ProvisioningMode = result.mode; });
1221 amtMei.getProvisioningState(function (result) { amtMeiTmpState.ProvisioningState = result.state; });
1218 - amtMei.getEHBCState(function (result) { if (result.EHBC == true) { amtMeiTmpState.Flags += 1; } });
1222 + amtMei.getEHBCState(function (result) { if ((result != null) && (result.EHBC == true)) { amtMeiTmpState.Flags += 1; } });
1223 amtMei.getControlMode(function (result) { if (result.controlMode == 1) { amtMeiTmpState.Flags += 2; } if (result.controlMode == 2) { amtMeiTmpState.Flags += 4; } });
1224 //amtMei.getMACAddresses(function (result) { amtMeiTmpState.mac = result; });
1225 amtMei.getDnsSuffix(function (result) { if (result != null) { amtMeiTmpState.dns = result; } if (func != null) { func(amtMeiTmpState); } });
agents/modules_meshcmd/amt-mei.js
-1
@@ -18,7 +18,6 @@ var Q = require('queue');
18 function amt_heci() {
19 var emitterUtils = require('events').inherits(this);
20 emitterUtils.createEvent('error');
21 - emitterUtils.createEvent('connect');
21
22 var heci = require('heci');
23
agents/modules_meshcmd/amt.js
+3 -3
@@ -633,7 +633,7 @@ function AmtStackCreateService(wsmanStack) {
633 2003: 'Security Audit Log Enabled',
634 2004: 'Security Audit Log Exported',
635 2005: 'Security Audit Log Recovered',
636 - 2100: 'Intel&reg; ME Time Set',
636 + 2100: 'Intel(R) ME Time Set',
637 2200: 'TCPIP Parameters Set',
638 2201: 'Host Name Set',
639 2202: 'Domain Name Set',
@@ -742,12 +742,12 @@ function AmtStackCreateService(wsmanStack) {
742 }
743 if (x['InitiatorType'] == 2) {
744 // Local
745 - x['Initiator'] = '<i>Local</i>';
745 + x['Initiator'] = 'Local';
746 ptr = 5;
747 }
748 if (x['InitiatorType'] == 3) {
749 // KVM Default Port
750 - x['Initiator'] = '<i>KVM Default Port</i>';
750 + x['Initiator'] = 'KVM Default Port';
751 ptr = 5;
752 }
753
agents/modules_meshcore/amt-lme.js
+9 -5
@@ -290,11 +290,8 @@ function lme_heci(options) {
290 var notify = null;
291 try { notify = xmlParser.ParseWsman(httpData); } catch (e) { }
292
293 - // Translate the event
294 - var notifyString = _lmsNotifyToString(notify);
295 -
293 // Event the http data
297 - if (notify != null) { this.LMS.emit('notify', notify, channel.options, notifyString); }
294 + if (notify != null) { this.LMS.emit('notify', notify, channel.options, _lmsNotifyToString(notify), _lmsNotifyToCode(notify)); }
295
296 // Send channel close
297 var buffer = Buffer.alloc(5);
@@ -437,6 +434,13 @@ function parseHttp(httpData) {
434 return null;
435 }
436
437 +function _lmsNotifyToCode(notify) {
438 + if ((notify == null) || (notify.Body == null) || (notify.Body.MessageID == null)) return null;
439 + var msgid = notify.Body.MessageID;
440 + try { msgid += '-' + notify.Body.MessageArguments[0]; } catch (e) { }
441 + return msgid;
442 +}
443 +
444 function _lmsNotifyToString(notify) {
445 if ((notify == null) || (notify.Body == null) || (notify.Body.MessageID == null)) return null;
446 var msgid = notify.Body.MessageID;
@@ -520,7 +524,7 @@ var lmsEvents = {
524 "iAMT0055-0": "User Notification Alert - Provisioning state change notification - Pre-configuration.",
525 "iAMT0055-1": "User Notification Alert - Provisioning state change notification - In configuration.",
526 "iAMT0055-2": "User Notification Alert - Provisioning state change notification - Post-configuration.",
523 - "iAMT0055-3": "User Notification Alert - Provisioning state change notification - unprovision process has started.",
527 + "iAMT0055-3": "User Notification Alert - Provisioning state change notification - Unprovision process has started.",
528 "iAMT0056": "User Notification Alert - System Defense change notification.",
529 "iAMT0057": "User Notification Alert - Network State change notification.",
530 "iAMT0058": "User Notification Alert - Remote Access change notification.",
agents/modules_meshcore/amt-mei.js
+8 -15
@@ -18,24 +18,20 @@ var Q = require('queue');
18 function amt_heci() {
19 var emitterUtils = require('events').inherits(this);
20 emitterUtils.createEvent('error');
21 - emitterUtils.createEvent('connect');
21
22 var heci = require('heci');
23
24 this._ObjectID = "pthi";
25 this._rq = new Q();
27 - this._setupPTHI = function _setupPTHI()
28 - {
26 + this._setupPTHI = function _setupPTHI() {
27 this._amt = heci.create();
28 this._amt.BiosVersionLen = 65;
29 this._amt.UnicodeStringLen = 20;
30
31 this._amt.Parent = this;
32 this._amt.on('error', function _amtOnError(e) { this.Parent.emit('error', e); });
35 - this._amt.on('connect', function _amtOnConnect()
36 - {
37 - this.on('data', function _amtOnData(chunk)
38 - {
33 + this._amt.on('connect', function _amtOnConnect() {
34 + this.on('data', function _amtOnData(chunk) {
35 //console.log("Received: " + chunk.length + " bytes");
36 var header = this.Parent.getCommand(chunk);
37 //console.log("CMD = " + header.Command + " (Status: " + header.Status + ") Response = " + header.IsResponse);
@@ -47,14 +43,12 @@ function amt_heci() {
43 params.unshift(header);
44 callback.apply(this.Parent, params);
45
50 - if(this.Parent._rq.isEmpty())
51 - {
46 + if (this.Parent._rq.isEmpty()) {
47 // No More Requests, we can close PTHI
48 this.Parent._amt.disconnect();
49 this.Parent._amt = null;
50 }
56 - else
57 - {
51 + else {
52 // Send the next request
53 this.write(this.Parent._rq.peekQueue().send);
54 }
@@ -79,10 +73,9 @@ function amt_heci() {
73 var header = Buffer.from('010100000000000000000000', 'hex');
74 header.writeUInt32LE(arguments[0] | 0x04000000, 4);
75 header.writeUInt32LE(arguments[1] == null ? 0 : arguments[1].length, 8);
82 - this._rq.enQueue({ cmd: arguments[0], func: arguments[2], optional: args , send: (arguments[1] == null ? header : Buffer.concat([header, arguments[1]]))});
76 + this._rq.enQueue({ cmd: arguments[0], func: arguments[2], optional: args, send: (arguments[1] == null ? header : Buffer.concat([header, arguments[1]])) });
77
84 - if(!this._amt)
85 - {
78 + if (!this._amt) {
79 this._setupPTHI();
80 this._amt.connect(heci.GUIDS.AMT, { noPipeline: 1 });
81 }
@@ -94,7 +87,7 @@ function amt_heci() {
87 this.sendCommand(26, null, function (header, fn, opt) {
88 if (header.Status == 0) {
89 var i, CodeVersion = header.Data, val = { BiosVersion: CodeVersion.slice(0, this._amt.BiosVersionLen), Versions: [] }, v = CodeVersion.slice(this._amt.BiosVersionLen + 4);
97 - for (i = 0; i < CodeVersion.readUInt32LE(this._amt.BiosVersionLen) ; ++i) {
90 + for (i = 0; i < CodeVersion.readUInt32LE(this._amt.BiosVersionLen); ++i) {
91 val.Versions[i] = { Description: v.slice(2, v.readUInt16LE(0) + 2).toString(), Version: v.slice(4 + this._amt.UnicodeStringLen, 4 + this._amt.UnicodeStringLen + v.readUInt16LE(2 + this._amt.UnicodeStringLen)).toString() };
92 v = v.slice(4 + (2 * this._amt.UnicodeStringLen));
93 }
views/default.handlebars
+5 -9
@@ -563,15 +563,7 @@
563 <div id="d7meshkvm">
564 <h4 style="width:100%;border-bottom:1px solid gray">Mesh Agent Remote Desktop</h4>
565 <div style="margin:3px 0 3px 0">
566 - <select id="d7bitmapquality" style="float:right;width:200px;height:20px" dir="rtl">
567 - <option value=50>50%</option>
568 - <option value=40>40%</option>
569 - <option selected=selected value=30>30%</option>
570 - <option value=20>20%</option>
571 - <option value=10>10%</option>
572 - <option value=5>5%</option>
573 - <option value=1>1%</option>
574 - </select>
566 + <select id="d7bitmapquality" style="float:right;width:200px;height:20px" dir="rtl"></select>
567 <div style="height:20px">Quality</div>
568 </div>
569 <div style="margin:3px 0 3px 0">
@@ -3075,9 +3067,13 @@
3067 }
3068
3069 function applyDesktopSettings() {
3070 + var r = '', ops = (features & 512)?[100,80,50,40,30,20,10,5,1]:[50,40,30,20,10,5,1];
3071 + for (var i in ops) { r += '<option value=' + ops[i] + '>' + ops[i] + '%</option>'; }
3072 + QH('d7bitmapquality', r);
3073 d7desktopmode.value = desktopsettings.encoding;
3074 d7showfocus.checked = desktopsettings.showfocus;
3075 d7showcursor.checked = desktopsettings.showmouse;
3076 + d7bitmapquality.value = 40; // Default value
3077 d7bitmapquality.value = desktopsettings.quality;
3078 d7bitmapscaling.value = desktopsettings.scaling;
3079 QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (desktop.state != 0) && (desktopsettings.showfocus));
webserver.js
+1
@@ -682,6 +682,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
682 if ((obj.parent.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName != 'un-configured') && (obj.args.lanonly != true)) { features += 64; } // Email invites
683 if (obj.args.webrtc == true) { features += 128; } // Enable WebRTC (Default false for now)
684 if (obj.args.clickonce !== false) { features += 256; } // Enable ClickOnce (Default true)
685 + if (obj.args.allowhighqualitydesktop == true) { features += 512; } // Enable AllowHighQualityDesktop (Default false)
686
687 // Send the master web application
688 if ((!obj.args.user) && (obj.args.nousers != true) && (nologout == false)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button