HackingTeam was deeply hacked in July 2015 and most of their data was spilled into public hands, including source code for all their sofware and also some 0day exploits. This was an epic hack that shown us their crap internal security but more important than that, their was of doing things and internal and external discussions, since using PGP was too much of an annoyance for these guys (Human biases are a royal pain in the ass, I know!). You can consult the email archives on this Wikileaks online and searchable archive. I had some love on those emails although they never sent that promised Playboy subscription (not interested anymore guys, they gave up on nudes!). For an epic presentation about their OS X RCS malware give a look at these slides.
Last Friday a new OS X RCS sample was sent to me (big thanks to @claud_xiao from Palo Alto Networks for the original discovery, and as usual to @noarfromspace for forwarding it to me). My expectations weren’t big since all the public samples were rather old and know we had their source code so if it were an old sample it was totally uninteresting to analyse. But contrary to my expectations there are some interesting details on this sample. So let’s start once more our reverse engineering journey…
The sample hashes are:
- ZIP with dropper: 2ee9e9d9a0cd3cee6519e7b950821d5c90af03da665879615e52fd093dd8e947
- Dropper binary: 58e4e4853c6cfbb43afd49e5238046596ee5b78eca439c7d76bd95a34115a273
Both files were submitted to VirusTotal three weeks ago.
And their detection rate was (as mostly expected) zero.
As I have written a couple of times, the first thing we should do is to look at the Mach-O headers of the binary files. This can quickly gives us valuable information and save us some time.
The first thing one can notice on this binary is that extra segment called _eh_frame. This is not a normal segment although it is labeled as a section that can be usually found in Mach-O binaries. HackingTeam used this same trick in the past so it’s a strong indicator we are analysing HackingTeam malware and that this could still be an old sample.
Next trick is the fact that this binary is using Apple’s Binary protection, which we can observe on the flags trick using SG_PROTECTED_VERSION_1 flag. A good reference on this Apple feature is Amit Singh’s blog post. It’s pretty easy to dump and recover the original code so it’s not an obstacle to reverse engineering this sample, mostly to evade AV detection. Back in 2009 I wrote a blog post on how to manually dump these binaries or you can use deprotect from class-dump to automatically do it for you.
The injected segment is also protected with the same Apple feature and deprotect tool seems unable to deal with this fact. We can try to manually dump this segment. For this to happen we need to attach a debugger to the dropper binary, since the segment will only be decrypted when its memory pages are used. This is where we find one interesting trick from this sample.
Before we go there, a last screenshot from the binary headers. If we look at the entrypoint it points into the _eh_frame segment, which is also very unusual (VirusTotal flags this as suspicious). What happens is that the normal __TEXT segment is fake since it contains no code (look at the size, it occupies 4kb in memory). Same trick as older RCS samples.
I’m not a fan of LLDB so I still use old Apple’s GDB. It works for me so why bother with the newer but awkard LLDB?
The entrypoint is a good breakpoint so that’s where we start. When we run the dropper GDB gives us a weird error message.
GDB has hit a EXC_BAD_ACCESS exception at the entrypoint address, meaning that memory permissions are wrong. The segment is now decrypted (you can compare this code with the code you get if you try to disassemble the binary) and we can dump it with GDB itself or my readmem util. What we are unable to do is to step and debug the dropper binary. To dump using readmem just use readmem -p PID -a 0x7000 -s 0xB9000, and with GDB dump memory FILENAME 0x7000 0xC0000. This will give you the full _eh_frame segment which you can then load into a disassembler. It’s not a full Mach-O binary so the disassembler will complain but you know where the entrypoint is so you can disassemble from there.
Anyway, let’s get into the interesting stuff. The GDB error quickly gave me an hint to look again at the Mach-O headers. Let’s look at the _eh_frame segment header again…
Can you spot anything special here?
Look at the VM memory protections. The maximum VM protection is set to Read and Writable, and the Initial VM protection to Read and Executable. If this code is executable the flags will need to be executable. What happens here is that the maximum VM protection is not executable and this is the reason why GDB is unable to access the memory. The fix is as simple as fixing the maximum protection to RWX (modify hex value to 8). That’s quite a nice anti-debugging trick I don’t remember every seeing before. Hat tip to you HackingTeam 😉.
Looking at the dropper code and comparing with older samples and we can’t spot many differences. The structure is more or less the same and the tricks still the same, so you can refer to my slides and older blog posts if you are interested in those details. The only difference is that this time the dropper only packs a single persistence binary and a configuration file. Older samples packed more stuff. In case you dumped the _eh_frame as I described, you can find the packed files at address/offset 0x22A4. At offset 0x22B7 we have the name of the persistency binary, _9g4cBUb.psr, and at 0x22D7 the folder name 8pHbqThW. The folder where the dropper installed binaries is still the same as older samples, ~/Library/Preferences/.
At offset 0x22F7 we have the size of the binary, 0xB5DF9, and at offset 0x22FB starts the persistency binary that will be installed by the dropper. At offset 0xB80F8 we can find the configuration file Bs-V7qIU.cYL. It has a size of 0x8F0 bytes (offset 0xB8138), and starts at offset 0xB813C. The configuration file as usual is encrypted.
Let’s recap what we have seen until now. The dropper is using more or less the same techniques as older HackingTeam RCS samples and its code is more or less the same. The new things we can observe is the binary using Apple’s binary protection feature and a small anti-debugging trick. Until now, nothing spectacular. Either this is an old sample or HackingTeam are still using the same code base as before the hack.
Next logical step is to look at the persistency binary we extracted from the _eh_frame segment. This is where the core of RCS is and should help us answer interesting questions, in particular how old is this sample. For me this was really what mattered with this sample. Once again, let’s look at its headers.
Right now you are already a Mach-O expert and noticed how simple this header is. It only contains two segments and one section. This is not normal, in particular when we expect HackingTeam persistency binary to be Objective-C code as in the past.
Loading this into a disassembler and we get only a tiny amount of code, the rest is what appears to be junk code. This is pretty much a tell tale that this binary is packed. This points straight way to HackingTeam’s own packer, keypress, that can be found in the leaked source code. The easiest way to validate this assumption is to compare the disassembly with the source code. The following piece of disassembly clearly identifies this as keypress.
For legal reasons I’m not going to display the leaked source code but you can easily compare those strings and find them in the unpacker code. This is the first sample I have ever seen using their packer, which makes sense since the packer has a 2014 date and all known samples were older than that.
The packer has nothing special and you can even dump it using my readmem util (this time use the -m option to have it dump the full binary from memory). Just start the persistency binary in a VM and while it’s starting you can quickly start readmem and dump it. The alternative is to load it in GDB and find the original entrypoint and dump from there. It’s a bit of more work because GDB can’t activate breakpoints on this binary so you will need to manually patch int3 all over to get GDB to break. If you are using gdbinit you can use the int3/rint3 commands to automate this work.
With the persistency binary finally dumped we can answer relevant questions. What is the date of this sample?
The date question can be answered two ways, using the information from the configuration file (at this stage still encrypted) and from encoded version information.
The source code has a variable called gVersion that refers, more or less, to the sample data. From the source code leak we can find the latest value for this variable, 2015032101, on a commit from 9th April 2015. The gVersion value is a good approximation to the commit date and allows us to track the sample in time.
A bit of reverse engineering here and there and we can find this variable value for this sample, 0x781C294E, translating to 2015111502. BINGO! This locates this sample around October and November 2015, a super fresh RCS sample and post July hack. Never before we had such a fresh sample. And if this date is really true we have a post hack sample, meaning that HackingTeam are still alive and kicking post July hack.
The next step is to confirm this information using the configuration file. First we locate the configuration file encryption key and then decrypt it. There we can find the configuration dates for this sample, 2015-10-16, confirming that this is indeed a post hack sample. The C&C server IP for this sample is 126.96.36.199. It’s already down and I didn’t verified if it was up before starting to tweet about this sample on last Friday (honestly I don’t care much about the server side). Might have been up and was quickly brought down or was already down (or this is simply a demo but it doesn’t look like it).
The last question about this is to understand what happened to HackingTeam after the July hack. At the time they promised to release a new version that they were telling was not affected by the hack. Is this really true?
Well, if you start disassembling and comparing with the leaked source code you will see that this appears to be totally false. The sample is compiled out of the leaked source code base and I can’t see many new improvements. I can guarantee you that this sample code is coming from that code base, up to the last commit (there are probably newer commits after the leak). HackingTeam appears to have resumed their operations but they are still using their old source code for this. Of course there is a question of are they using both old and the new promised source code or were they just lying about it and resumed operations with old code since they are probably on a shortage of engineering “talent”? This is definitely a question their customers will have to ask them.
HackingTeam latest sample is a very fresh sample compared with what we got in the past, it is a sample created post July 2015 hack, and it’s using the same code base as before. HackingTeam is still alive and kicking but they are still the same crap morons as the email leaks have shown us.
If you are new to OS X malware reverse engineering it’s a nice sample to practice with. I got my main questions answered so for me there’s nothing else interesting about this. After the leak I totally forgot about these guys.
@noarfromspace made a good point that this sample could have been compiled by someone else other than HackingTeam since the source code is out. It is definitely an easier and not so sexier alternative path for this. My feeling is that while possible this is not the case. But never forget that Human biases can always lead us to the wrong path.
For example, the gVersion variable appears to be manually updated on the source code repo (I can’t find any automated scripts for this) and follows the same pattern as previous versions. A definitive answer needs a bit more of reverse engineering time.
Some interesting network info provided by Charlie Eriksen tells us that the host was up at least in January and Shodan has a scan on the same day the sample was submitted to VirusTotal. References here and here.
Update: John Matherly just left some historical Shodan data. Shodan detected this host up as far as from 15 October 2015. The configuration file filters activation date start on the next day. Pretty good data out of Shodan 😄.
Looking at VirusTotal submission details we have the following:
- The zip file was created on 2016-01-29 11:43:50UTC, and submitted to VirusTotal via the web interface on 2016-02-04 from Italy. Censys updated the C&C server info at 2016-01-18T19:21:09+00:00.
- The dropper binary was submitted to VirusTotal twice on the 2016-02-04 from France via API.
- The bundle binary that is also extracted in the target persistency folder was submitted the next day 2016-02-25 07:36:07UTC via the API from unknown country and from the installation folder /Users/user1/Library/Preferences/8pHbqThW/w1_X-Hye.gn6.
Update: I just found some unique code in this dropper. This code checks for newer OS X versions and does not exist in the leaked source code. Either someone is maintaining and updating HackingTeam code (why the hell would someone do that!?!?!) or this is indeed a legit sample compiled by HackingTeam themselves. Reusage and repurpose of malware source code happens (Zeus for example) but my gut feeling and indicators seem to not point in that direction.