macOS High Sierra, AAPL's latest OS offering, seems to be "High" on something ever since it's release. Earlier in November of last year, High Sierra users were greeted with the news that anyone could login as root after clicking on the login button several times. Following on the heels of that announcement, a couple weeks ago, users were again alerted to another issue, that saw a user with administrative privileges being able to unlock the App Store menu in System preferences with any password. This latter issue piqued my interest, and I decided to take a look to see if I could understand the underlying flaw. This blog post chronicles that journey.
App Store Preferences |
In order to understand the bug, it is important that we first examine how the OS handles authentication. For this, we first turn our attention to the Pluggable Authentication Module(PAM). This is a standard UN*X library which aims to abstract and modularize the UN*X authentication API's.
The main PAM module used by macOS is /usr/lib/pam_opendirectory.so.2. The library links with the OpenDirectory.framework, which interfaces with the /usr/libexec/opendirectoryd daemon. The daemon serves as a focal point for all directory requests in the system. The configuration for this daemon is maintained in the /System/Library/OpenDirectory/. This directory, contains a Modules sub-directory which further contains plugins for various types of directory implementations.
Of importance to us is the /System/Library/OpenDirectory/Modules/PlistFile.bundle, which enables access to directory data stored in AAPL's format of property lists(.plist). The corresponding binary is found in /System/Library/OpenDirectory/Modules/PlistFile.bundle/Contents/MacOS and is aptly named PlistFile.
Updating App Store Preferences
With the groundwork out of the way, let's look at a normal authentication flow. The bug was not present on High Sierra 10.3, and so I started my investigations there.
macho-reverser:opend macho-reverser$ jtool -l opendirectoryd_10_3
LC 09: LC_VERSION_MIN_MACOSX Minimum OS X version: 10.13.0
LC 10: LC_SOURCE_VERSION Source Version: 483.1.4.0.0
Unlocking App Store preferences and setting a break point on Password resulted in the following hit:
Password Breakpoint hit |
Helper Methods |
Based on the above, the method takes three parameters. Note, on x86_x64 architectures, the first six parameters are passed in registers RDI, RSI, RDX, RCX, R8 and R9 respectively. If there are more than six, the program's stack is used for any additional ones. Setting a breakpoint at the function's entry point and examining the parameters reveals the following:
sub_18F1 arg 3 |
dscl queries |
sub_826B
Moving on, this method, seems to be where the action is, and we again start the analysis by examining its arguments. To set the breakpoint, we determine the ASLR slide as follows:
ASLR Slide |
sub_826B offset |
Function parameters |
sub_591C function call |
sub_591C paramter |
Generate key from CCKeyDerivationPBKDF |
Comparing user supplied value with stored credentials |
That is basically the flow for unlocking the App Store Preferences Pane. Also, to kick start this entire process, it seems that opendirectoryd registers a number of handlers for various requests:
API handlers |
The Bug on High Sierra(10.3.2)
With all that said, on High Sierra(10.3.2) none of this happens. In other words, setting a breakpoint on odm_handle_api_authentication or even VerifyPassword produces not a single hit. Simply put, no validation takes place. It's almost as if the call was removed altogether. However, on High Sierra(10.3.3) - where the bug has been fixed - things go back to normal and once again the odm_RecordVerifyPassword method is called. Go figure!
Conclusion
In the end it seems somewhere along the line there was a breakdown.This resulted in the password verification code block not being called at all. I am not sure of where the exact call into opendirectoryd occurs and that may be worth a further look.....
Hope you found the post interesting. As always, comments/feedback welcome.