Writeup – pinlock (BSides San Francisco)

This past weekend, I participated to some degree in the BSides San Francisco CTF, the HackIM CTF and Codegate Qualifier CTF. Due to the baleful glare of the Day Star pushing temperatures to above 40 degrees in Australia, my participation in these events was limited.

That said, I was able to participate in a good portion of the BSides San Francisco CTF. While a number of challenges was solved, I will present my writeup of the “pinlock” challenge, which I solved with some assistance from our friends at Capture The Swag (who pointed me to the README file, after I missed it initially).

Pinlock

This challenge was presented as an Android application file, which you can download here.

Our initial steps are to unpack the challenge (unzip the APK), attempt to convert the classes.dex file to a JAR file, and then decompile the JAR. This process works quickly, and we are able to begin source code review of the application in jd-gui:

1

From this viewpoint, we can immediately see some interesting code, in the SecretDisplay class, and the releated CryptoUtilities class. We can see the application works in the following logical manner:

2

From here, we should note the README file in the “assets” directory, indicating a switch to “v2” of the database (while the code indicates “v1” is in use, code for what is presumably “v2” is also present).

Our next stop is the “pinlock.db” database: we note that we can extract a secret from both secretsDBv1 and secretsDBv2, which is presumably the flag:

4_fetchdata

At this point, we have both the decryption algorithm, as well as the secret to be decrypted – we are only missing the key, which is derived from a user’s PIN. The PIN is 4 digits long, so this is an easily brute-forceable problem, but we note the presence of the “fetchPin” function within the code:

3_fetchpin

One more trip in to the database, and we can grab the PIN:

5_fetchpin

This looks suspiciously hash-like, so we pass it through crackstation.net, to derive the correct PIN of “7489”.

From here, we have all we need to build our own decryption app, copying and pasting code from the challenge application itself to make our lives easier. A few moments of Java later:

6_flag

You can download the Java solution file here – please forgive my shitty Java, it’s been a while.

I would like to thank the organisers of all three CTF’s this weekend – thankyou for putting together these events for everyone to enjoy, and while I was not able to participate in much of these events, I enjoyed the challenges presented.

See you all in the Boston Key Party Qualifier and VolgaCTF Qualifier in two weeks time!

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

Writeups – Catalyst, UnVM Me, Unknown Format, Mailclient

This weekend, I participated in the AlexCTF competition, hosted by Alexandria University. Overall, this event was easier than many previous CTF’s, with the last challenges being released significantly spiking the difficulty.

As always, I will present writeups for the challenges I found most interesting below:

Catalyst

This challenge was presented as an x86 ELF binary, which you can download here. From initial analysis, the structure of the program is as follows (the functions were not initially named thus, this is from an in-progress IDA session):

rev150-initial

We begin our investigation by trying to call the do_flag function directly. Unfortunately, this produces an invalid flag. On further investigation, we note that the flag is derived from the password:

rev150_doflag

Our first step is to patch out the delay calls. Once done, we can focus on the four “check” functions towards the bottom right. By observing which paramters (corresponding to fgets calls) match which arguments are passed to the functions – we can tell that the first three functions check for the username alone. The first function is reasonably uninteresting:

rev150_check_strlen

The next function appears to be a series of linear equations:

rev150_check_username

From this, we can observe the following:

  • The username is likely 12 characters in length, as it is divided up into three 32-bit register-sized chunks for processing here.
  • Part0-Part1+Part2 = 0x5C664B56
  • (Part0+Part2)*3 + Part1 = 0x2E700C7B2
  • Part1 * Part2 = 0x32AC30689A6AD314

Furthermore, we can also determine the valid character set (‘a’-‘z’ + ‘_’) by looking at the third check function.

This is enough to derive the username via a “cheap” brute-force attack – by checking for all the combinations where:

  • Each byte of Part1 is a legitimate character
  • Part2 = 0x32AC30689A6AD314 / Part1
  • Each byte of Part2 is a legitimate character

We can determine that Part1 is “lyst” and Part2 is “_ceo”: making the username “catalyst_ceo”. We can confirm this with a breakpoint at the fourth check function (0x400977), which gets hit:

rev150_breakpt

From here, we can continue on to an analysis of the fourth check function. This check function uses the “username” to seed a PRNG, which is used to generate a series of random numbers to validate the password. No problem, we can simply breakpoint each of the checks, to reveal the password, four characters at a time:

rev150_breakpw

Slowly, bit by 4-byte bit, we build up our password, eventually revealing the flag:

rev150_flag

UnVM Me

