Skip to content

Commit 301dc6b

Browse files
Merge pull request #102 from kirk-sayre-work/master
Version 1.9.27
2 parents 4d09755 + 9b48e3c commit 301dc6b

10 files changed

+139
-10
lines changed

analyze.js

+21-3
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ function hideStrs(s) {
122122
var resetSlashes = false;
123123
var justStartedRegex = false;
124124
var inSquareBrackets = false;
125+
var skippedSpace = false;
126+
125127
s = stripSingleLineComments(s);
126128
// For debugging.
127129
var window = " ";
@@ -186,7 +188,7 @@ function hideStrs(s) {
186188
// Dropping /* */ comments, so don't save current char.
187189

188190
// Out of comment?
189-
if ((prevChar == "*") && (currChar == "/")) {
191+
if ((prevChar == "*") && (currChar == "/") && !skippedSpace) {
190192
inComment = false;
191193
// Handle FP single line comment detection for things
192194
// like '/* comm1 *//* comm2 */'.
@@ -199,6 +201,10 @@ function hideStrs(s) {
199201
if (currChar != " ") {
200202
prevPrevChar = prevChar;
201203
prevChar = currChar;
204+
skippedSpace = false;
205+
}
206+
else {
207+
skippedSpace = true;
202208
}
203209
continue;
204210
}
@@ -419,10 +425,22 @@ function extractCode(code) {
419425
//
420426
// /*@cc_on
421427
// @if(1) ... @end@*/
428+
//
429+
// /*@cc_on @*//*@if (1)
430+
// ... @end @*/
422431
const commentPat = /\/\*(?:@cc_on\s+)?@if\s*\([^\)]+\)(.+?)@(else|end)\s*@\s*\*\//s
423-
const codeMatch = code.match(commentPat);
432+
var codeMatch = code.match(commentPat);
424433
if (!codeMatch) {
425-
return code;
434+
const commentPat1 = /\/\*\s*@cc_on\s*@\*\/\s*\/\*\s*@if\s*\([^\)]+\)(.+?)@(else|end)\s*@\s*\*\//s;
435+
codeMatch = code.match(commentPat1);
436+
if (!codeMatch) {
437+
// /*@cc_on\n...@*/
438+
const commentPat2 = /\/\*\s*@cc_on *\r?\n(.+?)\r?\n@\*\//;
439+
codeMatch = code.match(commentPat2);
440+
if (!codeMatch) {
441+
return code;
442+
}
443+
}
426444
}
427445
var r = codeMatch[1];
428446
lib.info("Extracted code to analyze from conditional JScript comment.");

boilerplate.js

+38-3
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ const dummyEvent = {
5050
key: 97, // "a"
5151

5252
stopPropagation: function() {},
53+
preventDefault: function() {},
54+
composedPath: function() {
55+
return {
56+
includes: function() { return false; },
57+
};
58+
},
5359
};
5460

5561
// Handle Blobs. All Blob methods in the real Blob class for dumping
@@ -451,6 +457,22 @@ function __createElement(tag) {
451457
// Call the onerror handler.
452458
func();
453459
},
460+
set value(txt) {
461+
this.val = txt;
462+
},
463+
get value() {
464+
return this.val;
465+
},
466+
get href() {
467+
if (typeof(this._href) === "undefined") this._href = 'http://mylegitdomain.com:2112/and/i/have/a/path.php#tag?var1=12&ref=otherlegitdomain.moe';
468+
return this._href;
469+
},
470+
set href(url) {
471+
url = url.replace(/\r?\n/g, "");
472+
this._href = url;
473+
logIOC('HREF Location', {url}, "The script changed location.href.");
474+
logUrl('HREF Location', url);
475+
},
454476
// Not ideal or close to correct, but sometimes needs a parentNode field.
455477
parentNode: __fakeParentElem,
456478
log: [],
@@ -567,7 +589,10 @@ __fakeParentElem = __createElement("FakeParentElem");
567589
// Stubbed global navigator object.
568590
const navigator = {
569591
userAgent: 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.2; WOW64; Trident/6.0; .NET4.0E; .NET4.0C; .NET CLR 3.5.30729; .NET CLR 2.0.50727; .NET CLR 3.0.30729; Tablet PC 2.0; InfoPath.3)',
570-
clipboard: {
592+
clipboard: {
593+
writeText : function(txt) {
594+
logIOC('Clipboard', txt, "The script pasted text into the clipboard.");
595+
},
571596
},
572597
connection: {
573598
},
@@ -589,8 +614,7 @@ const navigator = {
589614
},
590615
keyboard: {
591616
},
592-
language: {
593-
},
617+
language: "english",
594618
languages: {
595619
},
596620
locks: {
@@ -728,6 +752,7 @@ var document = {
728752
// got nothing to return. Make up some fake element and hope for the best.
729753
var r = __createElement(id);
730754
r.val = jqueryVals[id];
755+
if (typeof(r.val) == "undefined") r.val = "";
731756
return r;
732757
},
733758
documentElement: {
@@ -762,6 +787,7 @@ var document = {
762787
eval(extractJSFromHTA(node));
763788
},
764789
getElementsByTagName: __getElementsByTagName,
790+
getElementsByName: __getElementsByTagName,
765791
getElementsByClassName: __getElementsByTagName,
766792
createDocumentFragment: function() {
767793
return __createElement("__doc_fragment__");
@@ -1216,6 +1242,10 @@ var exports = {};
12161242
function fetch(url, data) {
12171243
lib.logIOC("fetch", {url: url, data: data}, "The script fetch()ed a URL.");
12181244
lib.logUrl("fetch", url);
1245+
return {
1246+
ok : true,
1247+
json : function() { return "1"; },
1248+
};
12191249
};
12201250

12211251
// Image class stub.
@@ -1310,3 +1340,8 @@ var history = {
13101340
pushState: function() {},
13111341
};
13121342

1343+
// Fake sessionStorage object.
1344+
var sessionStorage = {
1345+
getItem: function() {},
1346+
setItem: function() {},
1347+
};

emulator/FileSystemObject.js

+8
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,14 @@ function FileSystemObject() {
226226
var r = new ProxiedFile(filename);
227227
return r;
228228
};
229+
this.getfilename = function(filename) {
230+
filename = "" + filename;
231+
const i = filename.lastIndexOf("\\");
232+
if (i > 0) {
233+
filename = filename.slice(i + 1);
234+
}
235+
return filename;
236+
};
229237
this.getfileversion = () => "";
230238
this.getfolder = (str) => new ProxiedFolder(str);
231239
this.getspecialfolder = function(id) {

emulator/WBEMScriptingSWBEMLocator.js

+35-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,25 @@
11
const lib = require("../lib");
22
const enumerator = require("./Enumerator");
3+
const argv = require("../argv.js").run;
4+
5+
// Fake OS language can be set with the --fake-language option.
6+
// Default language is English.
7+
var langCode = 1033;
8+
if (argv["fake-language"]) {
9+
10+
// Were we given a supported language?
11+
const langStr = argv["fake-language"];
12+
const langs = {
13+
'spanish' : 2058,
14+
'english' : 1033,
15+
'portuguese' : 1046,
16+
};
17+
langCode = langs[langStr];
18+
if (!langCode) {
19+
lib.error("Language '" + langStr + "' not supported.");
20+
process.exit(4);
21+
};
22+
}
323

424
// Fake SWBEMService.instancesof results.
525

@@ -51,7 +71,15 @@ _fake_win32_operatingsystem = {
5171
"OperatingSystemSKU" : "4",
5272
"Organization" : "USERS",
5373
"OSArchitecture" : "64-bit",
54-
"OSLanguage" : "1033",
74+
// US English
75+
//"OSLanguage" : "1033",
76+
// Mexican Spanish
77+
get OSLanguage() {
78+
lib.logIOC("SWBEMService", langCode, "Read Win32_OperatingSystem.OSLanguage.");
79+
return langCode;
80+
},
81+
// International Spanish
82+
//"OSLanguage" : "3082",
5583
"OSProductSuite" : "256",
5684
"PAEEnabled" : "",
5785
"PlusProductID" : "",
@@ -89,6 +117,12 @@ function VirtualSWBEMServices() {
89117
};
90118
};
91119

120+
this.execquery = function(query) {
121+
lib.logIOC("SWBEMService", query, "Executed SWBEMService query '" + query + "'.");
122+
if (query.indexOf("Win32_OperatingSystem") > -1) return [_fake_win32_operatingsystem];
123+
return [];
124+
};
125+
92126
this.get = function(item) {
93127
return {
94128
spawninstance_ : function() {

emulator/WScriptNetwork.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
const lib = require("../lib");
2+
const argv = require("../argv.js").run;
3+
4+
var fakeUserDomain = "";
5+
if (argv["fake-domain"]) {
6+
fakeUserDomain = argv["fake-domain"];
7+
}
28

39
class DriveInfo {
410
constructor(driveLetters) {
@@ -17,7 +23,8 @@ function WScriptNetwork() {
1723
this.enumprinterconnections = () => [{
1824
foo: "bar",
1925
}];
20-
this.userdomain = "";
26+
this.userdomain = fakeUserDomain;
27+
this.username = "harvey_danger";
2128
this.mapnetworkdrive = function(letter, path) {
2229
lib.info(`Script maps network drive ${letter} to path ${path}`);
2330
lib.logUrl("map", ("https:" + path).replace("@", ":").replace(/\\/g, "/"));

emulator/XMLHTTP.js

+16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
const lib = require("../lib");
22
const argv = require("../argv.js").run;
33

4+
var _fileCheckCount = 0;
5+
var _lastUrl = "";
46
function XMLHTTP() {
57
this.headers = {};
68
this.onreadystatechange = () => {};
@@ -20,7 +22,21 @@ function XMLHTTP() {
2022
this.method = method;
2123
this.readystate = 1;
2224
this.statustext = "OPENED";
25+
lib.logUrl('XMLHTTP', url);
26+
lib.logIOC("XMLHTTP", {url: url}, "The script opened URL " + url + " with XMLHTTP");
27+
28+
// Try to break infinite network loops by exiting if we do
29+
// many open()s.
30+
_fileCheckCount++;
31+
if (argv["limit-file-checks"]) {
32+
if ((_fileCheckCount > 100) && (url == _lastUrl)) {
33+
lib.info("Possible infinite network loop detected. Exiting.");
34+
process.exit(0);
35+
}
36+
}
37+
_lastUrl = url;
2338
};
39+
this.responsetext = "console.log('The script executed JS returned from a C2 server.')";
2440
this.setrequestheader = function(key, val) {
2541
key = key.replace(/:$/, ""); // Replace a trailing ":" if present
2642
this.headers[key] = val;

flags.json

+10
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,16 @@
8282
"type": "String",
8383
"description": "Fake file name to use for the sample being analyzed. Can be a full path or just the file name to use. If you have '\\' in the path escape them as '\\\\' in this command line argument value (ex. --fake-sample-name=C:\\\\foo\\\\bar.js)."
8484
},
85+
{
86+
"name": "fake-language",
87+
"type": "String",
88+
"description": "Specify the language code to return for Win32_OperatingSystem.OSLanguage. Supported values are 'spanish', 'english', and 'portuguese'."
89+
},
90+
{
91+
"name": "fake-domain",
92+
"type": "String",
93+
"description": "Specify the user domain to return for WScript.Network.UserDomain."
94+
},
8595
{
8696
"name": "fake-download",
8797
"type": "Boolean",

lib.js

+1
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ module.exports = {
414414
}
415415

416416
const filename = getUUID();
417+
command = "" + command;
417418
logIOC("Run", {command}, "The script ran the command '" + command + "'.");
418419
logSnippet(filename, {as: "WScript code"}, command);
419420
process.send("expect-shell-error");

package-lock.json

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "box-js",
3-
"version": "1.9.26",
3+
"version": "1.9.27",
44
"description": "A tool for studying JavaScript malware.",
55
"dependencies": {
66
"acorn": ">=8.8.0",

0 commit comments

Comments
 (0)