Steam UAC bypass via code execution

Like many other gamers, I love Steam. Not only is it ridiculously convenient, but it’s also become a pretty awesome platform for indie game developers to get their games out there. It provides a online store platform for 54 million users, and most of the time it does an excellent job. That’s partly the reason why I’m so frustrated with Valve right now.

I spent a good few hours playing with a bug I found in Steam, and then made an effort to provide Valve with a clear, concise, detailed security vulnerability notification. Their response has been one of pure opacity, with not a single ounce of professional courtesy.

On Tuesday 17th September 2013, I submitted a vulnerability report to Valve, the full text of which follows:

I have discovered a vulnerability within the Steam client application that allows for arbitrary memory copies to be initiated within the Steam process. These issues can be triggered at multiple crash sites, and range in severity from unexploitable crash (denial of service) to full compromise of the process.

Technical details:

The shared memory section GameOverlayRender_PIDStream_mem-IPCWrapper does not have an ACL applied to it, so any user may open a handle to it with all privileges. This is especially important in multi-user systems such as terminal services, or in situations where other potentially risky processes are sandboxed into other user accounts within the same session.

By opening a handle to the section and writing random garbage data, then signalling the Steam3Master_SharedMemLock wait handle (which also does not have an ACL) it is possible to cause the Steam client to crash. I have discovered multiple locations where the crash may occur, and many are within REP MOVS copy instructions. In some cases it is possible to control the destination address (EDI), the source address (ESI), and/or the memory at the target site of ESI. In some cases other general purpose registers were modified. By carefully crafting a payload, it would certainly be possible to cause code execution via heap corruption, e.g. by overwriting a callback pointer. Despite the use of ASLR and DEP on the process, certain modules (e.g. Steam.dll, steamclient.dll, CSERHelper.dll) are not marked as ASLR supporting. It is possible to use a technique called Return Orientated Programming (ROP) to bypass ASLR and DEP in cases such as this, where there are non-ASLR modules loaded into the process.

I have created a proof of concept application, which can be provided upon request, though it should be trivial for a developer to discover the source of the vulnerabilities.


The fix I would propose is that an appropriate explicit ACL is set on the afforementioned objects, enforcing that only the user that created the Steam process can access the object. Additionally, I would recommend that proper bounds and sanity checking is enforced on the shared memory object. Furthermore, it would be prudent to ensure that memory copy operations (e.g. memcpy) are performed using SDL approved functions, such as memcpy_s.

Responsible disclosure policy:

This ticket serves as initial notification of a security issue. Please respond within 30 days, detailing your acceptance or rejection of the report, the proposed mitigation (if any), and patch timescale. If no satisfactory response is received within 30 days, it will be assumed that you do not consider the issues in this report to constitute a security issue, and they will be publicly disclosed. My normal public disclosure timescale is 90 days after initial notification, but this can be extended upon reasonable request. Most importantly, please remember that this is an invitation to work with me to help improve your product and increase the security posture of your customers. Should you require further information about the issue, or any other aspects of this notification, please contact me.

Thank you.

On Sunday 22nd of September 2013, after further pondering the issue, I provided this addendum to the report:

Impact update:

On further consideration, the impact of this issue is not exactly as described above. Due to the location of the shared memory section object within the object manager hierarchy, it is not accessible across sessions unless the reading process is running in an administrative context. This negates any cross-session privilege escalation, so one user session cannot directly attack another in this manner.

However, an additional impact has been discovered. If the attacking process runs in the same session as the user (e.g. malware) and waits for Steam to escalate its privileges to an administrative context via User Account Control (UAC), it may then exploit the vulnerability and gain UAC escalation. This completely bypasses the UAC process and could allow local malware to jump from a limited or guest user context to a full administrative context. Not only is this directly problematic for home users, but it becomes significantly important for domain environments where workstation security is enforced by group policy, which is bypassable via the administrative security context.

I feel that this new impact scenario is more significant, since it targets the most common configuration of Steam, i.e. a single-session machine.

As noted before, please feel free to contact me if you have any questions. For absolute clarity, the cut-off point for non-responsiveness is the 17th of October 2013, i.e. 30 days after initial notification. Please respond before then as per the responsible disclosure policy detailed above.

