Cybersecurity Missteps Passwords Security Trial by Fire: A Series

Misstep 9: Trial by Fire, the Perfect Storm that Created Me

Welcome to the second misstep of 2020… A series of hindsight. Back in late 2006, I started a small forum site where I learned that building desktop applications != hosting web applications that other people use. The former may be breakable, but it won’t hurt myself or other people. The latter can devastate a business and other users.

It wasn’t that I didn’t care, it was that I didn’t know better. A lot of developers are in the same boat. They want to build systems well, but they simply do not have access to the training or tools to determine if it was built securely.

Today, I want to take you on an adventure back to 2006/2007. I was working overnight 12-hour shifts in a factory, convinced I wouldn’t find a career in information technology. I’d get off at 6:30am, drive home and usually hop online to my new creation. I didn’t have a smart phone, so I couldn’t check my sites and see if there was spam or other issues, so it would go all night long unwatched. Here’s what that site looked like:

My first forum site, with blogs and articles

First things first, it was a WATP site… Windows, Abyss, Text File, and PHP site. If I recall correctly, it was PHP 5.1.6. I was a bit apprehensive learning MySQL at the time, or Linux, and wanted to focus on PHP only. This is why PHP is called “insecure”, it is simple to get something up and running that is terrible. So, people like me write legit crap and publish it.

The forum posts were all stored in text files, as were sessions, user logins (plain text the first few weeks, then unsalted MD5!), etc. This works reasonably well since I would extort a handful of friends to use my site and, even then, nobody wanted to use it. There were no chances for a race condition to happen.

Race Conditions Happen

A race condition happens when two or more actions are applied to the same datastore at the same time. My file structure was simply a random number. PHP’s random number generator is awful, and this practice is awful. Let’s take a peek:

$titl = strip_tags($_POST["titl"]);
$dat = strip_tags($_POST["dat"]);
$msg = strip_tags($_POST["msg"]);
$poster = strip_tags($_POST["poster"]);
$rnd = rand(0,999999);

//Convert linefeeds to bbcode key and remove. Apo's are done in edittopic.php
$msg = nl2br($msg);
$msg = str_ireplace("<br />", "[br]",$msg);
$msg = str_replace("\r", "", $msg);
$msg = str_replace("\n", "", $msg);

$file = fopen("forum/" . $rnd . ".txt", 'x');
fwrite($file, $titl . "\r\n");
fwrite($file, $dat . "\r\n");
fwrite($file, $msg . "\r\n");
fwrite($file, $poster . "\r\n");

So, I’m taking a random number as a file name, and adding each “field” as a newline within the file.

PHP’s random number generator is seeded by the current timestamp, so within a few milliseconds of each other, two posts can create the same topic, throw off the posts, or cause some people’s posts to be overwritten. It was a hot mess.

Race Condition + c:\site\sessions.txt

I had committed several “sins” of secure development at the time:

  • I did not use atomic identifiers on files, meaning two writes would cause an error in some conditions.
  • I did not turn off error reporting, I was editing the site live on the server, so I thought I needed to display errors.
  • I stored the “sessions” file within the webroot.

So, I had a few folks who would use my site who also had some legit curiosity into a site’s inner workings. It so happened when this user, we’ll call him “Cody”, logged into the site and spotted a write error on the site. Something along the lines of:

Parse Error: Could not open c:\site\sessions.txt for writing.

Quite possibly, accessing this file via would be the next thing that was attempted. And, this Cody did. Inside this file, he seen my username, next to a session ID. He then copied that into the browser, and he was in my account.

I get home from work, to find I was online all night…

Several posts were made from my account, mostly about how I’ve been owned and such. I totally deserved it. As a matter of fact, here’s the forum topic that told me about the exploit. Sadly, I don’t have the site running, so I can only show you a (Somewhat anonymized) forum “file” instead:

Attention Bob
Fri, 16 Feb 2007 16:24:34 CST
This is why SQL > TXT.[br][br]Love,[br]Cody
Fri, 16 Feb 2007 21:17:06 CST
I been hacks.
Tue, 27 Feb 2007 20:25:48 CST
Should be fixed now.

This post was from my account, since my session ID was exposed. I was able to fix it, but even my fix was implemented somewhat poorly.

Security by Obscurity, and other hilarious antics

$cok = $_COOKIE["COOKIE"];
$filses = @fopen("" , "r");
while ($names = @fscanf($filses, "%s\t%s\n")) 
	list ($userkey, $username) = $names;
	if ($userkey==$cok)

So, the sessions.txt file was changed to “online.bmp”. Still in the webroot, but a little less likely to be spotted. Also, I added the error control operator “@” before the file functions (fopen, fscanf, and fclose) to hide the errors. Now, we’re getting errors that nobody knows about, but hey, it’s not giving away my clever fix.

