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

Creating the DropBot9k (AKA; ESP8266 throwies) Part 3

Part 3 – The tools which Espressif hath provided

So we’re still chasing power savings at this point, the next logical step is to reduce the TX power of the ESP8266 because we don’t need much range in this application, unfortunately NodeMCU does not expose the TXPower API…

Looks like we need to write a patch against NodeMCU… Or not…

Something of a diversion;

Around about this time I decided I needed the rtc API for the software which necessitated a new build, off to the NodeMCU Build service we go; build a new image, flash to ESP8266, ESP8266 crashes…

Turns out some time between when I initially started playing with NodeMCU and now, there’d been several SDK updates, and with new versions of the ESP8266 SDK it is frequently necessary to flash a new “init data block” to the ESP, so I dug up the appropriate “init data block” (in the latest SDK package) and attempted to flash it using and also NodeMCU Flasher, but in no case was I able to get a working ESP at the end.

Further research lead me to the Espressif “Flash Download Tool v3.3.6” which can be downloaded from Espressif’s Other Tools page, with that and the latest SDK package I was able to get the updated init data block installed (I also reinstalled the “AT” firmware, probably wasn’t necessary to flash that as well, but I was being paranoid).

Espressif Flash Download Tool

Espressif Flash Download Tool

Then flashed the new NodeMCU image using the normal process.

End diversion.

The upshot of having to go through this process was the discovery of the RFConfig tab in the Flash Download Tool.

Flash Download Tool RFConfig tab

Flash Download Tool RFConfig tab

The “LowPowerEn” checkbox here piqued my interest, turns out, it does pretty much what it says on the box, it hard-codes a limitation on the TX Power. Checked the “LowPowerEn” checkbox, dialed it down to 0dBm (1mW), generated a new init data block, flashed it to the ESP, and re-tested.

Now, on a 5 min wake/1 min sleep cycle (I think, might have been 3 min wake/2 min sleep), I was seeing in excess of 48 hours of battery life, which was “good enough”. Out of interest I ran it up with NO sleep, and it was still good for 8+ hours, so a pretty good outcome all in all.

Turns out, the way we built the scenario for the competition meant that the ESP only needed to be (and indeed COULD ONLY be) deployed for about 6 hours, so I tweaked things to switch it to a 10min wake/10sec sleep cycle, just to give it the occasional kick in the head to make sure all ran smoothly, I also dropped two separate units in the alleyway for extra redundancy.

I’ll write another quick post in this series around “packaging” and that will cover the hardware, I’ll write up another post or maybe two about the software for it as well.

But for now, that’s your lot.

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

Creating the DropBot9k (AKA; ESP8266 throwies) Part 2

Part 2 – ESP8266’s do HORRIBLE things to batteries

So initially I went with the naive approach, I stuck a pair of CR2032’s in parallel and strapped them to the ESP8266, I was rather disappointed to discover that that only got me about 20 mins of life, repeated the test with a pair of AAA’s for interests sake, I think I got about an hour out of them, time to do some ACTUAL research…

In doing some fishing around online I found some YouTube video around powering ESP8266’s from batteries or somesuch, which alerted me to the horrific power draw behaviours of the ESP8266, turns out a bare module pulls bugger all current, EXCEPT every 100ms or so where when it’s in AP mode, where it suddenly draws 400+mA to beacon, which the CR2032’s (being that their nominal rated current draw is 15mA) were VERY unhappy with, I did a quick lash up on my electronics bench to validate that that was, in fact, what was happening here, the scope confirmed the findings.

Fortunately there exists a simple solution for this, “strap a big-ass capacitor across the power rails”, 1000uF is a good choice, it doesn’t completely eliminate the spikes, but it reduces them to manageable levels and doesn’t add excessive bulk.

So I went and strapped a 1000uF cap across the module and repeated the test with a fresh pair of AAA’s, sadly that was still only good for 6 hours or so (even after I dropped the beacon interval back to 2 sec).

Back down the rabbit hole then.

The ESP8266 supports various “sleep” modes, reading the doco, the only thing that would really work for me is “deep sleep”, next problem, the way deep sleep works is;

  • GPIO16 is connected to RESET.
  • Sets a timer to fire GPIO16.
  • Powers down everything except the timer.
  • Timer expires, GPIO16 fires, chip is reset.

Problem is that the ESP-01 doesn’t have GPIO16 broken out… Time for some microsurgery!

ESP-01 Modified for Deep Sleep

ESP-01 Modified for Deep Sleep

Note the jumper wire between the Reset pin and pin 8 on the ESP8266, also note that the power LED has been removed, that alone pulls ~10mA.

Bada bing, bada boom, deep sleep, did some testing managed to get 60 hours out of a 5min sleep 1min wake cycle, this was less than optimal but at least it showed that there was a way forward.

More in part 3 whence we dig into the tools Espressif hath provided.

Morgan / 2016-11-04 / Uncategorized / 0 Comments

Creating the DropBot9k (AKA; ESP8266 throwies) Part 1

Part 1 – The Inspiration

For Ruxcon 12 this year it was decided to expand the Black Bag competition into two phases, the first being on the Saturday which was the “standard” Black Bag fare, get into a hotel room, acquire intel, don’t set off alarms and such, Sunday however was a bit different.

We decided to send the top three teams on something of a “scavenger hunt”, basically we’d send them to a few locations across the Melbourne CBD to find clues which would eventually lead them back to the conference venue where they would find a (blatantly fake) “bomb” (I’ll write up another post on the construction of that some time later), which they’d have to “disarm” for extra points.

The first stop for this “scavenger hunt” was to be a Wireless hotspot stashed in one of Melbourne’s many alleyways, to which they would connect for instructions for the next step.

Because things were very much “up in the air” as far as how we were actually going to achieve this one of the design goals was that the hotspot should be capable of being deployed on the Friday night and collected on the Sunday, necessitating at least 48 hours of battery life.

WRT703N with Internal LiPo battery

WRT703N with Internal LiPo battery

I did some testing of a Linksys WRT703N platform I’d modified with an internal battery pack, unfortunately the battery life was rather woeful, next attempt was to just strap the WRT to a USB Power Bank and use that, turns out the 703N is actually really power hungry, the ~4000mAh power bank I tested with gave only a bit over 2 hours of life, even with TX Power down at 0dBm (1mW), and obviously the equation around the amount of battery capacity required just wasn’t going to work out.

Clearly it was time to go back to the drawing board, at some point on Slack somebody had suggested we might be able to do it with an ESP8266, I’d initially discarded the suggestion because I didn’t want to have to deal with building webservers and suchlike on a platform like that. But needs must, so I dug in, more on that in part 2.

Morgan / 2016-11-03 / 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