Windows 7 x64 Kernel Exploitation – Setup (1/3)

Several months ago, I took a short sojourn into the world of Windows Kernel exploitation, based on the work of hacksysteam and their excellent HackSys Extreme Vulnerable Driver (github here). I learned some things, and built a short community presentation on this, which was quietly presented a few times. I post this here in the hopes that someone finds this useful.

All of this work was done against a Windows 7 x64 target: when I get time, I will update this to a Windows 10 target (this may be a while). Fair warning, I am by no means an expert by any stretch of the imagination.

If you’d rather see a condensed presentation instead of my caffeine-fuelled shitposting, please download a PDF:

Without further ado:


As mentioned above, our target was set up as follows:

  • Host:
    • Windows 8.1 x64, Windows 10 x64
    • Visual Studio 2015 Community
    • Windows 10 DDK
    • VirtualBox
    • WinDbg
  • Guest:
    • Windows 7 x64
      • Windows 7 SDK (for cl.exe – but any language will work. you just need to call things)
      • FASM (because fuck you, visual studio. fuck you and your compiler intrinsics).
    • Hacksys Extreme Vulnerable Driver, self-built
    • OSR Loader (

We needed to use the “bcdedit.exe” utility to configure the target Windows 7 box to allow the loading of unsigned drivers, as follows:

bcdedit /set TESTSIGNING ON
bcdedit /copy {current} /d "lol" (this will return something, which we refer to as $GUID)
bcdedit /set $GUID debugtype serial
bcdedit /set $GUID debugport 4
bcdedit /set $GUID baudrate 115200
bcdedit /debug $GUID on

From here, we configure WinDbg in our guest to allow kernel debugging:

From here, start WinDbg on the host first, then start your guest VM, and when the boot menu pops up, select the appropriate debug option. You should see something like this:

From here, hit break in WinDbg, and enter the following, to enable kernel debugging via printf (well, DbgPrint):


From here, enter into your target VM, and use OSRLoader to load the vulnerable driver (HEVD_7x64.sys), and start the HEVD service. You should see something like the following:

In the next two parts of this series, we will explore actually exploiting two of the vulnerabilities within the HEVD driver (specifically, the arbitrary overwrite, and the stack overflow).

Posted in Uncategorized | Leave a comment

HG658 for Fun and Profit (AES Remix)

Recently, I took a look at a Huawei HG658 router for fun – this is a router common to multiple ISP’s across Australia, so a solid vulnerability in this would be significantly re-usable. The router I had in question was live and configured to TPG Internet, a “low-cost Internet” router, and I had physical access to the device, so hardware attacks were on the table.

I started my investigation by downloading a firmware image from our friends at iiNet, available here.

This is a JFFS2 image, which unpacks cleanly to a full filesystem. This is a typical MIPS-based firmware, which unpacks cleanly and emulates in a Debian MIPS Qemu. Upon a cursory inspection of the filesystem, the “telnetd” and “web” binaries stand out.

Initial reconnaissance indicates that port 23 runs a telnet server (as expected), port 80 and 443 run web servers, port 37215 runs something unidentified and port 37443 runs another web server, seemingly dedicated to serving images.

A quick Google search indicates the presence of several vulnerabilities (most notably, a local file disclosure from the port 37443 image web server) for this version of modem, but these appear to have been fixed in the version (re-) sold by TPG – so, down the rabbit hole we go.

A quick investigation of the telnetd binary indicates that it’s a wrapper for cli:

Continuing our investigation, we delve into the /var/cli binary. Quickly, we land at the function at 0x408224, which appears to handle authentication. A brief scroll through the code reveals something interesting:

Google indicates that this is a configuration setting which needs to be manually enabled in a configuration file to enable the Telnet interface. Some initial testing shows behaviour which matches the disassembly, so we download the configuration file from the router’s UI, decrypt it with, enable the magic parameter and reupload it.

While we’re there, a few interesting tidbits catch the eye. Firstly, what appears to be a TPG backdoor:

Secondly, we can see some backdoor accounts (I certainly didn’t create them):

Based on a bit of prior reading, I knew that the !!Huawei backdoor account password was “@HuaweiHgw”, which worked – however, this wasn’t the DES encryption as had been applied in previous versions of the firmware. A simple base64 -d | xxd doesn’t reveal anything I could immediately make sense of.

Going back to the ATP_CLI_AdaptAuthenticateCheck function, we can see that a new, shiny encrypted SHA256 function was in play:

By now, we could log in to the device itself using the !!Huawei account, and pull a fresh from the device (via ftpget: it turns out ftpput halts the device, as the name clearly indicates). Loading this into IDA, we can quickly review the ATP_SHA256_ENCRYPT function: it is immediately apparent that this function doesn’t actually encrypt anything, it simply performs a SHA256 hash:

However, we quickly notice other interesting functions within the file, such “ATP_CFM_ExtExportEncryptedCfgFile”, and “ATP_CFM_ExtDecodeParaValue”. We dive into the latter, as we are indeed after a single parameter (at this point: the password to the root account). The bulk of this function appears to be memory-admin related, with the actual decryption handled at sub_473C, a wrapper to a standard AES CBC decryption routine.

But alas, what do we see above it? Bingo: shiny new static keys –

Using these, we can quickly build a Python script, which grabs the encrypted password blob, and spits out a SHA256 hash of the root password, as well as the hash of the “!!Huawei” account, for confirmation. This is available here. I ran this through an initial wordlist and no dice, I’ll brute force this properly when I have time (or a beer for anyone who cracks it first).

Given the progress so far in working on this device, and the success in running it in an emulation setup (and thus, enabling the use of normal gdb), I intend to continue reversing the web server to identify additional vulnerabilities (I was somewhat peeved that the old ping command injection trick had been patched on this device – a shame).

I hope you enjoyed reading this 🙂

Posted in Bards, Computers, Jesting | Leave a comment

Signal Disruption via GNURadio

This weekend, I also spent some time looking into applied signal disruption. It is my firm belief that many security “professionals” talk too much shit about presumably easy things, but couldn’t change their MAC address without half an hour of Google. In my ongoing effort to avoid this, I spent some time trying some things out.

Remember kids, be ethical. Don’t be unethical. Thanks. Also happy Easter.

Unsurprisingly, building a generic jammer in GNURadio is rather easy (in practice: don’t forget to raise the sample rate because bladeRF won’t do 32k samples. 80k or no play):

To modify this to work on a Raspberry Pi (or similar handheld device) is an exercise in simplicity itself. This works on the principle of raising the noise floor: that is, typically, your computer’s WiFi baseband expects a signal similar to the following:

We simply overpower the signal with a random one of our own, to the point where the computer can no longer tell what’s a legitimate signal:

It is here that the power of the bladeRF device becomes apparent, with the device being able to comfortably disrupt a glorious 28Mhz of bandwidth around a central frequency.

After gaining the express written consent of everyone in my vicnity using my WiFi (and choosing a band I can’t see anyone else using), I then proceeded to test the effective range of this jamming, using GQRX on another laptop to detect to which point this would be effective. My test setup is as follows:

  • A bladeRF (the jamming device), using the above flow graph and a relative gain of 50 in gnuradio, using a low-gain omnidirectional 2.4Ghz antenna, purchased with the bladeRF.
    • It should be noted that the bladeRF has an extremely low transmit power (+6dBm), where a wifi router might transmit up to 20dBm.
    • It should also be noted that a commercial amplifier is available for the bladeRF (XB300) offering a tremendous +33dBm gain over 2.4Ghz.
    • The USRP B-series has significantly higher transmit power (10dbm). The prospect of using a B205-mini and a Raspberry Pi is tantalizing, to say the least.
    • It is apparently possible to raise this with a Low Noise Amplifier. I don’t have one, I wouldn’t know where to start with such a device.
  • A USRP B200 (the testing device), running gqrx to visually inspect the spectrum
  • An iPad (secondary testing device), using the interface to connect as usual
  • A laptop (secondary testing device, using iw’s scanning capability to detect the AP)

Some of my initial results (for brevity) are as follows:

  • At approximately 10M, with line of sight, jamming works. Devices almost instantly disconnect from WiFi.
  • At approximately 10M with two brick walls (within 5M of the broadcasting AP, with an iPad) between the jammer and the target, this no longer works. At this point, the SNR of the wifi connection is poor, but it’s a functioning connection.

To progress this, I’d also like to investigate the effectiveness of ad-hoc antennas, as well as the impact of various not-completely-random modes of signal disruption against traditional WiFi (as well as other low-powered devices) – there’s surprisingly little literature on the topic, even from overseas.

One day, I hope to be as excellent as this glorious gentleman:


The practical application of this are limitless – but the simplest is that in cases where you are attacking a system with a hardened WiFi stack, which ignores and reports active deauthentication (if you’re reading this – you know who you are, this one’s for you :P), you can still force the target to disconnect and re-authenticate.

Posted in Bards, Computers, Jesting | Tagged , | Leave a comment

Simple Packets via GNURadio

This weekend, I spent time learning about GNURadio and it’s applications, with a goal of building a generic packet-based (non-stream) messaging interface between SDR devices. While I was not entirely successful, I was able to fake this behaviour by manipulating a stream transmission. In this process, I also gained some understanding of the intricacies of GNURadio.

The hardware used in this process was a USRP B200 attached to a Linux system, and a BladeRF attached to a Windows system, sending traffic over a quiet part of the 2.4Ghz spectrum: however, this should work anywhere (just adjust frequency and sample rate, and fix the osmocom source and sink).

I will document my progress here for future reference.

Simple File Transfer

I began by simply transferring a file between one system and another.  We start by creating a file source block, with output format selected to byte. We then pass this through a Packet Encoder block, and then prepare for transmission via a GMSK modulator. We multiply the output complex number by 1.0 (todo: why?), and pass this via an osmocom sink. The flow graph looks something like this:

We can confirm this “works”, via both the FFT sink (showing power over frequency over time), as well as an independent GQRX.

The illustration above shows a vector source pointing to a variable, but this is functionally equivalent (and works as well).

To receive the file, we simply do the reverse: from an osmocom source, we multiply by complex 1.0, decode the packet, send it through a low pass filter (to remove noise from nearby frequencies), demodulate the data (GMSK demod), decode the packets and write to file:

A quick test confirms we can send and receive an arbitrary stream of data via GNURadio.

Message PDUs / Message Strobe

From there, my research (and by research I mean Google) showed that I could presumably use the “Message Passing” interface to translate messages. Beginning from Dr. Aaron Scher’s example here, I attempted to glue this on to my existing flow graph, replacing the source with a Message Strobe, presumably converted to bytes:

  • Using a Message Strobe function to send a message every 500 ms
  • Create a tagged stream with an output format of byte
  • Build a header, and repack at a 1:8 compression rate (i.e. each bit is now represented as one byte in the output)
  • Treat this as a stream, pass it by GMSK modulation and send, as if it were a file.

Unfortunately, while an FFT sink showed that *some* signal was coming out of the GMSK modulator, a stream receive on the other end (to file) did not show the expected data. For reference, my flow graph was similar to the below:

On further research, it appears that this is not the intent of the message passing interface: instead, it is intended for use as “commands” to send around your flow graph: for example, if you receive a signal above a certain strength, retune your SDR Device to another frequency (via a “Message”). This will no doubt be useful later – I’m thinking jamming-resistant SDR.

It should be noted here that a quirk of the UI is apparent: the “repack bits” block actually requires a length tag to function correctly, but even if you set it, it’s not shown in the graphical view of the flow graph.

Modifying the Vector Source

After a few hours of learning about the Message interface, I attempted to solve this problem by utilising the file transfer code above, and simply modifying the Vector Source to transmit different data. This could be done by directly modifying the Python generated by gnuradio, to introduce a new thread created as the top block is initialized, which modifies the data used by the vector source:

This vector represents a simple custom packet format:

  • The first four bytes are a static header, consisting of the bytes 1, 2, 3 and 4
  • The next byte is the length of the packet data
  • The next byte is a packet ID. The receiver should reject packets with ID’s it’s seen before.
  • The next four bytes are the packet data. This is variable length.
  • The next and last four bytes are a footer, consisting of the bytes 5, 6, 7 and 8.

To receive this, we simply modify the file receive script, with a custom Python sink:

The flow graph is extremely simple, with the only change to accomodate the new packet sink:

This works, but causes overflows on the receiver. I suspect this is due to the Python message sink being too slow: that is, it takes too long to process messages, so the hardware’s receive buffer fills, and it “drops packets”.

I believe I can optimize this via a Vector sink, and using gnuradio’s “Probe” mechanism to constantly poll the value of the resultant Vector, leaving gnuradio to do the heavy lifting of data transfer.

I will continue to improve this work and document my progress.

Posted in Bards, Computers, Jesting | Tagged | Leave a comment

Writeups – Slumdog Millionaire, Purple Posse Market, Matroichka 1,2 (Nuit du Hack Quals)

Last weekend, I had the pleasure of once more participating in the Nuit du Hack qualifier CTF. Similar to last year, I found this to be an enjoyable event, even though my lack of skill and focus meant I was not able to solve many challenges. As always, I will document some of the interesting challenges I encountered.

I should note that from here, I will make an attempt to tackle web-based challenges, as this is an area that I am particularly and notably weak in.

Without further ado:

Matroichka 1

As last year, a four-part matroichka reverse engineering challenge was presented in this year’s CTF. You can download the original binary (as well as an unpacked Part 2) here.

I began my analysis by loading step1.bin into IDA Pro. The first challenge was a string comparison check, with a few distraction functions (“mmm”, “you” and “touch”). The core of the functionality is here:

A quick breakpoint at 0x4007A0  reveals two things:

  • Our input string is reversed, and;
  • The “target” string is Tr4laLa!!!

Running the program with an argument of “!!!aLal4rT” (appropriately escaped, of course) quickly revealed the second part of the binary, which is detailed below.

Matroichka 2

This binary is included with the download for Matroichka 1. Alternatively, just run Matroichka 1 with the correct flag, and this binary will be printed on stderr.

Again, I began my analysis by loading this binary into IDA Pro. This revealed a far more complex binary than the first:

Judging by the structure of the program, this did not appear to be an angr-style solve, so I delved further into the program. After some analysis, the structure of the program became clear:

  • Firstly, the program checked if argv[0] was “./step2.bin”. This would prevent the program from running correctly under gdb, as well as if it was incorrectly named.
  • Then, the program utilised a strange chained block cipher (utilizing simple XOR) along with some signal handler trickery to check the key.

Firstly, in order to overcome the argv[0] check, it was sufficient to re-write argv[0] at program execution, with the following steps:

  • break *0x4007CC
  • set {char[12]} $rax = “./step2.bin”
  • c
  • break *0x400879

Following this check, the program then checked if the first character of the flag (entered in argv[1]) was “W” (at 0x40085C). From here, the real “meat” of the program begins:

Immediately noticeable is the use of signal() to install a signal handler, as well as the unusual use of the “cmovz” instruction to select which signal handler is installed (either 400AC6 or 400AD0).

In a nutshell:

  • for each letter of our input:
    • if it’s even, subtract it’s value from the next character, mod 256 (and replace the next character with this)
    • if it’s odd, add it’s value to the next character, mod 256 (and replace the next character with this)

Following this, a static block of data (divided up into dwords) is then chain XOR’ed with 0xDEADBEEF: that is, 0xDEADBEEF is the xor key for the first block, the xor’ed first block is the xor key of the second block, and so forth. This slightly enciphered block is then compared with our mutated input (as above).

Due to the predictable nature of this algorithm (and that we know the first character of the key, “W”), we can quickly derive a Python script to work backwards: that is, we first reproduce the XOR code, and then we work backwards to derive what each character of the flag is.

You can download the solution script here.

Slumdog Millionaire

This challenge was presented as a web challenge, along with an associated Python file, which you can download here.

The website appeared to represent a lottery website: you could enter a set of random numbers, and the site would tell you if you guessed correctly or incorrectly (and print the correct set of numbers). The Python file above provided the algorithm behind the lottery game:

The algorithm appears to have a single point of failure: that is, the random number generator is seeded once – once you know the random number, the actual number generation isn’t very random.

The attack against this is a simple brute force search against the random seed used: given one set of winning numbers, we can easily determine the random seed, and thus predict the next set of numbers.

You can download the brute force solution script here.

Purple Posse Market

This challenge was presented as a raw web challenge, appearing to represent a legitimate web business. The purpose of the challenge was to determine the administrator’s IBAN number (think bank account):

After browsing the site for a few moments, we hit gold with a contact form:

Experience says that this is a cross-site scripting challenge: I quickly spin up a bucket, and try submitting a few contact forms. After a few tries (input filtering?), we get lucky, and end up with an administrator cookie:

From here, it is simple to read the /admin site with an administrator cookie, and retrieve the administrator’s IBAN number, for an easy 200 [?] points:

As always, I’d like to thank the Nuit du Hack organisers for putting together another enjoyable event, and I particularly look forward to solving the remainder of the Matroichka challenge, as time permits (level 3 is a fork-based mindfuck).

See you all in the ASIS CTF this weekend.

Posted in Bards, Computers, Jesting | Leave a comment