Thank you.

I recognise that this isn’t exactly an earth-shattering vulnerability, as UAC isn’t “officially” a privilege segregation. That said, it’s significant enough to warrant fixing, especially as it results in memory corruption. Furthermore, I’m sure someone could find a way to utilise the issue in a much more interesting way than I did.

A Valve employee under the name of “Support Tech Alex” responded the next day, apologising for the delay and informing me that the details would be forwarded to the appropriate department. Excellent, I thought. I thanked him, and waited. A week passed, then two. Still no response.

On Wednesday 9th October, I discovered that they had closed the ticket. I asked why, and their response was as follows:

Hello Graham,

Unfortunately, you will not receive a notification about any action taken as a result of this report.

If you have a business related inquiry, please visit

If you have any further difficulty, please let us know.

This annoys me, and I think it demonstrates a fundamental lack of understanding of whitehats on Valve’s part. In my opinion and experience, what drives a whitehat isn’t a lust for rewards, or free swag, or even being thanked by the company (though that is nice). What drives a whitehat is the quest for technical knowledge, and the satisfaction of having helped fixed a security issue. When a vendor cuts a whitehat out of the loop, and leaves them hanging without even saying whether they’re going to look into it, it kills all motivation. Not only is it unprofessional, but it’s also downright rude to reward a person’s hard work with little more than contempt.

I didn’t go into this expecting Valve to pay me or even send me a T-shirt for finding the bug. I did, however, at least expect to get something along the lines of “thanks, we’ll fix that, should get pushed out in the couple of months”. Instead what I got was opacity and avoidance, and that’s not the way to deal with security notifications. Hopefully a public shaming will do you some good, Valve. Treat whitehats well, and you’ll do well. Treat whitehats badly, and you might find that they take their reports elsewhere.

Update: In my sleep-deprived state last night, I forgot to update this draft before publishing it. There’s actually a much bigger vulnerability here: Steam gives itself SeDebugPrivilege, which allows it to bypass ACLs on OpenProcess calls, meaning it can inject code into any other process on the system, including those running as SYSTEM. It’s a full privesc. I’ve written a follow-up post that explains this in more detail.

Installing Dropbox? Prepare to lose ASLR.

Dropbox has become a daily part of my life. I rely on it to synchronise data between my growing set of devices. But how much of an impact does it have on the security of my system? I decided to find out by digging around in exactly what it does to my machine, or more specifically, the processes running on it.

The first thing I want to check out is what modules are loaded into various processes. Tools like Dropbox like to extend the functionality of other programs using shell extensions, which are nothing more than specially designed DLLs loaded into process memory. Let’s see what we’ve got…

Dropbox Files

Interesting! Looks like we’ve got two extension DLLs, one 32-bit and one 64-bit. These are likely used to add extra context menu options when right-clicking on files. Now let’s find out where they get injected. For this, we’ll use good ol’ trusty Process Explorer. By going to Find » Find Handle or DLL, we can search for the DLLs in running processes.

Dropbox DLL Injection

It looks like it’s being loaded into processes that have windows created, which implies it’s probably an AppInit DLL, but it turns out not to be the case – the registry key doesn’t contain that DLL. This implies that there’s something more active going on, and that Dropbox actively selects which processes to inject into. I may be mistaken here, I’m not sure. Either way, though, it’s a little odd that it chose to inject into Notepad++ and other innocuous processes.

(Update: thanks to zeha and 312c on Reddit for pointing out that it’s likely injected via the standard file browser shell, due to the Dropbox icon in the favourites list)

The biggest problem becomes clear when you take a look at the module in a running process. In this case, it’s Firefox:

Dropbox in Firefox

Notice that the Dropbox extension DLL doesn’t have the ASLR flag set. This means that any vulnerability in Firefox becomes a lot easier to exploit, since the Dropbox module provides an unrandomised anchor for a ROP chain. Ignore PowerHookMenu.dll here – I’m aware of that issue and have notified the developer, but it’s infrequently seen on people’s machines so it’s not so bad.

Let’s just quickly verify that the DLL isn’t ASLR enabled at all, by checking the DLL characteristics flags in the file…

ASLR disabled for DLL

Definitely not enabled.

Anyway, the take-away issue here is that Dropbox arbitrarily injects an ASLR-disabled DLL into various 32-bit and 64-bit processes, causing significant degradation in the efficacy of ASLR across the entire system. With no ASLR, an attacker could craft an exploit payload that utilises executable code within the injected DLL to product a ROP chain, leading to code execution. This is significantly problematic in high-risk programs like web browsers and torrent clients.

I notified Dropbox of this back when version was the latest version, but got not response. I’ve since tried again, but had no luck. I’m hoping that going public will give them the kick they need to get it fixed. In the meantime, a good mitigation is to install EMET and set a policy to enforce Mandatory ASLR. All of this was re-tested against Dropbox 2.0.22, with versions of both the 32-bit and 64-bit DLLs. The operating system used was Windows 7 x64 SP1.

Update: Brad “spender” Spengler (of grsec fame) has noted that the latest version of Dropbox has ASLR enabled for the 64-bit DLL, but still doesn’t on 32-bit.

Update 2: Dropbox responds: “Our engineers are aware of this issue and actively working on fixing it. Unfortunately, I can’t give you an exact timeline that a fix will become available. If you have any additional questions or concerns please let me know.”

Update 3: @_sinn3r has done some awesome work on the exploitability of these issues, over at Metasploit. Definitely worth a read.

The Router Review: From nmap to firmware

When I moved into my flat, I found that the previous tenant had left behind his Sky Broadband router. Awesome – a new toy to break! Sadly I got bogged down with silly things like moving house and going to work, so I didn’t get a chance to play with it. Until now, that is.

This isn’t the first embedded device I’ve played with. Over the years I’ve desoldered EEPROMs from routers, done unspeakable things to photocopiers, and even overvolted an industrial UPS unit via SNMP. The router I shall be discussing in this post, however, was one of the easier and more generic bits of kit I’ve played with.

Now, a little about the device. The model is DG934, and the full part number is 272-10452-01. It’s an ADSL router supplied by Sky (also known as BSkyB) as part of their old broadband package, but it’s actually manufactured by Netgear. It’s got four ethernet ports, an ADSL (phone) port, and takes a 12V power supply. Internally, it runs on the Atheros chipset. Unfortunately, this being a UK-only device, there’s no FCC ID – if there had been, I could’ve looked it up on the FCC OET database and found all sorts of internal photos and test data, which is often valuable when looking at the hardware aspects.

My first job was to power it on and get into the config panel. Since the previous tenant clearly wasn’t security conscious, he’d kindly left the device in its default configuration and I was able to log into the configuration interface using the default admin / sky credentials. I exported the config file to my machine, and took a look. In this case it’s plaintext, so there’s nothing to break here, but it’s not exactly good practice – it includes the passwords for WiFi and the configuration interface.

I ran nmap against the device and got the following results:

80/tcp    open  http    BSkyB DG934G http config
5000/tcp  open  sip     BSkyB/1.0 UPnP/1.0 miniupnpd/1.0 (Status: 501 Not Implemented)
8080/tcp  open  http    BSkyB DG934G http config
32764/tcp open  unknown

Interestingly, the configuration site was available on both 80 and 8080. This seems to be the norm for many routers, but I have no idea why. UPnP on port 5000 is always a fun one to spot, and we’ll take a look at this shortly. Finally, there’s an unknown protocol running on port 32764.

For messing with UPnP, I have the UPnP Developer Tools for Windows. They’re mainly written in C# and are open source, so you can always port to Mono if you want. I used Device Spy to get the following info:

  • It’s a BSkyB DG934 Router.
  • The firmware date is 2007-08-27.
  • You can pull out stats such as total bytes sent/received, total packets sent/received, and uptime in seconds.
  • Port mapping functions are available.
  • SetEnabledForInternet isn’t present – shame, really, since it leads to a nice DoS condition.

Sadly there’s not much you can play with here.

Next, we’ll take a look at that weird unknown protocol on port 32764. When connecting to it, the string “MMcS” is returned, along with two binary IP representations: and I tried playing around with this, but honestly I have no idea what it’s for. Google returned a bunch of people asking what it was, and nobody with any real answers. Potentially it’s for Multimedia Class Schedule Server, but that’s speculation at best. Again, no luck at fun stuff here.

Finally, let’s dig into the firmware. Instead of taking the device apart, desoldering the firmware EEPROM, and interfacing to it with a BusPirate to rip the data off, I decided to go the easy route and download the openly available firmware from Netgear. The file provided is a flat binary, with some interesting data inside it. It’s partitioned into various sections, with conveniently obvious data offsets (e.g. 0x10000). In order to properly dissect the file, I used binwalk. In BackTrack 5 it’s located in /pentest/reverse-engineering/binwalk/ and requires you to manually set the magic file via the -m switch.

root@bt:~# binwalk -m /pentest/reverse-engineering/binwalk/magic.binwalk ~/dg834gt_1_02_09.img
:1248 0x4E0 CFE boot loader
1288 0x508 CFE boot loader
4177 0x1051 LZMA compressed data, properties: 0xA4, dictionary size: 285474816 bytes, uncompressed size: 256 bytes
7951 0x1F0F LZMA compressed data, properties: 0xC2, dictionary size: 556793856 bytes, uncompressed size: 67108881 bytes
8087 0x1F97 LZMA compressed data, properties: 0x82, dictionary size: 556793856 bytes, uncompressed size: 67108881 bytes
8227 0x2023 LZMA compressed data, properties: 0xC2, dictionary size: 556793856 bytes, uncompressed size: 67108881 bytes
8371 0x20B3 LZMA compressed data, properties: 0x82, dictionary size: 556793856 bytes, uncompressed size: 67108881 bytes
10563 0x2943 LZMA compressed data, properties: 0xDF, dictionary size: 555220992 bytes, uncompressed size: 167272448 bytes
65792 0x10100 CramFS filesystem, big endian size 2879488 version #2 sorted_dirs CRC 0x51df60ff, edition 0, 1975 blocks, 938 files
1016865 0xF8421 ARJ archive data, v193, backup, original name: \230\346+\210\365 ... [snip]

This gives us a pretty good idea of what we’re dealing with. First, there’s a Common Firmware Environment (CFE) bootloader, which is Broadcom’s alternative to U-Boot. There’s some irony here in that Broadcom and Atheros are competitors, yet CFE is being used on an Atheros chipset device. Anyway, there’s a bunch of LZMA junk after that which looks like various bits of firmware and a Linux kernel image. The bit we’re really interested in is the CramFS data. As a side note here, it looks like binwalk was a bit overzealous in identifying an ARJ archive at the end (hence the corrupted original name) so we can assume that the CramFS block takes up the remainder of the file.

In order to extract the filesystem, we can use good old dd. The following should suffice:

dd size=256 skip=257 count=20000 if=dg834gt_1_02_09.img of=firmware.cramfs

Note that 257 * 256 = 65792, which is 0x10100, i.e. the offset of the data we want to pull out. I stuck a really big count in there because we’re reading to the end of the file. Now, you’re going to want to grab some tools to work with CramFS:

sudo apt-get install cramfsprogs fusecram

This provides you with the modules needed to mount CramFS volumes, as well as some tools to help you along the way. Now we can mount the filesystem:

root@bt:~# sudo mount -t cramfs -o loop ~/firmware.cramfs /media/firmware/
mount: wrong fs type, bad option, bad superblock on /dev/loop1,
missing codepage or helper program, or other error
In some cases useful info is found in syslog - try
dmesg | tail or so

Hmmm, that’s odd. Let’s see what dmesg has to say about this…

root@bt:~# dmesg | tail -n 1
[ 4394.319907] cramfs: wrong endianess

Aha! A fun fact about CramFS is that file systems have endianness as per the architecture they were created on. Since the router is big-endian and my box is little-endian, I need to convert it. Thankfully, cramfsprogs includes a tool called cramfsswap that flips the endianness of a provided image. Side note: if you get “wrong magic” as an error, you didn’t extract the right blocks of data, or the file system isn’t CramFS.

root@bt:~# cramfsswap ./firmware.cramfs ./firmware-conv.cramfs
Filesystem is big endian, will be converted to little endian.
Filesystem contains 937 files.
CRC: 0xe86ad3b0
root@bt:~# sudo mount -t cramfs -o loop ~/firmware-conv.cramfs /media/firmware/

