Talking about Windows drivers at 44CON 2015’s Community Evening

I’ll be speaking at 44CON this year, at the community evening on Wednesday 9th September. The community evening is free to attend – you just need to register to attend if you don’t have a conference ticket. My talk is currently scheduled at 19:45, and I’m speaking about writing Windows drivers, with the goal of leaving you a bit more informed about how they work, and how to get started.

In addition to my talk, Saumil Shah will be speaking about Stegosploit, and Michael Boman will be running a workshop on anti-analysis techniques used in malware. After the talks, there will be a showing of the 20th anniversary edition of Hackers, which is guaranteed to be fun.

As usual, there will be drinks and good conversation. Hope to see you all there! :)

W^X policy violation affecting all Windows drivers compiled in Visual Studio 2013 and previous

Back in June, I was doing some analysis on a Windows driver and discovered that the INIT section had the read, write, and executable characteristics flags set. Windows executables (drivers included) use these flags to tell the kernel what memory protection flags should be applied to that section’s pages once the contents are mapped into memory. With these flags set, the memory pages become both writable and executable, which violates the W^X policy, a concept which is considered good security practice. This is usually considered a security issue because it can give an attacker a place to write arbitrary code when staging an exploit, similar to how pre-NX exploits used to use the stack as a place to execute shellcode.

While investigating these section flags in the driver, I also noticed a slightly unusual flag was set: the DISCARDABLE flag. Marking a section as discardable in user-mode does nothing; the flag is meaningless. In kernel-mode, however, the flag causes the section’s pages to be unloaded after initialisation completes. There’s not a lot of documentation around this behaviour, but the best resource I discovered was an article on Raymond Chen’s “The Old New Thing” blog, which links off to some other pages that describe the usage and behaviour in various detail. I’d like to thank Hans Passant for giving me some pointers here, too. The short version of the story is that the INIT section contains the DriverEntry code (think of this like the ‘main()’ function of a driver), and it is marked as discardable because it isn’t used after the DriverEntry function returns. From gathering together scraps of information on this behaviour, it seems to be that the compiler does this because the memory that backs the DriverEntry function must be pageable (though I’m not sure why), but any driver code which may run at IRQLs higher than DISPATCH_LEVEL must not try to access any memory pages that are pageable, because there’s no guarantee that the OS can service the memory access operation. This is further evidenced by the fact that the CODE section of drivers is always flagged with the NOT_PAGED characteristic, whereas INIT is not. By discarding the INIT section, there can be no attempt to execute this pageable memory outside of the initialisation phase. My understanding of this is incomplete, so if anyone has any input on this, please let me know.

The DISCARDABLE behaviour means that the window of exploitation for targeting the memory pages in the INIT section is much smaller – a vulnerability must be triggered during the initialisation phase of a driver (before the section is discarded), and that driver’s INIT section location must be known. This certainly isn’t a vulnerability on its own (you need at least a write-what-where bug to leverage this) but it is also certainly bad practice.

Here’s where things get fun: in order to compare the driver I was analysing to a “known good” sample, I looked into some other drivers I had on my system. Every single driver I investigated, including ones that are core parts of the operating system (e.g. win32k.sys), had the same protection flags. At this point I was a little stumped – perhaps I got something wrong, and the writable flag is needed for some reason? In order to check this, I manually cleared the writable flag on a test driver, and loaded it. It worked just fine, as did several other test samples, from which I can surmise that it is superfluous. I also deduced that this must be a compiler (or linker) issue, since both Microsoft drivers and 3rd party drivers had the same issue. I tried drivers compiled with VS2005, VS2010, and VS2013, and all seemed to be affected, meaning that pretty much every driver on Windows Vista to Windows 8.1 is guaranteed to suffer from this behaviour, and Windows XP drivers probably do too.

INIT section of ATAPI Driver from Windows 8.1

While the target distribution appears to be pretty high, the only practical exploitation path I can think of is as follows:

  1. Application in unprivileged usermode can trigger a driver to be loaded on demand.
  2. Driver leaks a pointer (e.g. via debug output) during initialisation which can be used to determine the address of DriverEntry in memory.
  3. A write-what-where bug in another driver or in the kernel that is otherwise very difficult to exploit (e.g. due to KASLR, DEP, KPP, etc.) is triggered before the DriverEntry completes.
  4. Bug is used to overwrite the end of the DriverEntry function.
  5. Arbitrary code is executed in kernel.

