Words have not yet been invented to describe the utter awesomeness of HackFu. Run by MWR Infosecurity, it’s two extremely intense days of team-based hacking, puzzling and pwning, tackled by means of skill, luck and sometimes even outright cash bribery (Facebook photo albums here and here). Many thanks to the RAF Air Defence Radar Museum for providing the venue – it’s a great place to visit, go check it out!.

As with last year, I supplied a challenge for the event. I’m going to document it here, because it was a little, errm, “different”, and I learned an awful lot whilst I was screwing it together. HackFu is all about learning stuff, and there’s no point in learning without sharing the knowledge, right?

tl;dr

Booby trapped Aztec temple. Violent kinetic defences. Golden Idols for the taking. Robots with night vision and sonar. Four distinct forms of wireless comms.

Enter the Maze…

All HackFu events are themed, and this year’s theme was The Crystal Maze. My challenge was for the Aztec zone, and had quite a straightforward aim – retrieve the Golden Idol from the altar in the temple and discover its full name. It’s not going to be as easy as walking in there and picking it up – as this journal entry shows, we could be entering a high-threat environment. How to minimise the risk? In “The Phantom Menace,” Rune Haako was faced with a similar situation: “Are you brain-dead? I’m not going in dere with two Jedi. Send a droid.”

Send a droid, you say? Enter TempEx One, the remotely operated temple explorer:

TempEx allows the players to reconnoitre the temple, detect traps, discover clues, and ultimately permits them to formulate a plan to safely enter and retrieve the Golden Idol from the altar. TempEx is equipped with an ultrasonic range finder and a wireless infra-red camera, both mounted on a steerable pan/tilt mount.

TempEx is remotely controlled by means of a two-stick controller, shown here with its lid off:

The left stick drives TempEx; the right one operates the pan/tilt rig. The camera receiver is shown in the background, and its output is pumped through a TV overlay board. This means I can draw a nice heads-up-display over the camera feed that shows command inputs from the sticks, telemetry received from TempEx, and a cool targeting reticle to make the user feel extra-menacing. With the lid on, only the sticks poke out:

And the altar? It’s equipped with:

A light sensor – keep it dark in there, or face the consequences!

A pressure pad – remember what happened to Indy when he tried to swipe the Idol in Raiders of the Lost Ark!

Tripwires – careful where you step!

Active defences – eye protection mandatory!

Finally, we have the gameplay element of the challenge. It’s got to be fun, it’s got to be do-able, it’s got to have scoring in order to rank the teams, and it has to involve some hacking (otherwise the event would just be called “Fu”)

Hopefully…

…I’m keeping your attention. I built and coded all of the hardware above, and I’m going to document it one piece at a time. It’s a journey of discovery in which I struggle to remember which end of a soldering iron to hold and am forced to deploy several “Plan B’s” in pursuit of realising my ideas.

The Altar

The altar is basically an Arduino Mega 2560 mounted inside an appropriately decorated biscuit tub with one of my kids’ toys on top to give the Golden Idol somewhere to sit. It’s a pretty squat assembly, but from TempEx’s point of view seven or eight inches off the ground it looks pretty tall, especially with the idol sat on the top:

The Golden Idol is definitely made of gold, honest:

I’d never touched an Arduino before embarking on this challenge, but when you take a look at the ingredients in an Arduino Boffin Kit things like tripwires and light sensors suddenly don’t seem impossible to implement. Books like Beginning Arduino confirm the suspicion – it’s all possible, and even relatively straightforward.

For the hardware side of the Altar, I wanted four tripwires, some kind of pressure pad, and a light sensor. I also wanted to have some kind of visual indication that the pressure pad was being read, so that people could time some kind of Indy-style switchout, taking the Golden Idol and replacing it with something else. The idea was that players would start with a given points score which would be deducted from when they trip the traps. Tripping the light sensor and pressure pad were considered major sins when compared to tripping the wires – I wanted to guard against people just turning on the lights and swiping the Idol without “playing the game”.

Let’s start with the tripwires. They’re basically switches, and that’s what I used for my first prototype. From the Arduino’s perspective, they were normally-open switches attached to digital pins configured as INPUT_PULLUP – this means that they will read high until they are dragged low, in this case by my switches being closed.