Later, I added in an additional check. You would have to have both the session ID, and be on the same IP address as you were at login to stay logged in. Hey, this sounds fantastic! And it would be, except for these two failures (which I don’t have the code for anymore):

  • I typo’d… I used a single equals sign (=) or assignment, instead of a double (or triple) equals sign (== or ===), comparison and strict comparison, respectively. So, what ended up happening is that sessions were now disregarded, and the IP address is what was important. So, living at home with the rents at the time, my younger brother kept accidentally posting from my account and didn’t know why. This took an embarrassingly long time to correct.
  • Some users were using AOL’s custom-wrapped Internet Explorer, which proxies requests via different cache servers. This means that the IP wasn’t steady, and some users were randomly being logged off as a result.

I remember sharing my IP-following idea with Michael Coates at THOTCon 0x1 back in 2010, who liked the idea, but was immediately familiar with the issue you’d face with transient IP addresses.

Over time, I’ve improved how I’ve handled sessions, using PHP’s in-built session mechanism, ensuring proper entropy, proper cookie flags, and so on. This resolved my authentication woes, but there were still plenty more problems I was tempered by.

Join me again next Tuesday to see what other awful mistakes I’ve made.

Cybersecurity Missteps Security

Misstep 8: How I Was Almost Hacked

An attempt to upload a PHP script as an image

Very many moons ago (ca. 2008 or so), I built an online image resizer. This was before HTML5 Canvas, so I leveraged PHP and GD Library to handle the resize. Nothing too special really, but I looking to learn image manipulation and provide a tool for people to use when they use forums.

Recently, I was digging out some old server harddisks I had in a crate and decided to start pulling files off before I destroy them. Inside the /imageresize/ directory, I found a few images that were not being correctly rendered by my OS. I made a guess that these would either be empty files, or a corrupt file due to an injection attack. So, I opened these up in Bless Hex Editor and had a peek, and I wasn’t surprised what I found.

People were uploading these files and including the following code:

echo 'oh dear.';

If the above code were executed, it would be relatively harmless, simply disclosing some server information (global variables and paths being the worst), and then say “oh dear” on the screen. This would be a great way to test if my server was allowing uploads that could later be executed, as it would give visible output and would not leverage a restricted function. Once this was determined, some file or other web shell would probably be uploaded, my sites taken offline or defaced, and the server used for malicious purposes.

Why this didn’t cause a breach:

  • My script removed the submitted file extension and replaced it with the appropriate file extension according to the browser’s suggested MIME (Media) type
  • My server was only configured to allow *.php and *.html (I know, whatever) to execute as a PHP script, so .jpg/.jpeg/.png/.gif etc would not have ever executed
  • I dropped the file name as well, replacing it with an MD5 of a current timestamp with a salt

What I did wrong:

  • I was storing the file uploads directly in the root directory. Files should not have been uploaded to any web accessible directory.
  • I was relying on the provided MIME (Media) type to determine file extension, this did not mean the file was what it said it was.
  • By using the current timestamp instead of an atomic value, I introduced a race condition where several people may receive the wrong image if they’re uploaded within the same second.

The important thing is learning what you did that was so wrong. Regardless, I’ve removed some domain references and empty lines, and threw a die() at the beginning, but here’s the terrible source if you’re interested:

Over the next few weeks, I’ll share a new series Missteps: Trial by Fire detailing terrible development decisions I’ve made, what I’ve learned from them, and how I’ve become an actual software engineer, and a consultant in the security industry.

Locksmithing Missteps Physical Security Security

Misstep 7: Knoxoff KnoxBox

Low Security Key Holder

Alright, after this post, I’m taking the rest of the year off!

I’ve talked about this one before in Lockboxes and Key Space Exhaustion, and I’ve seen this guarding both a bagel/coffee shop out in LA, a restricted-use boat launch, and this dollar store back home. This photo shows the one by my place that is apparently just caulked to the building. I’m not sure if they’re using this for shared access to a control room or as a “KnoxBox” for first responders.

Even the manufacturer points out that the device is for convenience, not for security. A master-keyed cylinder or badge system would be better approaches to a multi-tenancy door, however without knowing its objectives, its hard to quantify if it is a big issue or not.

Join me next Tuesday, in 2020 — I’m going to start picking on some of my poor security choices over the years as well!

Missteps Physical Security Security

Misstep 6: Moneygrab

Key in Register
Key left in register in cluttered shop

This one is less about what you’re seeing, and more about temptation. This cash register has the drawer key sitting directly in the lock it is supposed to protect.

Cashiers should be performing “NO SALES” if they need access to the cash drawer without a transaction. This keeps a record of times an employee accesses the cash for reviewing with cameras or training purposes. They should not be using a mechanical bypass to enter the cash drawer.

Likewise, leaving a key in a cash drawer invites robbery by demonstrating that access to the cash will be easy and that security is lax.

Besides these issues, a key in a cash drawer is pretty meaningless, since access to most can be granted by way of a small drawer release lever on the underside of the unit, which is another reason why these units should be attached to a solid surface.

Missteps Physical Security Security

Misstep 5: Getting High in California

By getting high, of course, I’m talking about the relative distance from the ground. In this case, I added three stars to the image.

The first one is the “Yellow Star”, I’m not going into a lot of detail here except to say that Misstep 2: Security-As-An-Annoyance goes into greater detail about why a fence and a lever make a bad combo.

