Blog Archives
yes, enable the root user if you’re on High Sierra
Update: There’s a security update available in the App Store now that mitigates this risk. It should be applied by all High Sierra users as a matter of urgency.
Today has been all about a monumental security flaw in High Sierra which allows anyone to log in to a mac and immediately become the root user without a password at all.
If you haven’t yet seen the news, check out the 30-second video above. If you’re not on High Sierra, no need to worry.
Although there are conflicting reports of exactly under what conditions the exploit can be triggered, it seems that in most cases two attempts are required to escalate user privileges. The first time enables the root user with the password that you do or do not put in the password field (i.e., it’ll accept a blank password). The second time is using those credentials to unlock whatever it is you want to unlock (in the video, only 1 attempt is shown as I had already ran the exploit once prior to making the video). There also seems to be conflicting reports about whether the flaw can be exploited remotely. What does seem certain is that malicious 3rd party applications could programmatically use it to escalate privileges for themselves, so it’s important to make sure you take the proper precautions to deal with this flaw until Apple patches it with an update.
Alas, with so much excitement, it seems some people are getting confused about exactly what needs to be done to avoid falling victim to this security flaw. The answer is not, as has been mistakenly suggested in some quarters, to disable the root user, but quite the reverse: you need to enable it.
The one thing that stops the flaw from being exploited is having the root user already enabled and set with a strong password.
By default, macOS ships with the root user disabled, so unless you (or someone who administrates your mac) has enabled it at some point, it won’t be set. If you’re not sure, this AppleScript will quickly tell you the status of the root user:

Update: further testing on 10.13 shows that the root user may be enabled without writing a ShadowHash entry to dscl. In that case, the script would incorrectly indicate root was disabled. Thus, to be certain, the best way to check is to follow the instructions in the apple support article linked to below.
If you find the root user is disabled, then go and enable it by following Apple’s instructions here:
https://support.apple.com/en-us/HT204012
Be sure to use a strong password of at least 14 characters or more. You can save the password if you want, but it doesn’t really matter much if you forget it. There’s really never any need for an admin user to require the root user at all, and there are other ways to get root privileges safely through the Terminal if needs be.
why malware loves auto login (and why you shouldn’t)

Whenever I talk to people about the dangers of having their mac set to login automatically without requiring a password, I’m often waved away as an old worryguts. “I’m the only user on my mac”, they say, and “My mac is unlikely to get stolen”.
These optimistic dismissals may turn out to be true or false, but aren’t really relevant to the main security issue. Auto login presents a threat to anyone connecting to the internet.
To see why this is so, let’s look at how auto login works. First of all, the user enables auto login through System Preferences’ ‘Users & Groups’ pane. Open the pane and click on the Login Options item at the bottom of the sidebar (see the screenshot above). Choose a user from the ‘Automatic login:’ pop-up menu. You’ll need to provide the account password.
Where it gets interesting is what macOS does next with that information. You might perhaps think it secures that information safely in your Keychain, but that wouldn’t work at all. Your Keychain needs a user password to unlock it, so auto login can hardly unlock your Keychain to get the stored password out. No, it needs to be stored somewhere else that can be accessed when the computer starts up.
That place is in the hidden folder /etc/, and specifically in a file called kcpassword. This is outside of any user’s Home directory, so the system doesn’t need a user password to access it.
However, if you try to open that file to read it yourself (we’ll do this shortly, hold on), you’ll find you can’t read it without providing your admin password (the boot process already runs as root, so it doesn’t have this problem). For reasons we’ll see in a moment, you’d be mistaken to take much comfort from that in terms of security, but lets stick with /etc/kcpassword for a while first.
Now here’s something anybody can do, with or without elevated privileges (and by ‘anybody’ here we also mean ‘any process’): test to see if /etc/kcpassword exists. The file is only created when auto login is enabled, and it’s deleted when it’s turned off; thus, existence of the file is a simple way to check whether a mac has auto login enabled without needing to go through a user’s System Preferences pane.
A malicious program, for example, might run some code like this to test whether a target system is set to auto login:

If the file does exist, then passwordExploit will be ‘TRUE’, and all the attacker has to do now is execute code to read and parse the file:

We can take a look at what the file contains easily enough from the command line. Assuming you have auto login enabled (or you could just enable it temporarily for fun if you want to play along), try
sudo cat /etc/kcpassword
As we’ve already seen, you’ll need a password to see the password, but this isn’t a problem that’s going to phase a malware author, and nor does it mean that the malware author won’t be interested in the prize. Again, hold those thoughts while we look at what’s inside the kcpassword file.
Here’s what mine contains:

Hmm, goobledygook, it seems. Encrypted nonsense that surely takes a lifetime to break, no? Far from it. Be ready to behold the masterpiece of wisdom, humour or nearest book title that is your password by pasting this into the command line:
sudo ruby -e'key=[125,137,82,35,210,188,221,234,163,185,31];
IO.read("/etc/kcpassword").bytes.each_with_index{|b,i|break if key.include?(b);
print [b^key[i%key.size]].pack("U*")}'
Tradaa! And here’s my inglorious password: k33p_out_th3_badi3z.

