Monthly Archives: January 2018

how to add a window switcher

If you’re a big fan of the command tab Application switcher, you might enjoy adding a window switcher to your list of keyboard hotkeys. The window switcher allows you to jump between different windows, both those of other apps and the same app with a hotkey like option tab, which sits nicely next to command tab in my muscle memory!

This is particularly useful if you have a couple of windows open in several applications, and it is much faster and neater than first using command tab and then command backtick to cycle through an app’s windows. Another advantage here is that the window switcher will include full screen and non-full screen windows in multiple spaces, which command backtick typically does not handle well, something I find particularly frustrating when using Xcode.

Adding a window switcher is easy and doesn’t require any hacking. It does require Hammerspoon, however. But if you’re a regular reader of this blog, you’ll already have installed Hammerspoon after reading my earlier posts on it here and here and here. 🙂

With Hammerspoon up and running, adding the window switcher is just a case of cutting and pasting some code into your config file, saving it then reloading. You can use the default code in hs.window.switcher docs or use mine below. The default code is a bit ugly for my liking. Instead, I use the code below, which sets up the switcher’s ui as seen in the screenshots here with option tab and option-shift tab for shortcuts, but you can modify the appearance to suit your taste. As ever, the Hammerspoon docs are wonderfully clear and easy to follow (take a lesson, Apple!).

-- set up your windowfilter
switcher = -- default windowfilter: only visible windows, all Spaces
switcher.ui.highlightColor = {0.4,0.4,0.5,0.8}
switcher.ui.thumbnailSize = 112
switcher.ui.selectedThumbnailSize = 284
switcher.ui.backgroundColor = {0.3, 0.3, 0.3, 0.5}
switcher.ui.fontName = 'System'
switcher.ui.textSize = 14
switcher.ui.showSelectedTitle = false

-- bind to hotkeys; WARNING: at least one modifier key is required!

Adjust values such as shortcut bindings as you please, and that’s it. For two minutes work, you just added a very useful window switcher to macOS!

Enjoy! 😀

how High Sierra updater leaves behind a security vulnerability

Some time shortly after the release of High Sierra public betas last year, I started noticing a lot of user reports on Apple Support Communities that included something odd: an Apple Launch Daemon called appeared, but oddly its program argument, a binary located at /macOS Install Data/Locked Files/cleanup_installer was missing.

An ‘etrecheck’ report on ASC

Being an Apple Launch Daemon, of course, the cleanupinstaller.plist is owned by root:

-rw-r--r--   1 root  wheel   446 Oct 10 06:52

After discussion with a few colleagues about this oddity, I decided to see if I could catch a copy of the missing program argument. After rolling back to an earlier version first, I found that the macOS Install Data folder is created when a user runs the Upgrade installer (along with the Launch Daemon plist). A clean install with the full installer does not appear to create either the properly list or the program argument.

The Locked Files folder indicated in the program argument path is hidden in the Finder, but revealed in Terminal.

Inside the Locked Files folder is the cleanup_installer binary. The binary is 23kb, and the strings section contains the following, giving some indication of its purpose:

Upon a successful upgrade, the /macOS Install Data/ folder is removed, but the Launch Daemon is not, and therein lies the problem.

Let’s have a look at the plist:

The ‘LaunchOnlyOnce’ and ‘RunAtLoad’ keys tell us the program argument will be run just once on every reboot. It’ll execute whatever is at the program argument path with root privileges. With the executable missing as noted in numerous ASC reports, that leaves open the possibility that a malicious process could install its own executable at the path to aid in persistence or re-infection if the original infection were to be discovered or removed.

To test this hypothesis, I threw a quick script together that included a ‘sudo’ command.

#! /bin/bash
sudo launchctl list > /Users/phil/Desktop/securityhole.txt

The legacy command ‘launchctl list’ produces different results when it’s run with sudo and when it’s not. Without sudo, it’ll just list the launchd jobs running in the user’s domain. With sudo prepended, however, it’ll instead list the launchd jobs running in the system domain. This makes it easy for us to tell from the output of our script whether the job ran with privileges or not.

Having created my script, I created the path at /macOS Install Data/Locked Files/ and saved the script there as ‘cleanup_installer’. It’s worth pointing out that writing to this path requires admin privileges itself, so this issue doesn’t present any kind of ‘zero day’ possibility. The attacker needs to have a foothold in the system already for the danger to be real, so I’ll repeat that the vulnerability here is the possibilty of the attacker hiding a very subtle root persistence mechanism within a legitimate Apple Launch Daemon, making it all the more difficult to detect or remediate if otherwise unknown.

The final step was to chmod my script to make it executable, and then restart the mac. Sure enough, after reboot and without any other intervention from myself, the script was executed and my Desktop contained a text file with a nice list of all the system launchd jobs!

Of course, that’s a trivial script, but here’s the tl;dr:

Anything – including code to reinstall malware – can be executed with root privs from that path every time a High Sierra install containing the Apple cleanupinstaller.plist reboots.

If you’re already beyond your second reboot since updating and your /LaunchDaemons folder contains this property list, the obvious thing to do is to remove it (as High Sierra should have done when it completed the reinstall). It appears to serve no purpose once the program argument has been removed, other than to offer a way for malware to seek persistence.

Secondly, you should be able to safely remove the /macOS Install Data/ folder if you find that exists. This is usually removed after a successful update, but it can also be left behind if a user cancels out of an update half way through. If you do find this still lurking on your system, you can check that it is what it’s supposed to be by copying and pasting this into Terminal:

strings -a /macOS\ Install\ Data/Locked\ Files/cleanup_installer

and confirm you get the same or similar as listed earlier in this post. On my system here, the file also gives a checksum of 945203103c7f41fc8a1b853f80fc01fb81a8b3a8. You can produce that on the command line with:

shasum -a 1 /macOS\ Install\ Data/Locked\ Files/cleanup_installer

However, it’s entirely possible that Apple either already have or may in the future make changes to that binary since I captured it, so a varying checksum alone should be treated with caution.

Of course, even after having removed these items, there’s nothing to stop an attacker that’s already compromised a machine from recreating both of those (as indeed, there’s nothing to stop a privileged attacker creating anything else on your system!). Thus, it’s always a good idea to keep track of what changes occur on your system on a regular basis. My free/shareware tools DetectX and DetectX Swift are designed to do exactly this. In DetectX, after running a search, the log drawer will tell you if the /macOS Install Data/ exists:

1. This issue was reported to Apple Product Security in August 2017.

%d bloggers like this: