Writing Bad @$$ Lamware for OS X

The following is a guest post by noar (@noarfromspace), a long time friend.
It shows some simple attacks against BlockBlock, a software developed by Patrick Wardle that monitors OS X common persistence locations for potential malware. The other day noar was telling me about a few bypasses he had found so I invited him to write a guest post.
The title is obviously playing with one of Patrick’s presentations. I met Patrick at Shakacon last year and this is not an attempt to shame him (that is reserved mostly for Apple ;-)). It just illustrates the problems of building defensive tools and how much trust you put on them. By personal experience I can tell you that building a security product is a much harder task than what you might think initially.

Disclaimer: we both work for an endpoint software company. Together with another colleague I wrote an OS X version from scratch. I know very well the insane amount of problems that need to be solved, and they never end. When you build something you are always at mercy of potential security problems, we are no exception. Humans make mistakes. Offense is way easier.

Anyway, enjoy it and hopefully learn something new!
Thank you noar!
fG!

I remember those days when there were only 3 or 4 security software editors for OS X. As the threat counts increased, the market grew up too. Many products are now selling you a feeling of being secure: most of them are post-mortem detection tools, and none is re-inventing the security paradigm.

This dinosaur fight left some room for an altruistic new hype: free – but not open source – security tools. Should we trust them blindly?

I am dedicating this post to HGDB, a former colleague and friend. Your sudden departure is leaving us in an infinite sadness. May you rest in peace.

BlockBlock

New utilities are emerging to free the user from major companies subscription fees, like the recently acquired Adware Medic or Objective-See tools KnockKnock and BlockBlock. So I had interest in reversing Patrick Wardle’s BlockBlock, a self-proclaimed continual runtime protection.

BlockBlock has a weird design: the main binary is running both as a daemon and as an agent. The daemon waits for persistency related filesystem events and notifies the agent. The agent displays an alert and reports a user action to the daemon.

alert

On the day BlockBlock was released, I pointed out several design flaws and how we can abuse them:

Insecure interprocess communication

As Apple clearly states in the developer documentation:

“IMPORTANT
NSDistributedNotificationCenter does not implement a secure communications protocol. When using distributed notifications, your app should treat any data passed in the notification as untrusted. See Security Overview for general guidance on secure coding practices.”
*

In practice, it’s trivial to observe all distributed notifications, by setting notificationName to nil:

NSDistributedNotificationCenter *center = [NSDistributedNotificationCenter defaultCenter];
[center addObserver:self 
        selector:@selector(fyi:) 
        name:nil 
        object:nil 
        suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately];

Let’s snoop on daemon and agent distributed notifications, using notifyi, a very simple command line tool.

First, the daemon posts a shouldDisplayAlertNotification notification with a 16MB processIcon and an universal unique identifier watchEventUUID:

2015-08-07 00:27:43.859 notifyi[365:3025] __CFNotification 0x7fcc53d00270 {name = shouldDisplayAlertNotification; userInfo = {
	    alertMsg = "installed a launch daemon or agent";
	    itemBinary = "/Users/noar/.launchd.app/Contents/MacOS/launchd";
	    itemFile = "/Users/noar/Library/LaunchAgents/apple.launchd.plist";
	    itemName = "apple.launchd";
	    parentID = 1;
	    pluginType = 2;
	    processHierarchy =     (
	                {
	            index = 0;
	            name = "kernel_task";
	            pid = 0;
	        },
	                {
	            index = 1;
	            name = launchd;
	            pid = 1;
	        },
	                {
	            index = 2;
	            name = launchd;
	            pid = 368;
	        }
	    );
	    processID = 368;
	    processIcon = <REDACTED>;
	    processLabel = launchd;
	    processName = launchd;
	    processPath = "/Users/noar/.launchd.app/Contents/MacOS/launchd";
	    targetUID = 501;
	    watchEventUUID = "7EADEED3-2E17-4060-AF9B-3B37357A07D6";
	}}

Then, the agent alerts the user and posts a shouldHandleAlertNotification notification with the same watchEventUUID and the action to take:

2015-08-07 00:28:07.740 notifyi[365:3025] __CFNotification 0x7fcc53d00820 {name = shouldHandleAlertNotification; userInfo = {
	    action = 0;
	    remember = 0;
	    watchEventUUID = "7EADEED3-2E17-4060-AF9B-3B37357A07D6";
	}}

What was blocked?

In this example, I pressed the Block button, and BlockBlock deleted the reported launchd.plist file:

$ find ~/Library/LaunchAgents -type f 
/Users/noar/Library/LaunchAgents/com.objectiveSee.blockblock.plist

But, amazingly, process 368 is still running:

$ ps -p 368
  PID TTY           TIME CMD
  368 ??         0:00.57 /Users/noar/.launchd.app/Contents/MacOS/launchd

BlockBlock didn’t unload the agent or kill the process. The threat will run until the user logs out (the sample used here is OSX.Icefog.A).

Proof of Concept

To bypass BlockBlock, we can simply unload the agent. We can also wait for an alert and silently whitelist us until the daemon restarts:

  • observe shouldDisplayAlertNotification notification.
  • unload BlockBlock launch agent.
  • post shouldHandleAlertNotification notification with Allow and Remember to daemon.
  • reload BlockBlock launch agent.

The menu item quits and reopens, without alert. Proof of concept source code is avaible here (BlockBlock branch).

poc

So, what do we learn here?

First, every software you install, including those to protect your computer, increases its attack surface.
[fG!] Joxean Koret demonstrated how true this is in the past two years with his breaking AVs presentations. Just recently Symantec had similar issues on their EndPoint protection software. This is nothing new, people just keep forgetting this fact.

Second, we have to learn from mistakes: BlockBlock is not the only security software that uses distributed notifications.

Last but not least, providing quality service for nothing can’t be a one person job. To save users from trusting security vendors, InfoSec free tools should be open source, so a strong community has the possibility to audit and improve them.
[fG!] Trust is a key problem in InfoSec, even with open source tools. Everyone trusts someone else is doing an audit and most of the times that never happens. There are also many times assumptions that are never made clear or that users do not understand and/or care about them.