How is that possible? No, it’s not some secret new encryption breaking technique. The fact is the kcpassword is not encrypted at all, it’s XOR’d. To see the basic idea, take the first character, ‘?’. The asci code for ‘?’ is 63 (this is for demonstration purposes only; the actual XOR’ing is done in hexadecimal rather than the simpler decimal used in this example). That number in binary is 00111111. To XOR it, all I have to do is provide another binary number, lets say 84, which is 01010100, and apply the rule that for each equivalent bit in the two numbers, if the bits are the same we output a zero, and if they are different we output a 1. Thus, ‘?’ (63) ^ ’T’ (84) comes out like so:
00111111 (asci 63 = ‘?’ – encoded password character)
01010100 (asci 84 = ’T’ – XOR mask)
—————
01101011 (asci 107 = ‘k’ – plain text password character)
Now, if we go through each of the characters in my encoded (note, not ‘encrypted’) password, and apply the correct XOR mask for each, we can reveal the password — note the mask for the first character in my demo was 84, but each character is XOR’d with a different mask — and that’s precisely what the Ruby script we used above did (again, noting that the masks are in hex rather than decimal).
OK, now you may have some questions. 🙂 The first is probably: do Apple KNOW THIS!? Oh sure, of course! Nobody uses XOR for security, at least not like this, but you can’t blame Apple that much. It’s a reasonable assumption on their behalf that if a user sets their computer to auto login, security isn’t high on their priority list. The second reason why Apple probably feel unconcerned by this is that you need a password to see the password, so surely there’s no real danger?
That may have made sense 30 or 40 years ago when the only people who had admin passwords were, well, administrators, and when processes couldn’t easily exfiltrate data via the internet. It doesn’t make much sense nowadays in a computing environment where people download software from unknown sources which immediately asks the user for a password to install and then phones home. Users rarely say ‘no’ to such requests (after all, they downloaded the software because they wanted to run it, right?) and almost certainly have no idea what processes run with admin privileges as a result.
It would also be a mistake to believe that, in this scenario, a piece of malware that has just tricked the user into providing an admin password to install would not need or want to run the exploit against the kcpassword file. Far from it.
Usually, when apps ask for your password to install, they don’t get to see the password directly. Some malware will present a false dialog to do this, but most will take the easier (and less suspicious) route of letting macOS mediate the process. A legitimate password dialog box is actually from macOS, and it only grants privileges to the requesting app; it does not give them the password in plain text. But the plain text password is the holy grail of malware persistence: as powerful as elevated privileges are, they may also be temporary, limited, and revoked; they also can’t be stored or easily transferred.
To see why this matters, consider a piece of malware that gains elevated privileges through the OS in the way described, but not the password. If the malware is discovered, it can be removed. If the attacker wants to strike again, they have to fool the same person into the same trick of installing their software as they did before. In a world where we’re all increasingly ‘once-bitten twice shy’ when it comes to computer security, that’s not a trivial task.
On the other hand, if the attacker gains the plain-text password from the first attack, this can either be stored elsewhere on the victim’s computer (somewhere that doesn’t need privileges to be accessed) or even sent back to the attacker’s remote command and control server. In that case, even deleting the malware isn’t going stop the attacker (indeed the attacker may delete the malware themselves to avoid detection!). All they have to do is connect to your mac remotely, input your admin password and they’re straight back in again.
I hope it’s clear from this that due to the weak obfuscation of the kcpassword file, auto login is a tremendously bad idea. It doesn’t matter whether your mac is locked in a one-person vestibule with round-the-clock guards. It’s when your mac is in use that it’s vulnerable.
Moral of the tale: disable auto login, folks, especially those of you that just enabled it to play along with this post!
Acknowledgements:
Ruby script: http://osxnotes.net/passwords.html
Background info: OSX Incident Response – Jaron Bradley
how to: check for Sparkle vulnerability

