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® 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