This challenge was presented as a compiled Python file, which you can download here.

For this challenge, we can use the “uncompyle” utility, which spits out a nice chunk of Python source code, complete with symbols:

rev250_unvmme_fixed

From this, we know that the program will accept a flag, and “match” each chunk of 5 characters from a user input (the flag) against a set of known MD5’s – if all of them match, you’ve got the flag.

The solution to this is a trivial efficient brute force of the 5-character keyspace, noting down which “chunks” match the known MD5’s, revealing the flag after a few moments of brute forcing:

rev200_flag

You can download the solution script here. It’s not pretty, and requires about 5 minutes of manual “sorting the chunks” after you’re done, but it works.

Unknown Format

This challenge was presented as a packet capture file, which you can download here.

Upon initial analysis, we can see that this is a USB bulk data transfer capture. We begin by reconstructing the file being transferred:

for200-usbcap

Having recompiled the file,a quick inspection reveals this to be a Kindle Update file – the “SP01” header is a tell for this, and the filenames referencing books are but more confirmation.

Nothing obvious showed up in the file itself, but a bit of Google led to a tool for hiding data within Kindle Update files:

for200-lolgithub

A bit of compiling later, and we are able to extract another file from the original update binary. Unlike the original, this file contains a surprise:

alex_lol_gzip

One “-e” argument to binwalk later, and we have another extracted file containing what appears to be garbage. This time, strings reveals success:

alex_forensics_flag

Mailclient

This challenge was presented as a GDB core file, which you can download here. The goal of the challenge was to find a username and a password.

Initially, I had no idea how to tackle this challenge. I began by manually inspecting the file in a hex editor, and using “strings” to extract interesting text. From what I could derive, this was a crash dump from the “mutt” mail client (i.e. the clue about this being a Thunderbird crash was a troll).

Initially, I identified some promising content: an email address (alexctf@example.com) and an [sm]tp_pass variable, containing a password:

alex_forensics_mutt

Unfortunately, sending these yielded no success. My next avenue of attack was to install “mutt”, and try to use GDB to search through the program memory – unfortunately (and logically, in hindsight), this too was fruitless – besides, any interesting data would be contained in the core file, legitimate mutt install or not.

I then applied the power of brute force best force, simply trying to log in to the challenge server with “alexctf@example.com” and each of the strings in the binary as the password:

alex_forensics_lol_2

You can download the brute force script here. The “uniqnotes” file is simply a sorted list of unique strings, generated from the core file.

As always, I would like to thank our hosts, Alexandria University, for putting on this event. I enjoyed the event overall, and I believe this is the first such CTF (at least I didn’t see it last year) – if so, well done for putting together this event and having it run so smoothly.

See you all next week in HackIM / Codegate Qualifiers!

Posted in Bards, Computers, Jesting | Tagged , | 2 Comments

Writeup – Simple Secret 2 (Break In CTF), grgsm_livemon Headless Mode

During the last week, I participated in the Break In CTF. Unfortunately, I completely neglected to take notes or save binaries, therefore, I can only provide a single writeup, based on the only binary I saved.

Simple Secret 2

This challenge is presented as a Linux binary, which you can download here.

 

Upon initial analysis, we can see that this binary takes an input string, processes it somehow, then compares it against an existing string:

breakin-comp01

If this check succeeds, the program then makes an HTTP GET request to the CTF server, which retrieves the flag.

Going a bit further, we can investigate the “input processing” function, at 0x400BB6:

breakin-comp02

The rand() call is a little worrying – if it turns out that input is somehow combined with random input, we’ll need to either patch this out, or use an LD_PRELOAD hook to make the results of this static for testing purposes.

Our next step is to study this a bit further at runtime using gdb, to break on the strcmp call, to see if we can see anything obvious:

breakin-lol

Quickly, we can see that we got trolled, and it’s simply comparing our input against a static string. With this string in hand, we try to run the program again, giving us the flag:

breakin-win

As always, I would like to thank the organisers of the Break In CTF for organising this event. Looking on their website, it appears they run events quite frequently, and in a well organised manner – congratulations to the team for pulling this off. I enjoyed this event (what little time I could spend on it), and look forward to the next one.

grgsm_livemon Headless (+ misc. thoughts)

During this weekend, I also spent some time playing around with my bladeRF. While I am by all accounts a noob, I’ve quickly found this device to be quite versatile, but the interface with which to speak to it (i.e. gnuradio) is rather significant.

bladerf_fuckyou