Excellent! Now to dig around inside the files.

root@bt:~# ls -l /media/firmware/
total 20
drwxr-xr-x 1 root root 452 1970-01-01 01:00 bin
drwxr-xr-x 1 root root 0 1970-01-01 01:00 dev
lrwxrwxrwx 1 root root 8 1970-01-01 01:00 etc -> /tmp/etc
drwxr-xr-x 1 root root 784 1970-01-01 01:00 lib
drwxr-xr-x 1 root root 0 1970-01-01 01:00 proc
drwxr-xr-x 1 root root 176 1970-01-01 01:00 sbin
drwxr-xr-x 1 root root 0 1970-01-01 01:00 tmp
drwxr-xr-x 1 root root 116 1970-01-01 01:00 usr
lrwxrwxrwx 1 root root 8 1970-01-01 01:00 var -> /tmp/var
lrwxrwxrwx 1 root root 8 1970-01-01 01:00 www -> /tmp/www
drwxr-xr-x 1 root root 3900 1970-01-01 01:00 www.deu
drwxr-xr-x 1 root root 3908 1970-01-01 01:00 www.eng
drwxr-xr-x 1 root root 3824 1970-01-01 01:00 www.fre

There’s a full listing on pastebin, if you’re interested. It’s worth noting that if you can mount the filesystem, can see the directories and files inside it, but can’t read the file data, then you probably didn’t copy the entire filesystem and it’s missing chunks of data. Anyway, this looks pretty typical. We can see a very basic file system that comprises all the runtime parts of the device, excluding the kernel and any ramfs stuff. Here’s what I found:

  • The three www prefixed directories contain the template files used for the administration panel.
  • /bin contains busybox binaries.
  • /lib contains the kinds of libraries you’d expect on a router, e.g. libcrypt, libupnp, libpppoe, etc.
  • /lib/modules contains various kernel modules for the router, such as the push button driver and Atheros HAL.
  • /sbin contains various binaries such as ifconfig, insmod, lsmod, etc.
  • /usr/bin contains four binaries, including one called test.
  • /usr/etc contains the default config files and various scripts.
  • /usr/sbin contains various binaries for daemons (including reaim and iptables), as well as some for performing maintenance operations, e.g. WiFi control operations.
  • /usr/upnp contains the definitions for the UPnP endpoint.

The most interesting directory was /usr/etc, which contains both passwd and an The passwd file shows only root and nobody, which leads me to believe that all services run as root. The file has all sorts of interesting info in it:

Path: .
URL: file:///svn/Platform/DG834_PN/Source
Repository Root: file:///svn/Platform/DG834_PN
Repository UUID: 25bc2c04-8815-0410-823d-fa30465ac5aa
Revision: 93
Node Kind: directory
Schedule: normal
Last Changed Author: ethan
Last Changed Rev: 93
Last Changed Date: 2007-02-16 16:23:45 +0800 (Fri, 16 Feb 2007)

Boot Loader version: CFE version 1.0.37-5.11 for BCM96348

So we now know that Netgear use(d) SVN for their source control, that “Ethan” is the guy developing the firmware for the DG834, and that we’re running CFE 1.0.37-5.11 on the BCM96348 SoC IC. Hi, Ethan!

I’m going to leave this here for now, primarily because it’s almost 4am, but also because the point of this blog post was to show just how much information you can dig out of a device without even touching it with a screwdriver, or opening a manual. Keep in mind that the techniques I’ve shown here should apply to many routers and other small embedded devices. At some point in the future I’ll get around to digging into some of their custom binaries, as well as their HTTPD. If I find anything interesting, I’ll be sure to post an update. Also, let me know if you’ve got any spare routers you want me to dig into when I get a spare few hours – I’m always happy to take donations!

A quick crypto lesson – why “MAC then encrypt” is a bad choice

In light of the numerous recent attacks against SSL, I thought I’d offer up a quick and simple crypto lesson about why MAC-then-encrypt schemes are bad. This post will require only a minimum of knowledge about cryptography, so hopefully it’ll be useful to a wide range of people.

