Writeups – products-manager, overfloat (Facebook CTF)

This weekend, I participated in the Facebook CTF event. The quality of challenges in this CTF was decent, but the event was marred by significant connectivity problems, rendering it unplayable for a significant portion of time for me.

I solved two challenges during this event, as always, the writeups are below.

Products Manager

This challenge was presented as a web challenge, with corresponding source code, which you can download here.

We can identify the core of the challenge by reviewing db.php:

Inspection of the source code shows that there is surprisingly limited attack surface, and that all SQL queries are sensibly parameterised. A poor choice of setup in the CTF gave the solution away: I noticed that at one point, two “facebook” entries were present in the “top 5” list.

This indicated that it was possible to both add another entry called “facebook” (or close to it), and that the web application was a shared, stateful application – an interesting choice for the expected player turnout.

A bit of fiddling later, and I was able to add “facebook” with an encoded space (“+”) at the end:

Following this, I could extract the flag by correctly supplying the secret that I knew.

Logic would have it that this was an edge case in MySQL, regarding adding items with blank spaces after them in queries, or matching them – a useful trick for later, but 100 points for now.

Overfloat

This challenge was presented as a pwnable challenge. The pwn binary can be downloaded here, along with the corresponding libc.

Upon initial analysis, this application performed some floating point maths:

I did some local debugging with gdb and comparing inputs and outputs, but got nowhere until I used retdec to decompile the binary. You can download the decompiled source here.

This made the program logic much clearer, and the structure was immediately revealed as a “rop builder” challenge: the program would effectively allow the user to enter rop gadgets at will as floats, and then trigger a stack-based overflow. To bypass the first hurdle, I created a simple C program which did the appropriate float conversion. You can download this here.

We can quickly confirm that we have the appropriate stack execution:

From here, traditional wisdom (and the fact that we have libc) indicates that we should leak an offset within libc, reset execution, then re-exploit the overflow to call a magic gadget (or system-equivalent point) to get a shell.

The leak was trivial to accomplish through loading RDI then calling puts at 0x400690. The program execution is reset to 0x400749, and then the exploit is re-fired against a known target. Of note, note that RBP is fucked at this point thanks to the leave instruction, and the remote target behaved differently to my local machine, resulting in a frustrating period of yes/no debugging via printf rop chain links – but flags are flags.

You can download the complete exploit here.

Thanks to the organisers and challenge creators of this CTF – this was a good exercise for someone who hasn’t CTF’ed for quite some time, and a steady reminder that no matter the strengths of one’s motivations, only results matter. See you in the next CTF.

Posted in Bards, Computers, Jesting | Leave a comment

Writeup – Overcobol (INS’Hack)

Over the past weekend, I participated in the INS’Hack CTF. This was a well executed CTF with a fairly mixed-bag of challenges. A sizeable serving of salt coming from a blind Python breakout which took a bit of brute force, but as I neared completion, was declared not working (nevertheless, this was a lot of fun, and I broadened my creative horizons a bit).

One noteworthy and excellent aspect of this CTF was a COBOL challenge: truth told, this was the first time I had ever seen COBOL. Without further ado, the writeup follows:

Overcobol

This challenge was presented as an low-value (IIRC) exploitation challenge, with the source code to a COBOL program provided. You can download this here. Honestly, I’m amazed Github has syntax highlighting for this.

Reviewing the challenge reveals what appears to be a straightforward buffer overflow:

02 TMPNAME PIC X(10).
02 TMPSCORE PIC 99.
02 SUBPRGARG PIC X(20).
02 SUBPRGNAME PIC X(20).

This seems triggered by the SEND-CLOUD… function?

SEND-CLOUD.
IF SUBPRGNAME = SPACE
MOVE "send" TO SUBPRGNAME
MOVE "matchs" TO SUBPRGARG
END-IF
DISPLAY SUBPRGNAME " " SUBPRGARG
CALL SUBPRGNAME USING SUBPRGARG.
END-SEND-CLOUD.

A little bit of brute forcing yields the argument lengths required to load SUBPRGARG and SUBPRGNAME – but invoking “CALL ls USING /” yields nothing meaningful. A little while of Google later, and we stumble across the SYSTEM COBOL module, and a working exploit appears:

Thankyou to the organisers of INS’Hack for putting this challenge together, and coming up with some really creative challenges.

I realize I haven’t written anything for the past few months, and truth told, haven’t been pushing myself to work as hard on side projects (at least to completion). I acknowledge this weakness and strive to correct it – I look forward to another year of pushing my boundaries.

Posted in Bards, Computers, Jesting | Leave a comment

On AppSec Day…

Last week, I had the pleasure of attending OWASP AppSec day in Melbourne. This was a productive day. On the flight to Melbourne, I stumbled upon a hypothesis as to why my initial attempt at differential electromagnetic analysis of some AES traces didn’t work (I figured it was due to the non-instantaneous nature of magnetic fields), which I contradicted later through further experimentation and analysis of existing capture data – all hail the advent of cheap, portable storage.