The pressure pad and light sensor were implemented as a force-sensitive resistor and a light-dependant resistor. Both were configured in series with a fixed-value resistor, forming a voltage divider. This means that by attaching the voltage divider’s Vout to an Arduino analogue pin I can determine “how much weight is on the pad” and “how light it is in the room”.

The first prototype for the Altar looked like this, built in the traditional fashion on breadboard with jumper wires:

The light-dependant resistor is highlighted blue; red shows two switches pretending to be tripwires (there were four in the final version), green is the force sensitive resistor and cyan shows an LED that flashes when the FSR is being read. The LED highlighted white was used as a debugging aid to show me when all the traps were tripped. The Arduino sketch for all of this was reasonably straightforward (final version is shown later on).

Great! It’s the Altar done! Check it off the list!

Orrrrr, not. What we have here is strictly a prototype, knocked up over the course of an evening. This isn’t a deployable solution – we’ve got to “make” something, based upon the breadboarded proof of concept.

The tripwires were the easiest bit. On the breadboard above, the switches were normally-open (causing the INPUT_PULLUP pins to read high) until they were closed (causing the pin to read low). To replicate this, I took some clothespegs and drilled holes in the pads and ran wires through them:

The idea is that when the peg closes the two wires touch, making the circuit and pulling the Arduino pin low. To (perhaps unnecessarily) aid conduction, I wrapped the ends in foil, resulting in this:

OK, now we’ve replicated the switches on the breadboard. How to make these into practical tripwires? To keep the pegs “open”, I used strips of plastic cut from a drinks bottle. Next, I tied some fishing line to the strip and anchored the other end to a fixed point. The net result is a working tripwire – if you knock the fishing line, you’ll pull the plastic strip out of the peg, which will make the circuit and cause the Arduino pin to read low, telling it that the wire has been tripped. Boom!

The FSR, LDR and flashing LED were a slightly different proposition – I had to get out the soldering iron and fabricate a circuit on stripboard. I wanted to take a modular approach, so I soldered some stackable pin headers onto the stripboard so that I could run removable wires from it back to the Arduino. More stackable headers were used as “sockets” for the tripwires. The finished stripboard is the rectangular affair that can be seen standing proud of the rim of the Altar in the picture below:

I mounted the Arduino in a case I had lying around; the case was eventually mounted in the decorated biscuit tub that you can see sitting under the Altar in the first picture of it above.

I have got an LCD display attached to the Arduino, from a dirt-cheap “lucky bag” from Maplin. This was originally intended to be part of the challenge, showing several lines of clues for the players. I got caught up in the fun of hooking up the display and I had it all working nicely before I realised the obvious – TempEx’s camera is an active IR one. This means that it has an IR-sensitive camera surrounded by a ring of IR LEDs – basically infra-red torches. This means that, when viewed on the camera, the LCD display is completely obscured by the reflection of the IR LEDs and you can’t read a single thing on it… Cue Plan ‘B’, which involves having the clues on a piece of paper hidden somewhere in the temple. Crude and low tech, but gets the job done!

We’re nearly there with the Altar. It can detect intrusions with all its various sensors – all it needs to be able to do is ward people off. My eldest son was suggesting things we could do when the traps were tripped, and his least lethal suggestion was to shoot them with a Nerf gun. Fortunately, MWR have a Nerf Vulcan in the corporate toybox – all I had to do was hook it up.

I wasn’t keen on destructively modding the Vulcan. Instead, I put a strip of plastic in the battery compartment between one of the spring terminals and the adjacent battery, with long wires snaking out of the compartment from each side of the strip. By turning on the Vulcan’s power and taping the trigger shut it can now be fired by touching the ends of the wires together. Satisfied that it’s working like this, we can put the ends of the wires into a relay that we can control from the Arduino – at this point, we have an Arduino-controlled Nerf gun, which is extremely cool in itself. I used a convenient relay board for this, having the relay energise for two seconds when one of the tripwires was pulled – this was sufficient to unleash a volley of about 6-7 darts.

As interesting as the Altar hopefully is, it doesn’t pose much of a hacking challenge – something else is needed. Time to put the soldering iron away and think about the “gameplay” element of things.

The idea was that the altar would have a “remote management” interface which, when discovered and activated, would allow players to:

See the status of the traps

Decrease the polling interval of the FSR (to make it physically possible to swap the golden idol for a stone one)

Increase the trip threshold of the light sensor (so that you can send someone in with a glowstick so they can see where they’re going).

The altar management interface was implemented as a simple set of web pages on a small PC attached to the Arduino in the altar via USB. Communication was by means of a simple serial protocol over the emulated serial port that appears when you connect the two together (/dev/ttyACM0 in my case).

Here’s where a slight oddity of the Arduino platform threw a spanner in the works. By default, when you open a serial port the DTR line goes low for a short period of time. This “DTR waggle” is seen by the Arduino, which then performs an auto-reset (reboot) and starts running the sketch from scratch. This is somewhat problematic if you’re trying to keep track of someone’s score!

There’s a page on the Arduino site devoted to disabling this feature. I wasn’t keen on physically altering my Mega, nor could I make any of the software solutions work. I found another solution here – by executing “tail -f /dev/ttyACM0” on the PC, the serial connection is kept open and my scripts could talk to the Arduino without resetting it.

So now the traps are set, the remote management interface is deployed, and the Altar can be controlled via a PC. Here is how the challenge was intended to be played:

From the safety of a room outside the temple, read the journal entry and TempEx manual. Cautiously open the door to the darkened temple. This will trip the tripwire controlling the Vulcan, causing the player to get a bunch of Nerf darts in the head. Aside from being for the amusement of the challenge creator, this step is designed to put players on edge and make them more cautious than they need to be. But mostly it was for the amusement of the challenge creator. Send in TempEx and have a look around. Things it will see include the Golden Idol sitting on the Altar at the far end of the room (with a light that’s flashing really fast), the tripwires, a stone Idol, and if you look hard enough, some clues written on the wall (these were the clues that I intended to show on the LCD). The clues list some “control codes” to turn “remote management” on and off. There is also the statement that something is “listening on: xx:xx:xx:xx:xx:x”. The xx:xx.. thing looks a bit like a MAC address, but it’s not – it’s one nybble short in the last byte. It’s actually a phone number, and you can turn remote management on and off by sending the command codes to it via SMS. The codes are received by a GPRS modem (below) attached to the PC, and are parsed by a script run by gsmsmsd.

The script checks the content of the message, and will communicate with the Arduino if an appropriate message is present. A response message is then sent to the sender informing them of the result. I implemented a couple of commands for my own purposes, including retrieving the current trap status and score, and resetting all the trap statuses. If remote management has been turned on, the player receives the following message: “Probing for – 4zt3c : Listening on – 192.168.99.100:80 – Access Token – Sallah : Password – Kobayashii”. Oddly enough, gsmsmsd seemed to duplicate the last character when sending the reply, hence the two i’s when only one is in the script. Hopefully, the word “probing” will make the players think of wifi and set up an access point serving up an SSID of “4zt3c” (hostapd or airbase-ng could be used for this). Once the Altar has connected to your wireless network, we dutifully connect a web browser to http://192.168.99.100, as directed by the SMS. A login screen appears: …but the supplied Access Token and Password don’t work. Whoops. Investigation of the page source shows some client-side validation JavaScript that attempts to prevent the use of several characters including <, > and ‘ Knowing that most of the players will be skilled pentesters, I was hoping that they would see this as a potential indicator of a SQL Injection vulnerability. Sure enough, bypassing the JavaScript and supplying values with single quotes in them causes a MySQL error to be displayed… …but there isn’t a MySQL database, let alone a SQLi hole. The entire site is fake, designed to make people waste their time. Nothing you can enter into the form will log you in, because there’s nothing to log in to. Deception is a completely valid defensive technique! Examination of the HTTP host headers sent by the server shows that there’s one called “nazcaTrail” whose value is “clupea_harengus_russus_0120-bona_fide_0177322”. “Clupea Harengus Russus” roughly translates as “red herring”, and 0120 is 80 in Octal. The message I was trying to send was that the red herring is on port 80, and the “bona fide” site is on port 65234 (decimal representation of the octal 0177322). Finally, we have a site we can log in to at http://192.168.99.100:65234. Sure enough, it shows the state of all the traps and offers a facility to tweak the pressure pad polling interval and light sensor trip threshold. There is also a schematic of the altar showing how it all hangs together. After tweaking the pad’s polling interval, TempEx’s camera will show the Altar’s light flashing much more slowly. A brave adventurer will go in, pick up the stone idol, negotiate the tripwires, and will attempt to swap the stone idol for the golden one on the Altar in between light flashes. Except they can’t see the flashes because the LED is an infra-red one, and can only be seen on TempEx’s camera feed. To solve this problem some teams resorted to banging on the wall, others installed metronome apps on their phones and synced them up to the flashing of the LED. However they approached the LED problem, eventually the adventurer would emerge from the temple clutching the golden idol. Underneath the idol was written its name – the answer to the challenge! But… …the challenge asks for the idol’s full name. Closer examination of the remote management website shows that the idol is running at 13.56MHz, which is an RFID frequency. Scanning the idol with an NFC-capable phone will tell you the idol’s surname.