[updated Mon 15th:]
Here’s what we know about the widely-reported vulnerability found in Sparkle so far:
1. It requires a version of Sparkle earlier than 1.13
AND
2.1 It requires the SUFeedURL address to be an unencrypted http address AND/OR
2.2 the release notes address to be an unencrypted http address.
Condition 1 and one (or more) of conditions 2 need to be true to make the exploit possible. You can check to see if condition 2.1 is true for many apps on your system with the following procedure:
1. Control-click on the app in the Finder
2. Choose ‘Show Package Contents’
3. Navigate to /Contents/Info.plist
4. Hit the space bar to open in quick look, scroll down for the SUFeedURL field (it won’t have one if it doesn’t use Sparkle). The field will show you whether the address is https or not.
To make life easier, you can run this script in the AppleScript Editor (/Applications/Utilites/Script Editor.app) to do the job for you.
#script version 1.64
#regression to 1.52 and then
#added: now includes apps that do not have SUFeedURL key in plist and reports their Sparkle version number
#added: borrowed Bill Cheeseman's idea of using choose list and offering to launch the app
#added: borrowed reverse_offset handler from Nigel Garvey's post on MacScripter
#changed: test if Sparkle is < 1.13.1 first
#shows the Sparkle version number for each entry in the list
#added logic for opening prefPanes if chosen from the list
#changed the mdfind command to improve speed
#searches for keys of the form "SUFeedURL*" rather than just "SUFeedURL"
on extractSUFeedURL(aRecord)
set aRec to “httpx”
try
set aRec to item 1 of aRecord
on error errorMessage
set aRec to errorMessage
set aRec to my parseErrorMsg(aRec)
end try
return aRec
end extractSUFeedURL
on parseErrorMsg(aErr)
set what to “SUFeedURL” –define the full or partial record name you’re trying to find
if aErr contains what then
set theStart to offset of what in aErr
set thisString to text theStart thru -1 of aErr
set theEnd to offset of “,” in thisString
set subString to text 1 thru theEnd of thisString
–log subString –see the record name and its value in Script Editor’s Messages pane
return subString
end if
end parseErrorMsg
on reverse_offset(d, t)
set astid to AppleScript’s text item delimiters
set AppleScript’s text item delimiters to d
set ro to (count t) – (count text item -1 of t)
set AppleScript’s text item delimiters to astid
return ro
end reverse_offset
set foundCounter to 0
set infoFilePath to “/Contents/info.plist”
set theApps to do shell script “mdfind \”kMDItemFSName == ‘*.prefPane’cd || kMDItemFSName == ‘*.app’cd’\””
set theApps to paragraphs of theApps
set sparkleAppsList to {}
tell application “System Events”
repeat with anApp in theApps
set anApp to anApp as text
set aFrameWork to anApp & “/Contents/Frameworks/Sparkle.framework”
if exists disk item aFrameWork then
try
–get Sparkle Version first
set aSparklePlist to aFrameWork & “/Versions/A/Resources/Info.plist”
set thePlist to contents of property list file aSparklePlist
set theValue to value of thePlist
try
set sparkleVersion to CFBundleShortVersionString of theValue as text
on error
set sparkleVersion to CFBundleVersion of theValue as text
end try
end try
— compare version num
considering numeric strings
set vulnerable to sparkleVersion < “1.13.1”
end considering
if vulnerable then
–get SUFeedURL if it exists
set thePlist to contents of property list file (anApp & infoFilePath)
set theValue to value of thePlist
try
set thisSUFeedURL to my extractSUFeedURL(theValue)
if length of thisSUFeedURL = 0 then
set thisSUFeedURL to “httpx”
end if
on error
set thisSUFeedURL to “httpx”
end try
if thisSUFeedURL contains “http:” then
set end of sparkleAppsList to anApp & ” : uses insecure update URL (not https) ” & “with Sparkle v” & sparkleVersion
set foundCounter to foundCounter + 1
else if thisSUFeedURL contains “httpx” then
set end of sparkleAppsList to anApp & ” : update URL unknown (http/https??); uses Sparkle v” & sparkleVersion & linefeed & linefeed
set foundCounter to foundCounter + 1
end if
end if
end if
end repeat
end tell
set thePrompt to “Found ” & foundCounter & ” items that may be using a vulnerable form of the Sparkle framework: ” & linefeed & linefeed
choose from list sparkleAppsList with title “Sparkle Vulnerability Check” with prompt thePrompt OK button name “Launch”
if result is not false then
set appPath to item 1 of result
get offset of ” :” in appPath
set appPath to text 1 thru (result – 1) of appPath
set ro to reverse_offset(“/”, appPath)
set appPath to text (ro + 1) thru -1 of appPath
if appPath contains “prefPane” then
set paneOffset to offset of “.” in appPath
set paneName to text 1 thru (paneOffset – 1) of appPath
log paneName
tell application “System Preferences”
activate
try
reveal (first pane whose name is paneName)
end try
end tell
else
tell me to launch application appPath
end if
end if
#EOF
However, be aware that this script will not find certain plug-ins (e.g., Mail plug-ins that use Sparkle).
If the app runs on 10.6, it’s not possible for Sparkle to be updated to the latest secure version, 1.13.1, so you need to check with the developers that they’re using https addresses for both the appcast feed and the release notes html.
Rest assured that Sqwarq apps that use Sparkle (App Fixer, DetectX, FastTasks 2, and OSXClock) all use encrypted https update feeds and release notes addresses, so as far as we’re aware at the moment, none of our apps are vulnerable to the exploit regardless of what version of Sparkle they’re using.
As said above, we’ll update this post if things change as the story unfolds.
Credits: Thanks to Yvan for significantly improving my earlier drafts of the AppleScript and writing the code for retrieving the Sparkle bundle number. Thanks to Chris Stone for tweaking and eeking a bit more speed out of the mdfind command. Thanks to Al for pointing out that in earlier versions of the script the Display Dialog message could get truncated.