This is not designed to be a full and detailed description of how SSL works, or how various attacks against it works, but rather a short primer on the subject for those who know a bit about crypto but don’t really understand how something as seemingly strong as SSL might be broken. Some parts have been generalised or simplified for brevity and ease of understanding, so please don’t take anything I say here as a literal description of how it all works.

Anyway, let’s get started…

A secure network protocol has two main jobs:

  1. Keep the information in the conversation completely confidential.
  2. Prevent an attacker from tampering with the conversation.

The first part, as you probably already know, is performed by encryption. This usually involves exchanging one or more secret session keys between two endpoints, then using them with a cipher of some kind in order to provide safety against eavesdroppers.

The second part is a little more involved. In this case, when I say “tampering with the conversation”, I mean forging packets that look like they came from a legitimate endpoint, in such a way that they have a meaningful effect on the security of the conversation. This part is often implemented via a Message Authentication Code (MAC), which verifies that all data received was in fact sent by an authorised endpoint. Usually, a HMAC hash will be used, which is a keyed version of a cryptographic hash function. By using the session key as the key for the HMAC hash, it is possible to produce a hash of the payload in a way that cannot be forged by anyone that does not know the session key. By computing the same HMAC hash on the receiving end, using the same session key, it is possible to verify the authenticity of the data.

However, there’s a catch. One implementation option, called MAC-then-encrypt, is to compute the MAC on the plaintext data, then encrypt the data. The receiving endpoint then decrypts the data using the session key, and verifies its authenticity. Unfortunately, this means that an unauthenticated attacker can send arbitrary messages, and the receiving endpoint must decrypt them first in order to verify the MAC. Without knowing the session key, the attacker will likely produce garbage data after decryption, and the MAC will not match.

There is, however, an interesting trick that can be done here. Block ciphers require the length of all plaintext messages to be a multiple of the cipher’s block size. Since there is often a length discrepancy, padding is used to ensure that the message length is extended to fit. There are many different algorithms for generating padding data, but the padding is usually reliant on the plaintext in some way. This padding is checked during the decryption phase, and invalid padding results in an error. An attacker can flip certain bits in the ciphertext to modify this padding, and identify changes in behaviour and timing based on these altered bits. This is called a padding oracle attack, and can lead to full discovery of the plaintext.

A better solution, called encrypt-then-MAC, is to encrypt the data first, then compute the MAC of the ciphertext. This leads to a situation where the receiving endpoint checks the MAC first, before performing decryption, and drops the connection if the MAC is incorrect. Since the attacker can’t forge the MAC without knowing the session key, this completely negates the padding oracle attack.

How is all of this relevant to SSL? Well, in TLS 1.0 and earlier, a MAC-then-encrypt scheme was used. This resulted in various attacks, including BEAST and Lucky 13. In TLS 1.1 and later, these types of attacks are prevented.

Hopefully this has given you some insight into one of the ways that SSL can be vulnerable.

Password cracking with VMware Authentication Daemon

I just came across a cool trick you can try which allows you to crack passwords on a remote system that is running the VMware Authentication Daemon. This service installs and runs by default on Windows host machines that have VMware Virtual Workstation installed, and listens on TCP port 912. It shows up on nmap as apex-mesh, but doesn’t follow the APEX protocol at all. Instead, it looks a little bit like a hybrid between an FTP and SMTP server:

220 VMware Authentication Daemon Version 1.0, ServerDaemonProtocol:SOAP, MKSDisplayProtocol:VNC ,
530 Please login with USER and PASS.
USER test
331 Password required for test.
PASS test
530 Login incorrect.
USER Graham
331 Password required for Graham.
PASS <snip>
230 User Graham logged in.
500 Unknown command '?'
500 Unknown command 'HELP'
500 Unknown command 'INFO'
500 Unknown command 'STAT'
CD C:\
500 Unknown command 'CD C:\'
500 Unknown command 'HELO'
500 Unknown command 'HELLO'
500 Unknown command 'EXIT'
221 Goodbye

As you can see, I couldn’t find any working commands. The interesting part is that it accepted my real NT username and password for the machine that the service was running on. Even more interesting, it doesn’t seem to have any rate-limiting or obvious “failed attempt” logs, so it’s much more stealthy than attacking RDP or SMB directly. In fact, this may translate over to Linux user accounts, too.