Furthermore, I was able to refine a script for trace acquisition for Rigol scopes via Ethernet, using a modified github/pklaus/ds1054z module as the communications back-end – this is now mostly stable, and semi-consistent with other parts of the fuckshitfuck toolkit. Here it is in action against 100(!!) power traces of AES on an ATMega328p (I think we ended up missing one byte!):

There’s also some progress towards a template-based attack, though I’m not sure how realistically applicable this is, given variances such as horizontal jitter (still, based on the below, cutting out 1000 data points out of 8000 is still a solid improvement):

I must admit, there is a certain joie de vivre in this work that is, broadly speaking, absent elsewhere – compared to this, I really don’t care whose XSS is where and which crayon we need for the risk matrix.

On a somewhat more serious note, a few things were telling from this day, which are worth noting down:

The Top Ten are Dead, Long Live the Top Ten

Every single talk spoke about moving security to the left, but most of the industry is still attempting to fix the OWASP Top Ten. Realistically, the OWASP Top Ten has become the OWASP Top One or Two with the introduction of modern frameworks and sensible hosting, which voids entire categories of vulnerabilities. When’s the last time you saw someone construct a SQL query with string concatenation?

When’s the last time you saw someone (who’s day job is developer – our code is duct-tape and we know it) build a SQL query manually, as opposed to fetching data through a pre-built framework?

Yet let’s take a look at the OWASP wiki for how to protect against SQL Injection vulnerabilities:

Who realistically uses this stuff in 2018? No really, please do leave a comment if these principles are still applicable to production code where you are: I need to know.

On the other hand, where is the advice on how to prevent the logic-based bugs and debug content which are generally the easiest way into a web application? More importantly, is it even feasible to package the concept of “don’t fuck up logic” into a set of codifiable rules, which people will inevitably ask for? (My initial inclination on this is “no”).

What use is all this when people still sticky tape their passwords on their POS systems to the top of their monitors, for anyone walking past to read?

Most Dangerous Adversary 2018: Vendors

One of the speakers mentioned that the most dangerous adversary of the year was the vendor. This holds particularly true in application security, where the space is poorly defined enough that it is simple to deceive unsuspecting marks – failed comedy shows like “Next-Generation WAF” and “Self-Protecting Software” have taken root, like some kind of malignant tumor. Thinking of this contemptible filth, my mind cannot help but drift to the image of a serpent in the afternoon sun, poised to strike.

If these salespeople played EVE Online, surely they would be highsec miners.

What happened to genuinely building a good product, and simply letting the product speak for itself (and making datasheets publically available as technical reference material)? Imagine how much faster the market would mature, if we all followed the Atlassian model!

Integration and You: The Untold Story

I also was able to spend some time speaking with fellow… “appsec practitioners”. I got a sense that every product on the market had miniscule signal-to-noise ratios, and the best way to use a “code security” product was to simply drop all non-critical issues identified (i.e. switch a product on, and only require human interaction on critical issues). This matches with my experience speaking to developers, who overwhelmingly reject security review tools on the basis of false positives.

This is a tricky one: as security folks, we generally don’t “eat our own dog food”, so to speak: without running large enterprise codebases (which we don’t write) through enterprise appsec tools, we don’t know where the realistic pain points are. Getting security people to write copious amounts of enterprise code isn’t necessarily the solution either – broadly speaking, it’s not necessary.

In Conclusion

While there’s no clear fixes to a lot of the stuff, I think a lot of the above is reasonably applicable to any enterprise application security programme, particularly in the form of industry-accepted best practice as opposed to ISC^2-style standards.

See you all in BSides Delhi CTF.

Posted in Bards, Jesting | Leave a comment

Power Leakage Modelling of DES

This weekend, as part of my efforts to advance my learning of power analysis, I attempted to create my own power leakage model of DES and recover a key without referring to previous work. My targets were the ATMega328p board, used for previous experiments, as well as a PIC24F target board. Both ran with DES code from avr-crypto-lib.

I must admit that I cheated somewhat, by using triggers at the start of DES round 1. Unfortunately, I haven’t yet been able to compensate for some high-amplitude, low-frequency noise I’m seeing in one target (I’ve eliminated the power supply as a cause, I’ve yet to try with a magnetic probe) – without this, I am almost certain trace alignment would be meaningless.

While conceptually trivial, implementing this was a good exercise in selecting and writing my own leakage model.

Recovering Key Fragments

We begin our analysis by looking at avr-crypto-lib’s implementation of the DES algorithm. In diagram form, it looks like this (only the bits we need, half the round function is omitted):

The key is split into 8 6-bit key fragments for each round, and there are 16 xor-sbox-mix operations (8 against each half of the plaintext) for each round of DES (i.e. 16 sub-rounds per round). This comes up clearly in a power trace (from memory, 64MS/s, 16100 samples), which shows the first 8 rounds, which is more than enough for this attack:

We perform a correlation attack, by choosing the 6 bits of key material XOR’ed with the permuted plaintext, and then correlating against the expected Hamming weight of sbox[out] & 0x0F OR sbox[out] >> 4. If our key guess is correct, we should get an extremely strong correlation.

