Race Conditions

One commit at a time

Blackhoodie18 Berlin Bootcamp Report

In my previous post I wrote a few notes about the Blackhoodie18 Conference day. In this post, I’ll do a brief overview of some of the topics that were covered in the two day (intensive!) bootcamp. For some reason(most likely I did not read the track descriptions closely enough), I applied to track 3. The name (on my way to rock as hell) sounded super cool and I was really intrigued by the topics that were covered (intro to crypto, intro to Return Oriented Programming (ROP) and intro to Windows Kernel internals via building a keylogger). In reality, given my limited knowledge of reverse engineering, I should have probably applied to Tracks 1 or 2, but alas, I was scheduled for Track 3 and I was going to do my best prep to enjoy it as much as I could! A huge thank you to all of the instructors at Blackhoodie18! All of the mistakes in this writeup are mine and mine alone - please feel free to drop a note to camilla[at]synbyote.io if you have feedback/comments!

Introduction to Cryptography

The first day of track 3 was all about crypto! I was quite excited to revisit these topics. During my math degree at Bryn Mawr College, I was very interested in elliptic curve cryptography and I’ve been meaning to pick up this subject again (once time and work allows!) In addition to the maths-y part of crypto, I wanted to know more about the way crypto is implemented and the kinds of exploits that are possible against cryptosystems.

Our instructor Marion Videau had asked us to prepare for the bootcamp by writing down our expectations for the course. Mine were related to practical aspects: how do people find vulnerabilities in crypto systems, what kind of vulnerabilities are currently known, how does TLS work (I should have probably looked this up a long time ago), what kinds of changes will happen in the crypto field once we enter the post-quantum computing era, what new advances are there in the field of homomorphic encryption and so forth. I also had a brief look at some cryptopals challenges.

We started the workshop by taking a tour of the different levels of abstractions that a student of cryptography can encounter: hardware implementations, mathematical primitives, cryptographic mechanisms, protocols, cryptosystems etc. We then took a look at the TLS handshake between client and server and the aspects that go into establishing it and the kinds of questions one might ask when choosing a cryptographic system. We also went over in detail the basic building blocks of modern cryptosystems: symmetric and asymmetric ciphers, hash functions, MAC (message origin authentication), asymmetric signatures, crypto protocols and random sequence generation. I’m going to be going over my notes in depth a bit later and publishing some more notes, because this is some seriously cool stuff!

Introduction to Return Oriented Programming

The Return oriented programming (ROP) workshop led by chiliz starts with a recap of/intro to buffer overflows. In short, a program that is susceptible to the buffer overflow vuln can be tricked to overwrite some areas in the stack with material of the attackers choosing - for example malicious shellcode. However, most modern systems are protected from code injection into the stack by Data Execution Prevention (DEP) mechanism which prevents those areas of the stack that a program can write to from being executed (the so called NX-bit is set). So since we cannot inject some external code into the stack when exploiting a buffer overflow and then execute it, we need to find a way to re-use code that already exists on the system. To get a shell access from a program, we can always reuse the system call which is available in libc. This leads us to ret2libc - a special case of ROP.

ret2libc

The basics of a ret2libc attack are encompassed in the following steps: find a buffer overflow in the target program, overwrite the return address on the stack with the address of a libc function, for example system, which will allow an attacker to get shell access. Then, when the function that is vulnerable to the buffer overflow tries to return control flow to its caller, instead of returning up the stack, we will execute whatever libc function is at the address we used to overwrite the return pointer.

If we want our ret2libc attack to spawn a shell, we have to be able to pass an argument “bin/sh” to the libc function system. Since arguments are stored on the stack, we have to make sure to add “/bin/sh” at the location ESP+4 (offset of 4 from the register ESP) on 32-bit systems.

How do we find the memory locations that point to libc, system and the string “bin/sh” so that we can insert these addresses into the stack? We can use the vmmap function in gdb to find the absolute address of libc or alternatively the ldd command. Once we have the absolute address of libc, we need to find the offset of the system function within libc so that we can compute the absolute address of system and write it to the stack. We also need to perform a similar computation for “bin/sh”. Knowing the addresses of these two things will complete the malicious payload we need to write to the stack to take control of the execution of the program after the buffer overflow. We can find the offset to system within libc using readelf -s and then grepping for system. The -s flag will return only the symbols so we don’t have as much stuff to grep through. Using a similar fashion, we can find the offset to the string “/bin/sh” using strings -tx /path/libc and then grepping for /bin/sh. The -t flag tells strings to print the offset of the string and x option specifies that we want the offset to be in hexadecimal.

At this point, the water is starting to get preeeettty deep for me (the newbie, who ended up in track 3), but I’m still able to get shell access! Wohooo! Another workshop attendee was wondering how to pass command arguments to “/bin/sh” - for example so that one could automatically run some program without having to interact with a shell. Although we didn’t get to the answer during the workshop, this would definitely be something cool to explore on my own!

ROPgadgets

Now onwards to performing ROP on a 64bit program. Things are different here. For one, the register that holds the return pointer is different. I got a bit lost at this point, if I’m honest! However, the tactic employed in carrying out a ROP exploit in the 64bit case is something called a ROP chain, which is built from little existing bits of code from the binary called ROPgadgets. These can be discovered by passing the exploited binary through the ROPgadget.py search engine. It’s quite cool and a bit scary that you can glue together bits of the binary to cause an exploit!

Introduction to Windows Kernel Debugging

This workshop led by Gwaby was by far the most challenging one for me! Kernel internals! And on Windows, which is not my usual work environment. I was a bit poorly prepared for this workshop and for some reason the debug windbg environment I had setup on my Win10 machine was unable to talk to the Win10 debugee VM. After poking and prodding at the VM settings for the better part of an hour, I was able to find a forum post that suggested there may be some limitations on what data Win10 host will accept from a Win10 guest when the guest is using a NAT to connect to the internet and advised to try a host-only connection. Luckily, changing the VM debugee network settings to host only made the windbg connection work, but only towards the end of the workshop, so I have a lot of catching up to do! Expect some further posts on these topics very soon!