It turns out that someone already created a metasploit module for exactly this purpose, so go nuts!

The anti-virus age is over.

As far as I’m concerned, anti-virus systems are as good as dead. Or, if they aren’t just yet, they’re certainly headed that way.

Signature-based analysis, both static (e.g. SHA1 hash) and heuristic (e.g. pattern matching) is useless against polymorphic malware, which is becoming a big concern when you consider how easy it is to write code generators these days. By the time an identifying pattern is found in a particular morphing engine, the bad guys have already written a new one. When you consider that even most browser scripting languages are Turing complete, it becomes evident that the same malware behaviour is almost infinitely re-writeable, with little effort on the developer’s part. Behavioural analysis might provide a low-success-rate detection method, but it’s a weak indicator of malintent at best.

We’ve also seen a huge surge in attacks that fit the Advanced Persistent Threat (APT) model in the last few years. These threats have a specific target and goal, rather than randomly attacking targets to grab the low-hanging fruit. Attacks under the APT model can involve social engineering, custom malware, custom exploits / payloads and undisclosed 0-day vulnerabilities – exactly the threats that anti-malware solutions have difficulty handling.

The next problem is memory-resident malware. It’s very difficult (i.e. computationally expensive) for AV software to monitor the contents of program memory, let alone provide accurate detection of in-memory exploits on a live system. If malware never touches the disk, most AV software will never catch it. In his  “HTML5 – A Whole New Attack Vector” talk at BSidesLondon, Robert McArdle talked about botnets and other malware, written in HTML5, that reside within a browser tab. Now, assuming the browser doesn’t cache this on disk (you can usually mandate this with HTTP headers) you’ve got a memory-resident malware threat that doesn’t need browser exploits, is easy to obfuscate, and has full networking capabilities. On the other side of things, arbitrary code execution exploits within browsers might be leveraged to load executable modules into process memory. It would be relatively simple to write malware that remains resident in the browser process, or infects other long-running processes on the system. It’s also usually possible to prevent swapping on memory pages, so you can guarantee that the malware never touches the disk. It’s a nightmare for AV software, and a nightmare for forensic analysts.

Whilst the technical aspects of these attacks are a daunting opponent to anti-virus systems, the economic aspect is the nail in the coffin. According to PayScale, an average software developer in India gets about 320,000 INR per year, which equates to roughly 5700 USD. Compare that to the price of a malware analyst or systems security analyst, which is 60,000 USD before insurance, pension and other benefit costs are tacked on. That means that for every analyst that an AV company hires, the bad guys can hire 10 developers. That’s easily enough to work on 3 or 4 malware projects in parallel. There’s no competition here – the bad guys have more people working for them, for less money, and they don’t need to adhere to employment standards or ethical working practices. They can produce and update malware significantly more quickly (and cost-effectively) than the AV guys can analyse and defend against it.

Now don’t get me wrong, AV still has its place in the security world – without it, sysadmins would have to deal with a deluge of common malware used by script kiddies. However, it’s no longer much more than a filter for the most basic attacks.

Kelihos.B takedown

There are two main points to take away from the Kelihos.B takedown. The first is that malware writers, as smart as they are, are really dumb.

Forget about malware for a moment, and imagine the architecture involved in Kelihos.B was part of a legitimate distributed-computing business system. Would you invest all that time and effort to build a P2P network and design a mechanism for message propagation, then leave it wide open to attack by failing to include any form of authentication mechanism? It’s complete lunacy. If you did it in a commercial environment, you’d get fired. Out of a cannon. Into the sun.

The second interesting point is that this botnet exclusively infected OS X, which is a pretty big shift in focus from the previous major botnets like Conficker and Mariposa. I’m actually surprise it took this long for a major OS X botnet to surface, considering the general stereotype of Apple users. They’re usually not tech-savvy, generally more wealthy than the average Windows user, and often under the illusion that “there are no viruses for Macs!”. The perfect storm of getting pwned.

I have a feeling it won’t be very many years before the distribution of malware across Windows and OS X ends up being close to equal.