Ruxcon 2017 HHV Badge Flag – Part 2 – The “Hard” Way

In this part we’ll go through how to retrieve the flag directly from the binary. This should be easier than it is but there are some eccentricities to the NodeMCU Lua compiler which break most of the tools out there, after spending some time trying various decompilers and attempting to get ChunkSpy to behave with the NodeMCU bytecode (if I can be bothered I might write up a post on said eccentricities at some point, but don’t hold your breath), I ended up doing the decompilation manually. Took a while but wasn’t particularly “hard”.

The full annotated listing is in this file: RuxBadge 2017 Listing.

Lua is a bit of an odd bird, but the only thing you really need to know for the purposes of this discussion is that pretty much everything in Lua is a table.

If you want to dig down into the nitty gritty I recommend this document A No Frills Introduction to Lua 5.1 VM Instructions that’s where most of the info I used in this process came from.

For the sake of expedience I’m not going to go through the whole listing, hopefully what’s there is fairly self explanatory, though I will explain a few bits and pieces along the way.

The chunk we’re interested in here is function[0] which starts at offset 0x70 in the binary file.

The basic structure of a Lua binary chunk is;
– Function header
– Function code table
– Function constants table
– Function functions prototypes table (for sub-functions)
– Function source line info table (optional debug info)
– Function local variables table (optional debug info)
– Function upvalues table (optional debug info)

So the flag will obviously be some kind of constant, so your first port of call is the constants table (I’m jumping to the function[0] constants table for expedience, but it’s pretty easy to figure out which of the three is the right one to be looking at);

function[0] constants:
011C 13 00 00 00 - Table size (19)

0120 06 - Constant Type (6 = NodeMCU String)
0121 07 00 00 00 - Length of Constant (7)
0125 63 72 79 70 74 6F 00 - "crypto\0"

012C 06 - Constant Type (6 = NodeMCU String)
012D 06 00 00 00 - Length of Constant (6)
0131 74 6F 48 65 78 00 - "toHex\0"
019F 06 - Constant Type (6 = NodeMCU String)
01A0 27 00 00 00 - Length of Constant (39)
01A4 3E 3A 35 3E 23 60 11 6F
01AC 6D 14 66 1F 68 63 65 1D
01B4 61 12 66 1A 6E 14 12 1D
01BC 1E 63 62 6D 1D 63 16 18
01C4 1C 6F 6C 69 6F 2B 00 - ">:5>#`\17om\20f\31hce\29a\18f\26n\20\18\29\30cbm\29c\22\24\28olio+\0"

So the table has 19 entries, the first couple look to be some kind of function calls, but what’s this weird looking string down here which just happens to be 39 chars (well 38+NULL terminator)? Could it be our flag? Clearly it’s been mangled somehow so we’ll need to figure that out, to the code table (offset 0x80 in the file)!