I am currently working on understanding the GSM stack, and as part of this, I have modified the grgsm_livemon code to work in headless mode, with no dependency on Qt. You can download this code here.

(It turns out that the Python generated by gnuradio-companion is generally pretty old).

I look forward to exploring more of the SDR world, and posting more about what I learn.

See you all next week in AlexCTF.

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

Writeup – bender_safe (Insomni’hack 2017 Teaser)

This weekend, I participated in the Insomni’hack 2017 Teaser. During this CTF, I got schooled pretty hardcore, but I was able to solve one challenge in the time allocated. I will write this challenge up below.

bender_safe

This challenge is presented as a Linux MIPS binary, as well as a standalone qemu-mips wrapper. You can download this binary here.

This binary presents the user with an “OTP challenge”, for which the user must generate the correct corresponding token:

bender_safe

We begin our adventure by reverse engineering the code. We can determine that this reads 8 bytes of OS-generated random data, and then transforms this into the OTP challenge. From there, it accepts the USB input, and attempts a complicated validation function against the OTP challenge. From the disassembly graph overview alone, it is apparent that the intended solution is angr:

plsno

However, upon closer inspection, we can determine there is a minor quirk which allows us to find a solution without resorting to angr – for each “block” of the validation function, a failed check will result in a call to exit, with the exit code being the number of the check that failed. Thankfully, qemu-mips will pass on this exit code to the user.

This means we can trivially brute force the correct answer for any OTP challenge. We simply need to tweak the binary to accept an OTP token from disk (instead of generating it from /dev/urandom):

modified_load

also read 0x10 instead of 0x8

This allows us to “lock” the OTP challenge to a single user-specified value (whatever we read from the challenge server).

From there, we simply brute force each character in sequence until the exit code changes. When the exit code changes, we “lock” the correctly guessed character in place, and restart the cycle for the next exit code:

bruteforcebestforce

This quickly reveals the correct code, and the flag:

flag_lol

You can download the python script for this brute force here – note that it doesn’t always work (qemu can be a bit finicky), if it doesn’t work, generate a new OTP token and try again.

Tools Update – retdec.com / Retargetable Decompiler

During this CTF, I made use of the free decompiler service offered by retdec.com, provided courtesy of AVG. This decompiler will accept an upload of a binary file (including, surprisingly for the cost, non-x86/x64 files), and output a decompiled C file.

Note that free-but-registered users are limited to 10 minutes of maximum decompilation time, which can cause an issue with large files. To get around this, I advise disabling decompiler optimisations. The output looks just like as if someone had pressed F5 in IDA:

bender

As always, I’d like to thank the organisers of the Insomni’hack 2017 Teaser CTF for putting together an enjoyable and challenging event. See you all in AlexCTF!

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

Late Writeups – cheer_msg, jmper (seccon)

Recently, I progressed through the “cheermsg” and “jmper” challenges from the SECCON CTF event last year. I was not able to solve these during the time allocated for the event. I will document my solves below.

Note that both challenges rely on libc – for ease of testing, I have done these with my CTF VM’s libc, instead of the provided ones.

cheer_msg

This challenge was presented as a binary with libc, you can download this here.

Disassembling the challenge, we can determine the vulnerable function is a “write-what-where” in the “message”, stemming from an extremely oddly constructed pointer based on the message length first entered by the user:

cheer_msg_x

By specifying a negative message length, we are able to write to arbitrary locations on the stack. Specify -152, and we’re able to write to the return address of the current function:

cheer_msg_huzzah

From here, this is a reasonably straightforward exercise in multi-stage ROP chains. Our ultimate goal is to make a call to system(“/bin/sh”). To do this, we construct multiple ROP chains which return to main:

  • ROP Chain 1: Infoleak GOT (to derive system in libc)
    • printf
    • main (return address)
    • 0x0804A010 (printf in the GOT)
  • ROP Chain 2: Seed /bin/sh into the data section
    • getnline
    • main (return address)
    • 0x0804A030 (data section)
    • 0x41414141 (length. doesn’t really matter)
  • ROP Chain 3: Call system
    • system (derived from initial infoleak in ROP chain 1)
    • main (return address – may as well be exit())
    • 0x0804A030 (data section)

A quick Python script later, and we have a shell:

cheer_msg_shell

Note the initial failure: this doesn’t always work cleanly, if an address in the GOT contains a zero (and terminates the infoleak too early), we simply exit and try again. It is possible to continue ROP chaining to leak more bytes of the GOT, but given the possibility of a GOT address containing a zero versus the possibility of it not, it’s faster to just try again.

You can download the Python script here.

jmper