This is a pretty tall order, but there are some things that make it more likely for some of the conditions to arise. First, since any driver can be used (they all have INIT marked as RWX) you only need to find one that you can trigger from unprivileged usermode. Ordinarily the race condition between step 1 and step 4 would be difficult to hit, but if the DriverEntry calls any kind of synchronisation routine (e.g. ZwWaitForSingleObject) then things get a lot easier, especially if the target sync object happens to have a poor or missing DACL, allowing for manipulation from unprivileged usermode code. These things make it a little easier, but it’s still not very likely.

Since I was utterly stumped at this point as to why drivers were being compiled in this way, I decided to contact Microsoft’s security team. Things were all quiet on that front for a long time; aside from an acknowledgement, I actually only heard back from yesterday (2015/09/03). To be fair to them, though, it was a complicated issue and even I wasn’t very sure as to its impact, and I forgot all about it until their response email.

Their answer was as follows:

After discussing this issue internally, we have decided that no action will be taken at this time. I am unable to allocate more resources to answer your questions more specifically, but we do thank you for your concern and your commitment to computer security.

And I can’t blame them. Exploiting this issue would need a powerful attack vector already, and even then it’d be pretty rare to find the prerequisite conditions. The only thing I’m a bit bummed about is that they couldn’t get anyone to explain how it all works in full.

But the story doesn’t end there! In preparation for writing this blog post, I opened up a couple of Microsoft’s drivers on my Windows 10 box to refresh my memory, and found that they no longer had the execute flag set on the INIT section. It seems that Microsoft probably patched this issue in Visual Studio 2015, or in a hotfix for previous versions, so that it no longer happens. Makes me feel all warm and fuzzy inside. I should note, however, that 3rd party drivers such as Nvidia’s audio and video drivers still have the same issue, which implies that they haven’t been recompiled with a version of Visual Studio that contains the fix. I suspect that many vendor drivers will continue to have this issue.

I asked Microsoft whether it had been fixed in VS2015, but they wouldn’t comment on the matter. Since I don’t have a copy of VS2015 yet, I can’t verify my suspicion that they fixed it.

In closing, I’d like to invite anyone who knows more than me about this to provide more information about how/why the INIT section is used and discarded. If you’ve got a copy of VS2015 and can build a quick Hello World driver to test it out, I’d love to see whether it has the RWX issue on INIT.

Disclosure timeline:

  • 29th June 2015 – Discovered Initial driver bug
  • 30th June 2015 – Discovered wider impact (all drivers affected)
  • 2nd July 2015 – Contacted Microsoft with report / query
  • 2nd July 2015 – Microsoft replied with acknowledgement
  • 6th July 2015 – Follow-up email sent to Microsoft
  • [ mostly forgot about this, so I didn’t chase it up ]
  • 3rd September 2015 – Microsoft respond (see above)
  • 3rd September 2015 – Acknowledgement email sent to Microsoft, querying fix status
  • 4th September 2015 – Microsoft respond, will not comment on fix status
  • 4th September 2015 – Disclosed

Another year, another Securi-Tay, another talk… and this time we’re sponsoring the bar!

Another year has rolled by (damn, I really don’t update this blog much, do I?) and Securi-Tay IV is coming up. I’ll be speaking about security issues related to serialisation and deserialisation of data in modern programming languages, including PHP and C#.

My colleague FreakyClown will be talking about robbing banks for a living, which promises to be amusing at the very least (which reminds me – ask me about coathangers and server rooms when you see me).

Most importantly though: we (and by that I mean Portcullis) are sponsoring the bar this year! I hope to see you all there for plenty of drunken security rambling.

Pentesting Java EE web applications with LAPSE+

Just a quick tip for anyone doing a code review of a Java EE web application: LAPSE+ is a very useful tool to have in the arsenal, whether you’ve got the original source or just the JAR/WAR file.

In my case, the client provided me with a single .WAR file which contained the application. As it was a large application, I didn’t really fancy digging through everything manually with JD-GUI, although it is an excellent Java decompiler. I decided to take the opportunity to give LAPSE+ a try.

Here’s what  you’ll need:

You can also grab a PDF instruction manual for LAPSE from the same site. However, be aware that I found some of the information in there to be a bit misleading, e.g. needing a specific version of Eclipse. Also, don’t worry if your client provided you a project for a different IDE, such as IntelliJ IDEA – it doesn’t really matter.