Job done! Another successful quest for the Man In The Hat!

Here’s the Arduino sketch running the altar. I’m using the Metro library as a pseudo-timer to control the FSR polling interval and the update frequency of the (redundant) LCD display:

// Pseudo-timer library #include <Metro.h> // LCD driver code #include <LiquidCrystal.h> // RW,EN,RS on the LCD int lcdRW = 42; int lcdEN = 45; int lcdRS = 44; // The LEDs on the LCD int lcdLED1 = 43; int lcdLED2 = 40; // The button on the LCD int lcdButton = 35; // initialize the library with the numbers of the interface pins LiquidCrystal lcd(lcdRS, lcdRW, lcdEN, 48, 49, 46, 47); // LDR to ensure darkness in the room int LDR = 0; int ldrLowThreshold = 200; int ldrHighThreshold = 590; int LDRThreshold = ldrLowThreshold; bool ldrIsThresholdLow = true; // FSR to check for presence of Golden Idol int FSR = 1; int FSRThreshold = 600; // Tripwires - normally open, read high when untripped #define numTripWires 4 int tripWireOne = 12; int tripWireTwo = 11; int tripWireThree = 6; int tripWireFour = 7; // Relay board - Nerf gun is attached to this int relay = 8; // Lights up when you trip all the traps int alarmIndicator = lcdLED2; // Lights up when the FSR is being polled int fsrIndicator = 10; // Polling speeds in milliseconds int fsrFastPoll = 100; int fsrSlowPoll = 1000; Metro fsrMetro = Metro(fsrFastPoll); bool fsrFastPolling = true; // Health counter - your "score", deducted from when you trip traps int health = 1400; // Sensor penalties and tripped flags int LDRPenalty = 300; bool LDRTripped = false; int FSRPenalty = 300; bool FSRTripped = false; int tripWirePenalty[numTripWires] = { 200, 200, 200, 200 }; bool tripWireTripped[numTripWires] = { false, false, false, false }; int tripWirePins[numTripWires] = { tripWireOne, tripWireTwo, tripWireThree, tripWireFour }; // Display modes const int dispModeListeningOnText = 0; const int dispModeListeningOnValue = 1; const int dispModeControlCodeOneText = 2; const int dispModeControlCodeOne = 3; const int dispModeControlCodeTwoText = 4; const int dispModeControlCodeTwo = 5; const int dispModeRemote = 6; const int dispModeProbingFor = 7; // How many modes? const int dispModesRemoteOff = 7; const int dispModesRemoteOn = 8; int numModesActive = dispModesRemoteOff; // Set inital display mode int dispMode = dispModeListeningOnText; // Set pseudoTimer for display Metro dispMetro = Metro(2000); // Holds data received on serial port String serialInput = ""; // Is the message complete, terminated by # ? bool serialInputMessageComplete = false; // Is remote management on on the PC? bool remoteManagementActive = false; // Phone number to listen on String listeningOn = "07:xx:xx:xx:xx:x"; void setup() { // Set up serial port for debugging Serial.begin(9600); // reserve 200 bytes for serialInput: serialInput.reserve(200); // Set up pinmodes pinMode( alarmIndicator, OUTPUT ); pinMode( fsrIndicator, OUTPUT ); pinMode( lcdLED1, OUTPUT ); pinMode( lcdLED2, OUTPUT ); pinMode( lcdButton, INPUT ); for( int tripWire = 0; tripWire < numTripWires; tripWire++ ) pinMode( tripWirePins[tripWire], INPUT_PULLUP ); pinMode( LDR, INPUT ); pinMode( FSR, INPUT ); pinMode( relay, OUTPUT ); // Turn off alarmIndicator and fsrIndicator digitalWrite( alarmIndicator, LOW ); digitalWrite( fsrIndicator, LOW ); // Turn off the LEDs on the LCD digitalWrite( lcdLED1, LOW ); digitalWrite( lcdLED2, LOW ); // set up the LCD's number of columns and rows: lcd.begin(16, 2); // Turn off relay digitalWrite( relay, LOW ); } void loop() { checkLCDButton(); health -= checkLDR(); health -= checkFSR(); health -= checkTripwires(); if( health <= 0 ) digitalWrite( alarmIndicator, HIGH ); updateDisplay(); if( serialInputMessageComplete ) processSerialInput( serialInput ); } /////////////////////////////////////////////////////////////// // Updates the LCD /////////////////////////////////////////////////////////////// void updateDisplay() { if( dispMetro.check() == 1 ) { switch( dispMode ) { case dispModeListeningOnText: lcd.clear(); lcd.print( "Listening on:" ); break; case dispModeListeningOnValue: lcd.clear(); lcd.print( listeningOn ); break; case dispModeControlCodeOneText: lcd.clear(); lcd.print( "Control code 1:" ); break; case dispModeControlCodeOne: lcd.clear(); lcd.print( "QZ = rmtmgmt on" ); break; case dispModeControlCodeTwoText: lcd.clear(); lcd.print( "Control code 2:" ); break; case dispModeControlCodeTwo: lcd.clear(); lcd.print( "JV = rmtmgmt off" ); break; case dispModeRemote: lcd.clear(); lcd.print( "Remote mgmt: " ); lcd.setCursor( 13, 0 ); lcd.print( remoteManagementActive ? "Y" : "N" ); break; case dispModeProbingFor: lcd.clear(); lcd.print( "Probe for: 4zt3c" ); break; default: dispMode = 0; } // Cycle display if( ++dispMode >= numModesActive ) dispMode = 0; } } /////////////////////////////////////////////////////////////// // Checks the LDR against the threshold // Returns penalty /////////////////////////////////////////////////////////////// int checkLDR() { int penalty = 0; if( !LDRTripped ) { // Read LDR int val = analogRead( LDR ); if( val > LDRThreshold ) { penalty += LDRPenalty; LDRTripped = true; } } return( penalty ); } /////////////////////////////////////////////////////////////// // Checks all tripwires // Returns accumulated penalty /////////////////////////////////////////////////////////////// int checkTripwires() { int penalty = 0; for( int tripWire = 0; tripWire < numTripWires; tripWire++ ) { if( !tripWireTripped[tripWire] ) { if( digitalRead( tripWirePins[tripWire] ) == LOW ) { penalty += tripWirePenalty[tripWire]; tripWireTripped[tripWire] = true; if( tripWire == 3 ) { // Fire the Nerf gun! Ahahahhahahaaaaaa! digitalWrite( relay, HIGH ); delay( 2000 ); // Cease fire! digitalWrite( relay, LOW ); } } } } return( penalty ); } /////////////////////////////////////////////////////////////// // Checks the FSR // Returns penalty /////////////////////////////////////////////////////////////// int checkFSR() { int penalty = 0; if( fsrMetro.check() == 1 ) { // Turn on LED digitalWrite( fsrIndicator, HIGH ); if( !FSRTripped ) { // Read FSR int val = analogRead( FSR ); if( val < FSRThreshold ) { penalty += FSRPenalty; FSRTripped = true; } } // Delay to blip the LED delay( 10 ); // Turn LED off digitalWrite( fsrIndicator, LOW ); } return( penalty ); } /////////////////////////////////////////////////////////////// // Checks status of button // Resets sensors when pressed /////////////////////////////////////////////////////////////// void checkLCDButton() { if( digitalRead( lcdButton ) == HIGH ) { resetTraps(); digitalWrite( lcdLED1, HIGH ); } else digitalWrite( lcdLED1, LOW ); } /////////////////////////////////////////////////////////////// // Resets everything for the next team! /////////////////////////////////////////////////////////////// void resetTraps() { // Reset health health = 1400; FSRTripped = false; fsrMetro.interval( fsrFastPoll ); fsrFastPolling = true; for( int tripWire = 0; tripWire < numTripWires; tripWire++ ) tripWireTripped[tripWire] = false; LDRTripped = false; LDRThreshold = ldrLowThreshold; ldrIsThresholdLow = true; numModesActive = dispModesRemoteOff; remoteManagementActive = false; digitalWrite( lcdLED2, LOW ); } /////////////////////////////////////////////////////////////// // SerialEvent occurs whenever a new data comes in the // hardware serial RX. This routine is run between each // time loop() runs, so using delay inside loop can delay // response. Multiple bytes of data may be available. /////////////////////////////////////////////////////////////// void serialEvent() { while( Serial.available() ) { // get the new byte: char inChar = (char)Serial.read(); // add it to the inputString: serialInput += inChar; // if the incoming character is a #, set a flag // so the main loop can do something about it: if (inChar == '#') serialInputMessageComplete = true; } } /////////////////////////////////////////////////////////////// // Processes input from the PC /////////////////////////////////////////////////////////////// void processSerialInput( String message ) { if( message.startsWith( "STATUS" ) ) // Return sensor status { Serial.print( "STATUS FSR " ); Serial.print( FSRTripped ? "T " : "N " ); Serial.print( fsrFastPolling ? "F" : "S" ); Serial.print( " LDR " ); Serial.print( LDRTripped ? "T " : "N " ); Serial.print( ldrIsThresholdLow ? "L" : "H" ); for( int tripWire = 0; tripWire < numTripWires; tripWire++ ) { Serial.print( " TRIP " ); Serial.print( tripWire + 1 ); Serial.print( tripWireTripped[tripWire] ? " T" : " N" ); } Serial.print( " RMGMT " ); Serial.print( remoteManagementActive ? "Y" : "N" ); Serial.print( " HLTH " ); Serial.print( health ); Serial.print( "#" ); } else if( message.startsWith( "LDRLOW" ) ) // Adjust LDR { LDRThreshold = ldrLowThreshold; ldrIsThresholdLow = true; Serial.print( "OK#" ); } else if( message.startsWith( "LDRHIGH" ) ) // Adjust LDR { LDRThreshold = ldrHighThreshold; ldrIsThresholdLow = false; Serial.print( "OK#" ); } else if( message.startsWith( "FSRSLOW" ) ) // Adjust FSR { fsrMetro.interval( fsrSlowPoll ); fsrFastPolling = false; Serial.print( "OK#" ); } else if( message.startsWith( "FSRFAST" ) ) // Adjust FSR { fsrMetro.interval( fsrFastPoll ); fsrFastPolling = true; Serial.print( "OK#" ); } else if( message.startsWith( "REMOTEON" ) ) // Toggle remote management ON { numModesActive = dispModesRemoteOn; remoteManagementActive = true; digitalWrite( lcdLED2, HIGH ); Serial.print( "OK#" ); } else if( message.startsWith( "REMOTEOFF" ) ) // Toggle remote management OFF { numModesActive = dispModesRemoteOff; remoteManagementActive = false; digitalWrite( lcdLED2, LOW ); Serial.print( "OK#" ); } else if( message.startsWith( "07:" ) ) // Set phone number { listeningOn = message; Serial.print( "OK#" ); } else if( message.startsWith( "RESET" ) ) // Resets all the traps { resetTraps(); Serial.print( "OK#" ); } else if( message.startsWith( "HEALTH" ) ) // Outputs health only { Serial.print( health ); Serial.print( "#" ); } else Serial.print( "Uknown!" ); // Done with the message now serialInput = ""; serialInputMessageComplete = false; }

In part two of this post, I’ll delve into TempEx One and its control unit – stay tuned! In the meantime, perhaps you’d like to get yourself an Arduino and start tinkering?



Alec Waters is responsible for all things security at Dataline Software, and can be emailed at alec.waters@dataline.co.uk



Share this: Twitter

Reddit

Facebook

LinkedIn

Like this: Like Loading... Related