This challenge was presented as a binary with libc, you can download this here.

This challenge is presented as an executable which allows operations on a number of “students”. Each “student” is represented in memory like this:

struct student{
  char memo[0x20]
  char *name;
}

The application allows the user to create students (which malloc’s the structure above as well as the ‘name’ and stores it in a big array), and view or edit the memo or name of any existing student record.

The vulnerability comes in the form of an off-by-one in the “write memo” function: this allows a user to write a single byte past the end of a memo or a name:

jmper_vulnfunction

It’s possible to abuse this to create a limited read/write-what-where condition, by overflowing the “memo” field for student zero, one can write within a limited space surrounding student zero’s “name” field:

jmper_overwriteptr

 

As illustrated above, we are able to exert limited control over the name pointer of a student object. With this limited level of control, we can read and write to an arbitrary location. We can relax this restriction, by creating a second student object, and overflowing student[0].memo to make student[0].name point to the address of student[1].name.

We don’t need to know where it is exactly, but if we know where it is relative to student[0].name, and that’s within a single-byte-overflow range, we’re in business – and this relative distance isn’t changing between execution’s so ASLR isn’t a problem.

We then set student[0].name (pointing to student[1].name’s address) to an arbitrary address (e.g. the GOT), and then read it via reading student[1].name (which is now set to the GOT).

This becomes an arbitrary read-write-where primitive. From here, we can use the setjmp/longjmp functionality to gain code execution:

setjmp_longjmp

We can abuse this functionality, as we know that setjmp “saves” the state of execution to a buffer, the address of which is stored locally: between the read-write primitive, the GOT and the setjmp buffer, we should be able to return execution to system pretty easily – unfortunately, it isn’t that simple. Viewing the buffer in gdb shows the following:

jmper_showbuf

Oddly enough, what appears to be RIP and RSP in the jump buffer isn’t, it’s actually what’s stored in the red box. A bit of documentation surfing and traipsing through the disassembly of setjmp, and we can determine that the pointer is mangled through a rather simple function:

PTR_MANGLE = (PTR ^ FS30_STACK_COOKIE) ROL 0x11

Using this, we can de-obfuscate the pointers cleanly and write our own new RIP and RSP. Simply setting RSP to system() won’t work – if RDI isn’t clear, system() on a 64-bit system will attempt to read the first argument out of RDI.

At this point, I looked to an existing writeup for guidance. Credit to Inndy@Github for this idea: https://github.com/Inndy/ctf-writeup/blob/master/2016-seccon/jmper/jmper.py.

From here, we can use a simple static pop rdi; ret ROP gadget to set RDI, as well as prepare the stack for a return to system(). Therefore, our order of operations is as follows, abusing the arbitrary write primitive above:

  • Leak a function from the GOT to locate system()
  • Leak RSP from jmpbuf
  • Write jmpbuf->RSP[0] = a pointer to /bin/sh (an unmodified student[1].name works nicely, see above – we’ll have the address of this anyway as we set up the read-write-anywhere primitive).
  • Write jmpbuf->RSP[1] = system()
  • Write jmpbuf->RIP = POP RDI, RET rop gadget

We then trigger longjmp by adding 29 more students. When longjmp gets triggered, RIP and RSP are set according to the values in jmpbuf, as follows:

  • RIP is POP RDI; RET
  • RDI is now a pointer to /bin/sh
  • RIP is RET
  • RIP is system(), and we get shell:

jmper_shell

You can download the Python script for the full exploit here.

Tools – Binary Ninja

During this time, I did the reverse engineering for jmper exclusively in Binary Ninja. This isn’t a tool I use often, and “feels different” for someone used to working in IDA. To me, it was clear that this was designed with a fresh pair of eyes, as opposed to IDA being layer upon layer of useful functionality (the “evolved” feel).

Two things of note, for reference:

  • The option to display opcodes and addresses is hidden in the bottom right, in the “Options” menu next to “ELF” and “Linear”:
    binja_showoptions
  • There appears to be no function to show segment permissions in the tool itself, I had to rely on objdump –headers to see which sections were writeable in the executable.

Despite it’s relative youth, this appears to be a solid tool. I look forward to experimenting more with it’s capabilities.

As always, I’d like to thank the SECCON team for putting together a fantastic and challenging CTF last year. I was (fortunately!) able to save a great many challenges from this CTF for future reference, and look forward to solving them at my own pace, if you’d like to play along, come find me and I’d be happy to share what I have with you.

I’ll see you all in the Insomni’hack teaser CTF in a week’s time.

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