In order to do this, we need to implement:

  • the first part of the DES algorithm up to the first round, allowing us to permute the plaintext via the initial permute (ip_permtab) and expand permute (e_permtab)
  • the “guess” part of the DES algorithm: for each guessed key fragment, we must be able to compute the SBOX output (keeping in mind the 8 separate SBoxes, depending on the key fragment used.

A bit of quick testing shows us the leak actually works, showing a strong correlation against a single key fragment:

We then complete the rest of the attack, including the multiple SBox mechanic, leaving us with the following overview:

Strangely, only 4 of the 8 key guesses were recovered. I slowly walked through my code, until I realized that I had only guessed key bits up to 48, instead of up to 64 (2 ^ 6) as it should have been. one quick fix later:

Key Recombination and Recovery

To recover the key fragments into a useful key, we need to perform the following steps, in order:

  • Invert the PC2 permutation (which takes 48 bits of input, and generates 56 bits of output, including 8 bits which we know are useful, but don’t know the value of)
  • Invert the shiftkeys operation (which takes 56 bits of input and gives 56 bits of output)
  • Invert the PC1 permutation (which takes 56 bits of input, and generates 64 bits of output, including 8 bits which we know are ignored)

Unfortunately, the PC2 permutation applied to the key only keeps 48 / 56 bits of usable key material – we can use a brute force attack to recover the final 8 bits of useful key material.

To allow this, I used a flexible inverse permutation, which allowed marking bits as “don’t know but care (2)” and “don’t know, don’t care (3)”:

def inv_permute(table,blk,default_char=2):
  pt = [default_char] * (max(table) + 1)
  for index in range(0,len(blk)):
    if pt[table[index]] == 2 or pt[table[index]] == 3:
      pt[table[index]] = int(blk[index])
    else:
      if pt[table[index]] != int(blk[index]):
        print "fail - mismatch in inv_permute"
        sys.exit(0)
  return pt

This ended up providing a template like the following (based off the recovered fragments above):

[0, 0, 1, 0, 1, 2, 2, 3, 0, 1, 2, 2, 1, 1, 1, 3, 0, 0, 0, 1, 0, 1,
 0, 3, 0, 0, 0, 1, 0, 1, 1, 3, 0, 0, 1, 0, 1, 0, 0, 3, 1, 0, 2, 0,
 1, 2, 1, 3, 1, 2, 0, 2, 0, 0, 1, 3, 1, 0, 1, 0, 0, 1, 1, 3]

We can then brute force a single byte of key material, substituting it into the bits marked ‘2’, and replacing the ‘3”s with 0’s. Testing this against a single known plaintext and ciphertext is enough to recover an equivalent key, which works just as well as the original key:

Original:   2b7e151628aed2a6
Equivalent: 2a7e141628aed2a6

Alternatively, using the second and third rounds of DES to recover this material is also feasible, but tremendously time-consuming in terms of code.

All the code is in github.com/CreateRemoteThread/fuckshitfuck – most of the DES-specific code is in dessupport.py.

Posted in Bards, Computers, Jesting | Leave a comment

Magnetic Correlation Analysis of AES

Over the past week, I have attempted to replicate my power analysis work on AES using a magnetic field / H-Field probe. Unfortunately, there is little literature on the specifics of how to do this, but I was able to do this on the ATmega target used for the original correlation analysis to achieve an extremely strong result, using only a few captures (1000):

The key to this was to maximize the signal to noise ratio of the incoming capture via probe positioning. To do this, I manually sampled the magnetic field emission while the device was on and off (not doing anything active – just powered on). Here is a sample of the magnetic field measured through an H-field probe, while the device is powered off (the time scale is ms I think, but it doesn’t matter, we only look at the average):

Contrast this to a sample of the magnetic field, while the device is on and awaiting input:

In practical terms, this was possible with the H-field probe’s “tip” approximately 25% from the top of the ATmega328p target, as follows:

I also massively oversampled, based on commentary from the NewAE forum. In this thread, there is mention of needing to phase shift the ADC of the ChipWhisperer when doing this attack. Given that I wasn’t providing the clock signal directly, I concluded that phase shifting was not applicable, and therefore, I set the sample rate to 128MS for a 16Mhz target, hoping to get enough samples it didn’t matter.

Using this setup, I was able to clearly capture the rounds of AES such that they were visually distinguishable:

(This was a pleasant surprise, given the comment around the waveform being less nice than a shunt resistor here, I was emotionally prepared to go the distance with maths alone).

Correlating these by the hamming weight of the first round post-sbox value, I was able to recover some bytes of the key, corresponding to the peaks demonstrated above. The entire key is not recovered but the success is clear: the rest is just better selection of the first round of AES… and maybe a nicer plotting tool to do this.

Perhaps the greatest success is that no new code needed to be written for this attack – everything is still at github/CreateRemoteThread/fuckshitfuck. Hooray!

May your weekend be ruthlessly productive.

Posted in Bards, Computers, Jesting | Leave a comment