First step is to get Eclipse set up. Drop the .jar file from the LAPSE+ archive into the plugins directory of Eclipse. (Re)start Eclipse, then go to Window -> View -> Other… and select the items relating to LAPSE+. A little toolbar should appear on the right with blue spherical buttons. These are your LAPSE+ windows.

Next step is to load your code into a project. This is split up into two parts, but if you’ve already got an Eclipse project for the site’s source code, you can skip the first part. Otherwise, you’ll need to extract the code from your archive and make a project for it. Start by loading the JAR (rename the .WAR to .JAR if needs be) into JD-GUI. It should decompile the archive and let you browse the code. Go to File -> Export all Sources, and save the resulting ZIP file somewhere. This archive now contains all your decompiled source code, split into directories based on the namespace hierarchy.

Now, go back to Eclipse and create an empty Java project, filling the wizard out with whatever values suit you. Once that’s created, go into the project explorer tree and find the src directory, then right click it and select Import. Select your newly exported ZIP file, and Eclipse will populate your project with your reverse-engineered source. Now right-click the project and select Build. In all likelihood, it’ll throw a whole load of errors due to imperfect decompilation – don’t worry, we don’t really care, because LAPSE+ can still function with a broken build.

Once you’ve got your project set up, go to the individual LAPSE+ windows and browse through what they found. You might need to manually refresh them to run through the checking process. In my case, I found about a 10:1 ratio of false positives, which isn’t actually too bad for code scanning. Within an hour or so of digging through the results I’d found a couple of concrete XSS bugs that I’d not spotted yet, plus a whole bunch of potential XSS bugs that I couldn’t immediately find vectors for, and a whole variety of other interesting stuff to dig through. It’s a really nice way to cut down a 400kLoC project into manageable target points.

Talking about crypto at Securi-Tay 2014 (Dundee, Scotland)

I’m doing a talk about cryptography at Securi-Tay 2014 on the 15th of January, up in Dundee, Scotland. The talk is aimed at people who are interested in cryptography from a practical perspective, but are put off by the slew of hieroglyphs and maths-speak that tends to plague the field. The talk is entitled “Breaking bad crypto without breaking your brain”. I promise that there are no Breaking Bad references in there, primarily because I seem to be the only person on earth that still hasn’t started watching it.

Securi-Tay is a great conference, organised by Ethical Hacking students at the university, with some help from other nice folk and sponsors. I attended (and spoke) last year, and it was great from both technical and social aspects. There’s a really good line-up of talks so far, and it’s always great to see the student talks dealing with things from brand new perspectives, as well as the staple talks from professionals and seasoned researchers.

Tickets are £20 a head, and there’s free booze after the con, so it’s an absolute bargain – come join us!

Steam Code Execution – Privilege Escalation to SYSTEM (Part 2)

In my previous post I talked about a vulnerability in Steam which allows you to bypass UAC. I’m going to be totally transparent here: I fucked up. I wrote the draft post a few days back, then did some more work on the vulnerability. I discovered something much more serious in the process. I posted last night’s blog post at 1am, tired as hell, and in my sleep-deprived state I completely neglected to update it properly, and there are several mistakes and bits of missing information. The draft went out and confused a lot of people. So, for that, I apologise. I’m going to leave it there so people can see it, because it’ll remind me not to do that next time.

Now, onto the real impact of the vulnerability: I can leverage it to gain code execution as SYSTEM. How? Well, it turns out that Steam.exe gives itself one unusual privilege – the privilege to debug other processes. This is called SeDebugPrivilege and one of its features is that it allows the process to bypass access control lists (ACLs) on processes when you call OpenProcess, i.e. the process can open a handle to any process it likes, with any privilege it likes.

Here’s how you can elevate to SYSTEM when you have SeDebugPrivilege:

  1. Open a handle to a process that is running as SYSTEM, with PROCESS_ALL_ACCESS as the access flag.
  2. Use VirtualAllocEx to allocate a block of memory in the remote process, with the executable flag set.
  3. Use WriteProcessMemory to copy a block of shellcode into that memory buffer.
  4. Use CreateRemoteThread to create a new thread in the remote process, whose start address is the base address of the memory allocation.
  5. Bingo! You just got a privesc to SYSTEM.

In this case, once you’ve got code execution inside Steam, you can utilise this trick to escalate yourself to SYSTEM. There’s your privesc vuln.

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.