This week we’ll take a look at the blue star, where there’s a decently tall chain-link fence, above which there is barbed wire. From the outset, this seems fine, but there are two tactical mistakes at play here:

  • The barbed wire faces inside of the property. This is acceptable if you’re trying to keep something in (think prisons), otherwise, it should be facing out. This makes it harder to simply throw a jacket or blanket over the barbs and jump the fence.
  • The somewhat funnier one is by the red star… This fence is substantially shorter (guessing 5′ tall), no barbed wire, provides concealment for what is on the other side, and won’t make a bunch of noise when you jump it. It will be slightly harder to get a footing, but the flat top should prove easy enough.
Missteps Physical Security Security

Misstep 4: Pretty Friggin’ Suite

A door showing a locked deadbolt and exposed hinges

Another example of “A chain is as strong as its weakest link”, this door was inside of my suite during my stay in Los Angeles. I assume it is for cleaning supplies, coffee supplies, or similar so that the room service folks can save time not transporting all of this without an elevator.

But lets just pretend for the sake of this blog that they store some fine Chicago-style pizzas, millions of dollars of money, and some Cinnamon Coke behind here. First of all, I wouldn’t have wrote this blog because I’d have broke in already. But, here we are.

The deadbolt was locked with what strikes me as a Kwikset KW1 keyway (may be a 6-pinner, no idea). Let’s just say I can’t pick a lock? How else can I breach this door non-destructively?

A door hinge

Generally you’ll have an “unsecured side” and a “secured side”, or “sterile side” in FAA parlance. This delineates the side that is public, and a side that is private (boarding area for aircraft, or this sweet pizza closet in my suite).

In this case, these hinges are on the unsecured side. I can easily drive the hinge pins out of the door and gain access to this closet. The two halves of the hinge will easily slide apart in this case.

Because I didn’t want to trespass, I did not verify if this was implemented securely. In order to have the hinge pins on the unsecured side, you can use “security pins”… These tiny devices will replace some of the hinge screws in the door or frame, and recess into the mating surface. In this way, the hinge halves will not slide among each other — increasing the security of this approach.

Here’s some on Amazon (these may not be the cheapest, I don’t know. It’s also not a referral link):

Missteps Physical Security Security

Misstep 3: Flow Freakin’ Way

Unprotected water control valve
Sweet Cage Decoration

From my trip to LA, I’ve seen several of these water control valves placed above ground. (Must be nice, in Chicago, these guys would turn into ice and destroy themselves).

An oddity is the choice of security — a wire mesh that stops folks from disabling the water. This could affect fire systems, but those usually have a standpipe or external outlet for sprinklers, but what this can mean is — when your coworkers are coming back from the company Chipotle outing, they can’t evacuate the sinister remnants effectively.

The cages are a minor obstacle, since these are quarter-turn ball valves, they only have to be rotated 90° in order to turn off (or on) flow.

Inserting a stick, pipe, or some other rigid instrument and biasing it against the wire cage would create plenty enough of a lever to force the valve shut.

Solution? Lock the valves like everybody else, except this water main, since it uses a hilariously deficient “warded Master Lock” that can be trivially bypassed in several ways (shimming, warded picks, keys that accommodate wards, etc)

Water main showing a Master Warded Lock
See the bottom of the chain between the valves
Missteps Physical Security Security

Misstep 2: Security-As-An-Annoyance

A locked door at a hotel pool where the gate allows easy access to the opposite handle.
So ez

I’m in Los Angeles, CA this week and my hotel has a pool. Like many hotel pools, they lock it down at a silly early hour. They also keep the area locked to ensure that the pool isn’t being abused by non-guests.

With several different shifts of hotel operators, and this hotel’s nature of having several outdoor buildings for rooms, it would be very difficult for a hotel employee to identify who is a guest and who isn’t.

While there isn’t anything of value behind this gate, it does demonstrate an oversight in design. My hands were only slightly too fat to fit next to the handle, to turn the “inside” handle and gain access. People with smaller hands, those who are clever enough to bend a wire coat hanger, and those who also really need to swim can bypass this sort of gate easily.

I’d argue that this isn’t a big deal here, since the gate is there to prove trespassing and deny liability if you didn’t belong there in the first place. Either way, an interesting conversation piece.

It should be noted that these types of lever handles are required by ADA standards (in the US) to enable people with advanced arthritis, or other physical ailments to open doors where they cannot grasp a knob. That is why replacing these with knobs is not a workable solution.

Missteps Physical Security Security

Misstep 1: A Chain is as strong as its weakest link

A Trek Hybrid for the low cost of a front tire

I wanted to start a new blog feature where I share occasional security missteps just sitting in public.

These bikes are not cheap, generally starting at $500 and climbing rapidly.

This bike is held in place by a typical U-bolt lock, but the front tire is held in by a quick connect near the bottom of the rim, through the spokes (meaning it takes no tools and only a flick of your finger to release the tire, and thus: the bike).

Say you wanted to save some additional funds and you carry a Leatherman? Cut a few spokes and ride off on it. Later, order a few replacements … Or if needed, a rim.

You can have the world’s strongest lock. It means nothing when the entire situation isn’t considered.