00CC 41 00 03 00 - loadk (>:5>#`\17om\20f\31hce\29a\18f\26n\20\18\29\30cbm\29c\22\24\28olio+)
00D0 85 00 00 00 - getglobal (crypto)
00D4 86 40 43 01 - gettable (encrypt)
00D8 C1 80 03 00 - loadk (AES-CBC)
00DC 00 01 00 00 - move
00E0 45 01 00 00 - getglobal (crypto)
00E4 46 C1 C3 02 - gettable (mask)
00E8 80 01 80 00 - move
00EC C1 01 04 00 - loadk (XVTY)
00F0 5C 01 80 01 - call (crypto.mask(..."XVTY"))
00F4 9C 80 00 00 - call (crypto.encrypt(AES-CBC"...))

This is not the easiest to follow example of how function calls work in Lua because there are some register swaps but it’s not *too* bad.

The function call mechanism is vaguely similar to how the stack works in an x86 processor, so that provides a useful analog to work with, you can consider the above code as follows (not 100% accurate but close enough for our purposes);
– Load the “flag” constant onto stack.
– Load “crypto” global (a reference to the NodeMCU crypto module) onto stack.
– Load “encrypt” table (actually a function, but remember pretty much everything in Lua is a table) onto stack.
– Load the constant “AES-CBC” onto the stack.
– Juggle some registers (moving the “flag” constant down).
– Load “crypto” global onto stack.
– Load “mask” global onto stack.
– Juggle some registers (moving the “flag” constant down).
– Load the constant “XVTY” onto stack.
– Call “crypto.mask(<flag constant>, “XVTY”)”
– Call “crypto.encrypt(“AES-CBC”, <key>, <result from above>)”

So it’s taking the “flag” constant, and the value XVTY and feeding it to the crypto.mask function, time to go figure out what that does, to the docs! NodeMCU crypto module docs

From the documentation we find that this function merely applies an XOR mask to the provided string, so that must be how it’s getting the “actual” flag to encrypt in the next call, since XOR is trivially reversible all we need to do is apply the mask back to the string to get the answer, let’s try that;

3E 3A 35 3E
58 56 54 59 ^
66 6C 61 67

Converting back to ASCII we get;

WIN! Now we just need to apply the mask to the rest of the string;

3E 3A 35 3E 23 60 11 6F 6D 14 66 1F 68 63 65 1D 61 12 66 1A 6E 14 12 1D 1E 63 62 6D 1D 63 16 18 1C 6F 6C 69 6F 2B
58 56 54 59 58 56 54 59 58 56 54 59 58 56 54 59 58 56 54 59 58 56 54 59 58 56 54 59 58 56 54 59 58 56 54 59 58 56 54 59 ^
66 6C 61 67 7B 36 45 36 35 42 32 46 30 35 31 44 39 44 32 43 36 42 46 44 46 35 36 34 45 35 42 41 44 39 38 30 37 7D

Converting to ASCII we get;

Ta Da!

A random sidenote here, this code would likely flow a bit more logically if I’d not done it as a compound call i.e.
crypto.encrypt(“AES-CBC”, <key>, crypto.mask(<flag constant>, “XVTY”))

Morgan / 2017-11-09 / Uncategorized / 0 Comments

Ruxcon 2017 HHV Badge Flag – Part 1 – The “Easy” Way

As promised, here’s a walkthrough for retrieving the Badge Flag from the Ruxcon 2017 HHV Badge.

The easy way requires that you have the badge hardware up and running (though you could just load the firmware onto some random ESP8266 module for the same effect).

If we connect to the UART port on the badge we see the following at startup;

Boot messages

In this data we see;
flag: cbd3f82962b3b38679fba0250f243c4c7dc5b8aa5ff403383f43de6e9dd2e23a32de120d62776077e2196c36ae0a330d

SWEEET! that was easy!

Err, no… Typically for a CTF flag it’s something like a GUID or it’s something like flag{<GUID>} or just flag{<16 random hex bytes>}, which doesn’t really gel with the above, furthermore, if you boot a different badge you’ll see a different value here, so apparently we need to apply some intelligence.

If we have a look closer at the data we’ll see that there are 96 characters there, since it’s evidently hex, that corresponds to 48 bytes. Looking at the values, there are bytes there above 7F so it can’t be a direct ASCII encoding or any ASCII-based encoding.

Considering that flag{<GUID>} is 42 characters and flag{<16 random bytes>} is 38 characters, and our ciphertext is 48 bytes that indicates that it’s likely using some flavour of block-wise encryption (in this case 16 bytes or 128 bits) because if it was using a stream type encryption or most other (non ASCII based) encoding schemes the output would be the same size as the input.

In case you didn’t notice from the startup messages above, the firmware on the badge is based on NodeMCU (and the crypto module is included). NodeMCU is basically an embedded Lua engine for ESP8266, the documentation can be found at;

Looking at the documentation for the crypto module we find that the NodeMCU crypto module supports AES-CBC-128 and AES-ECB-128 algorithms for encrypt/decrypt, both of which are blockwise and both of which are 128 bit in the NodeMCU implementation.

So we have a couple of candidate algorithms, but we still need a key.

Since they’re 128 bit algorithms we’re looking for a 16 byte string. As I told everyone who asked over the course of the conference, the key is out in the open. So the question is where… Let’s go back to that screen grab from earlier;

Boot messages

Do we see any 16 character, or otherwise 16 byte strings here? Moreover, they need to be a *UNIQUE* 16 character/byte string, because the “flag” field is different on every badge… That rules out the commit ID because that’s the same for every badge (assuming you’re using the NodeMCU build that ships with the firmware) and it’s too long in any case. Let’s see, can’t be the SSID, that’s only 15 characters, wait what’s this?

Badge Boot Messages Anotated

It’s a 16 character string… And it’s being used as a crypto key (FWIW clue on the CTF listing for this one was “Reusing crypto keys is bad mmm’kay” or something like that), so that might just be it…

Conveniently enough we can use the badge to perform the decryption. First things first though, we need to convert our “flag” to a string for processing by crypto.decrypt(), a quick google will get you the following function;

function fromhex(str)
  return (str:gsub('..', function (cc)
    return string.char(tonumber(cc, 16))

Let’s try AES-ECB first because otherwise we need to figure out what was used as an IV for AES-CBC;

Well that’s interesting, looks like we’re on the right track, but we’re not quite there yet. We can still get some useful info here though, we know the flag begins with, flag{6E65B2F051D, so it’s definitely in the form “flag{<something>}” but we can go even further than that. GUIDs are of the form XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX, we have the first 11 chars here, and there’s no hyphen so it must be in the form flag{<16 random hex bytes>} which tells us that the length of the whole flag is 38 bytes long. This will become important later.

So we get a partial decryption with AES-ECB, this suggests that the code is using AES-CBC here, which means we need an IV.

The IV for any algo using one is the same as the block size (in this case 16 bytes), and in order to enable them to decrypt the data one needs to communicate the IV to the other party. Typically this is done by either prepending or appending the value to the ciphertext, so in this case we’d be looking at two blocks being cipher text and one being IV…

Hang on, but know our flag’s 38 bytes, how the hell do we fit that into 32 bytes…

From what we’ve seen previously, there’s clearly no clever encoding going on here, 38 bytes doesn’t fit in the 2 blocks we have “available”. Either we’re not being told the IV, or the IV is all zeros. Now, not telling you the IV would be a bit of a dick move, because without the IV you can’t decrypt the whole flag, so one can only assume that if it’s not an impossible challenge, the IV is all zeros.

This is easy enough to test, referring back to the doco, it specifies that if an IV is not provided it will use all zeros so, let’s try that;

Ta Da! We appear to have a flag.

It’ll take a while longer for me to do the write up of the “hard” way, because it involves a lot of bytecode and some understanding of the guts of Lua but we’ll get there eventually.

Morgan / 2017-10-28 / Uncategorized / 0 Comments

Ruxcon 2017 Hardware Hacking Village Wrap

Only eight hours sleep across the weekend (gotta love insomnia…) but we’re done for another year.

I was pretty happy with the level of engagement we saw at the Hardware Hacking Village this year, catering to a group like that is always a bit tough.

You can find my slide deck, the badge and simple solder build docs and badge firmware at my Ruxcon 2017 HHV page.

We handed out 111 of the “Simple Solder” kits across the course of the weekend, so we were pretty much spot on with the 120 that we ordered for (Gotta say, really wasn’t expecting to go through that many of those kits, last year IIRC we only ran out of the 50 we’d bought in by about 11 on the Sunday.)

The badge was the real surprise, last year we only went through about 10 of the kits on Saturday and we ended up handing them out to anybody after we ran out of Simple Solder kits on Sunday. This year we blew through 30 badge kits in the first 3 hours the village was open, going to have to figure out how to get 50+ into the budget for next year.

A note for those people who spoke to me and asked if the designs were going to be put up online. I have good news and bad news, the bad news is; the gerbers will not be being put up online. The art on the badge this year was commissioned on the understanding that it would be used for a limited run, as such we can’t publish them. However, if you’re quick there is some good news; I do have several spare boards (I actually had them with me at the village but my brain was too fried on Sunday to think of offering them to you.) because at the last minute I panelised them two up which meant we could get 40 for what it would’ve cost us for 20. I’m happy to send one out to anyone in AU gratis, if you’re international and you really want one I can send one out but it may have to be at your cost. Hit me up via email ( if you’re after one.

The only real downer from the weekend was that two of the Bus Pirates that Ruxcon had generously provided for Dr Noise’s workshop walked out with delegates.

Thanks to everyone who attended, without you the conference wouldn’t happen. And a special thanks to Chris Spencer without whose insanely tireless work we wouldn’t have a con 😉

Over the coming weeks I’ll put up some posts around the badge flag and maybe some bits and pieces about the IoT CTF stuff, stay tuned.

Morgan / 2017-10-23 / Uncategorized / 0 Comments

Ruxcon 2016 Hardware Hacking Village

Thanks to all who visited us at the Ruxcon 2016 HHV, hopefully you got some value out of my presentations and such (I’m sure you got value out of the other presenters at least).

I’ve uploaded new Gerbers/Drill file for the SimpleSolder kit to my Ruxcon 2016 HHV page, these have the assorted cock ups from the original design corrected, just in case anybody wants to go make their own.

I’ve also included a DigiKey basket link, though for one-off quantities you’re probably better off going elsewhere if you’re AU based.

The RuxBadge build instructions, firmware and firmware source are also up there, if you want to write your own firmware (or modify mine) you’ll need to get a hold of the appropriate STM32 Standard Peripheral Libraries and dump them in an appropriate place (if you attempt to make it before you do that it’ll bitch at you) but other than that it should be pretty straight forward, I think there’s a README in there which has some details about what’s what and build targets and such.

dnz is going to write a tutorials on how to load firmware onto the badge using the UART bootloader, he’s also got a tutorial from last year covering how to do the same with BusPirate (though you’ll need to figure out the connections yourself) and perhaps how to find the flag in the badge firmware so keep an eye out on his site

When I get around to grabbing them off my burner lappy I’ll also throw the slide decks from my presentations up there.

Morgan / 2016-10-28 / Uncategorized / 0 Comments