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.

Cybersecurity Security

I read 500 SSL Certificates so You Don’t Need To

First things first: There is no such thing as a SSL certificate. There’s digital certificate key pairs, and then there’s the protocols: SSL and TLS namely. But I’m mentally unable to break the habit of calling them “SSL Certs”, so it made it into the title.

The goal was to grab the Alexa Top 500, and do a quick scan of their certs — length, time until expiration, issuers and so on. My goal failed when I realized Alexa will give you the top 50, and wants simoleons to do so. This made my decision to use the Moz Top 500 an obvious fix — with a smooth CSV export to boot!

There’s some duplication across the top 500 ( and, and There’s also differing services from the same vendor (YouTube and Google, Microsoft and Bing). I made no effort of deduplicating either of these metrics, my feelings being that they still reflect a large part of the internet and therefore have the same impacts.

So I set off on building a script to browse to the Top 500, and throw it into a database. It worked pretty well for most of them — 76 didn’t make the cut. I then turned off peer name verification and got that down to 60. Turning off certificate verification dropped that down to 50.

Most Popular Issuers

Top Certificate Issuers in the Moz Top 500

Of the 450 domains I was able to pull a certificate for quickly and programmatically, I found that DigiCert Inc. was -by far- the most popular issuer of certificates. Any sites that had unique certs (e.g. it was the only site that used that vendor) were ignored to keep this list easy to read.

Again, there’s duplication here — and Starfield Technologies are the same issuer, just different names.

I was really happy to see my personal favorite — Let’s Encrypt — made the list. I have no affiliation with them other than using their free certificates for my websites (including this one). The only reasons I can see for companies to continue to consume paid certificates are:

  • They don’t realize Let’s Encrypt offers free certificates for both standard and wildcard certificates
  • They don’t want to deal with 90-day certificate expiration, and don’t have the ability to rollout certbot or the equivalent
  • They are still within the validity period of their current cert, riding that out until expiration.

Average Validity Length (Days)

Moz Top 500’s list of certificate providers, ordered by average validity length in days

Charts, graphs, pies… Only one of those is fun in a meeting. Since we’re all out of pie, I decided to add a nifty drop shadow to this one. I’m sure you appreciate the beauty.

In the graph, you can see on the left we have Thawte Inc. comes in at 1,106 days average validity for their certificates. That seems like an awful long time for a certificate to be valid, and I was curious who was using those:

Well, good to know I guess… Nobody is going to most of those anyways. Obviously I’m listing domains here — not all that I’ve went to myself, so if you don’t like the content, then I probably wouldn’t either.

On the other hand, Google Trust Services certs are at 84 days, and as most people know, Let’s Encrypt’s are at 90.

What can we learn from all of this? Maybe not much. Presumably, these are all industry-leading domains, so their choice of vendors and lengths may highlight some interesting information.

Cybersecurity Passwords Phishing Security Software Engineering

Stop Using Security Questions

Please stop using security questions.

Why security questions were designed with good intentions

If you forget your password, a site can ask you a series of security questions. This allows you to recover your account while still potentially authenticating you with questions only you know.

Account recovery options are always a great idea, but doing so with security questions is bad.

Insecurity Questions

Seriously — they introduce insecurity. In my experience, I’ve come across a form like this:

What is your favorite color?

Your security question must contain at least five characters!

What do you think the most popular colors are? Red? Blue? What about: teal, gray/grey, etc. A form I’ve came across actually had a 5-character minimum, which removed options from this answer and made guessing black/green/white/yellow a bit easier. My wife will tell you that everybody from the 90’s would say “Crayola Cerulean” is their favorite — I’m inclined to agree.

Facebook even has a feature where people can “know you better” where you can answer questions about yourself and paste it on your profile. Yikes!

Mother’s maiden names are easy to get from your social network (click you, click your mom, look at her friends names, or look at whom you call “aunt”, “uncle” etc).

Distributing Security Questions

I’ve once seen an admin that would screenshot a page that shown user’s security questions. This page existed to help admins verify users are who they say they are over the phone. In lieu of using it for this function, people were screen shotting this info and sending it to users who “forgot” them. Yikes.

I’m a site user — what should I do?

If a site insists you complete security questions, generate random text and throw that in the box. If you need to recover the account later, paste in that random text. While there, look for the company’s security@ e-mail, Twitter, etc. Tell them to fix it.

I’m a webmaster on the world wide web

Heh, old terms. Disable the requirement for security questions, remove account recovery until you can fix it. Replace it with CAPTCHAs and allow them to reset it via an e-mailed link. Make the link valid for <30 minutes, and with a bunch of entropy in the query string. Don’t store the expiration in the query string. If their e-mail is compromised, they indeed can steal this account. For this reason, it is imperative for users to have secure e-mail accounts. Also, wipe the security questions out of the database. If you’re compromised, those answers can quickly become public.

What if I follow the email reset and security questions?

You could. It’s better than no email reset.


Cybersecurity Passwords Uncategorized

Telltale Signs of Impending Password Breach

For most, password restrictions are an annoyance that prevents them from using easy to remember passwords, like “password” or “123456”. You can generally tell how a company handles your private information, and I’ll teach you a few tricks on determining which sites potentially store your password insecurely.

Smart Password Complexity Requirements

(none of these should be taken to indicate an insecure storage methodology)

  • Minimum character limits (for example, your password must contain at least 8 characters)
  • You must use numbers/uppercase/lowercase/symbols
  • You cannot use a dictionary word
  • You cannot use your name/username/email/other identifier in your password

Stupid Password Complexity Requirements

(it is probable that sites with these requirements are storing your password wrong)

  • Disallowing -any- symbol, be it dollar sign, comma, quotes/double quotes, hashes, less than/greater than, ampersand, and so on
  • Mentioning any upper limit to the length of your password (maximum 10 characters) *
  • Odd requirements, for example, requiring your password start or end with certain characters (letters, numbers) or prohibiting the ends of passwords from having specific characters.

*- There are functional limitations here, like the maximum POST size practical in a browser, yes, but if you can’t use a 100 character password, this is a problem.

What is a Password Hash?

There’s a separate blog post for that wee lil’ question:

What is a Password Hash?

In short, companies that care, use hashing for your passwords.

So you’re calling a company dumb, why?

Properly hashed data will return a relatively short hash from any sized input data — this is important to know, as it highlights exactly why having a maximum password length is a bad thing — it is a clear sign they’re storing your password in a really stupid way, or their devs are stupid. Either way, means bad security for you.

Now I love Southwest Airlines — a lot, I love flying with them I love their attendants, and none of their pilots have killed me. What else can you expect?

Well, I’d expect a certain level of hashing on my passwords:

Their reply wasn’t what I wanted. Basically reiterating the limitations of the form. It should be noted that this does not mean they’re vulnerable or are storing your passwords wrong, but it does make a pretty solid case that it’s possible.

Another company I used a very long time ago was TCF Bank. Now I know what you’re thinking — lmao, TCF. Yeah, their bill pay was garbage, their online banking from the 90’s, etc. I can’t speak for the interface now, but one thing that stuck out to me was the password length limit.

I’m done calling companies out now…

…Mostly because I don’t have more examples from the top of my head. When you see stupid password policies in place, it is generally in place because of a poorly configured WAF, or poorly built site. They are worried you’ll pass variables or SQL injections into their software so they filter the characters you use. Properly hashed passwords are completely inert — they are made up of hexadecimal letters without spaces, they will not execute as code.

Oh — One more thing, password resets:

If you reset your password and you get an e-mail back with your password, then they are clearly storing it WRONG. Change all of your passwords (except this site) and stop using it immediately. Close your account if possible. This site, once breached, will present no difficulty to anybody wanting your password.

Finally: Security questions suck really bad. Tell me what your favorite flavor of ice cream is in the comments!

Cybersecurity Passwords Security

What is a Password Hash?

What is encryption?

Encryption is a reversible message obfuscation technique which applies keys or mathematical models against a string of text. The key here is that, with the proper password or key, you can retrieve the original contents of the message.

Remember making up codes like “A=Z, B=Y, C=X” in school (this is a ROT13 Caesar Cipher by the way)?

That is encryption. Horrible encryption, since it is really easy to break, but it still counts.

What is Hashing?

Hashing is an irreversible message digest technique which applies mathematical models against a string of text. The same string of text will always generate the same output hash.

Let’s use MD5 because it’s old and people will comment on my blog if I mention it:

If I MD5 the word “hello”, I get the string “5D41402ABC4B2A76B9719D911017C592”

Go ahead, try it for yourself!

Every time you run a word through a hashing algorithm, it comes up with the same value. In theory, you can never “decrypt” a hash since the original information is no longer stored in it, just a representation of that data. This is the formats best selling point, and also it’s greatest weakness.

Password hashes, if unsalted/unpeppered, are vulnerable to these issues right out the gate:

  • Collisions, since we are using a limited amount of characters (in the case of MD5, 32 hex or 128-bits), it would be fundamentally impossible to ensure there is no collisions when hashed strings are both longer and shorter than 32 hexadecimal bytes.
  • Precomputed hashing tables “Rainbow Tables” — With enough time or storage, it is trivial to generate an MD5 hash of every common password (these lists are very easy to get). It is easy to reverse MD5/SHA1/any improperly handled hash. One of the biggest threats to password hashing is evolution — it used to take a “long time” to generate an MD5 hash, now GPUs can spit them out at astonishing rates. When your password is leaked by a company improperly storing your passwords, this is usually the first step — reverse all of the hashes.


What is a salted or peppered hash?

Due to the risks of precomputed hash tables, programmers have to work around the users. People will still pick terrible passwords that rainbow tables will contain. For this reason, a properly salted password is one that contains a randomly generated string for each password on the site. This is important, as using the same salt is as good as using no salt. People will get an export of your database, and generate a new table specific for your application. Having a salt for each password drastically increases the time to successfully attack your userbase (this is where password expiration come into play).

A peppered hash is a bit more uncommon, but still has it’s place. This value is an additional salt that exists only in the software. These are generally common across all passwords or are generated from other repeatable values. The purpose is layers — if the database leaks, and the pepper didn’t, it will be harder to get a password.

What is a Password Hash?

Finally — the question the post was made to answer. A password hash is simply a representation of your password that is repeatable and difficult to recover for the owners of the system and for attackers.

When you create an account, your password is hashed, therefore the site has your password but stores it in a secure manner.

When you log into the site later on, your password is again hashed and that hashed value is compared to the one from the time you created your account. If there is a match, you’re logged in. If not, it is “Forgot my Password” time.




Cybersecurity Security

Free Corporate Security Training

(Link is at bottom of post).

Every company should have a certifiable online security training, from how to handle documents to different techniques such as phishing, social engineering, etc.

I am an avid certification collector, so long as I don’t have to pay for it (and some I did). The United Nations offers several great courses in cyber security, active shooter response, and security in the field.

The two we’re going to talk about today are the foundational and advanced certificates:

Information Security Awareness - Advanced
Information Security Awareness – Advanced

Information Security Awareness - Foundational
Information Security Awareness – Foundational

The Certifications

The courses and training do have some UN-specific elements, such as reference documents within the UN pertaining to retention periods, classification and destruction of data, and UN or military-related scenarios.

I found it trivial to relate the work being done in the scenarios to my day-to-day tasks, and I find most people will not struggle with the material. There’s nothing against taking notes, but I did not need to at any point.

The foundational course is a prerequisite to the advanced course, and then there is a third one (that I have not completed) that deals with additional training.

The training reinforces best security practices:

  • Verifying encryption is being used (VPN or HTTPS)
  • Prioritizing cell-phone based hotspots instead of public wireless if possible, or falling back to encryption.
  • Scenarios demonstrating who you should share your password with and how they are social engineered from people (yes, even your manager should not have your password).
  • Password complexity rules, and entropy (how adding characters adds time to crack a password).
  • How to spot phishing sites (, etc).
  • Navigating away from browser-based virus popups instead of installing the software.
  • Always reporting errors and security issues to the IT staff.

Obviously, there’s a lot covered, as you will see. The course is offered free to everybody, so I cannot see why this would not be a good solution for small companies that cannot afford proctored exams or the development of training material.

Has anybody else found great employee-level solutions for security training? I’d love to hear about it!

Here’s the link! United Nations Information Security Portal


Cybersecurity Phishing Security Virus (Well, Phishing Scam)

First off, I want to be very clear that this is not actually a virus. This is a phishing scam.

I also want to make it clear that just seeing the domain does not mean it is a scam, likewise not seeing that domain does not imply it is safe.

Sadly, the local community college would rather tell people about art than about data security and privacy, and the term “ virus” is a term people often use for these things.

What is this Site?

It is a URL shortener, similar to,, and others. In lieu of telling a friend to visit “” you can create a short link, and tell them that instead.

That’s where the utility ends, and the scam starts. Link shorteners allow masking the actual destination of the URL, and thus, makes it harder to determine if the destination is legitimate. This site: CheckShortURL allows you to paste in the short URL and see where it is going. Always do this.

How does this scam look?

It could be anything from a friend to a post in a garage sale site. Below is an example of one I seen on a garage sale site just today:

Facebook Phishing Campaign

If you see something that sensational, it’s probably going to be fake. It has no place in a garage sale group. Another good indicator is that commenting is turned off. Why would you share news and expect no reactions? Simply put — it’s because they didn’t want the scam unveiled.

Sadly, this user probably fell for this trick, and lost her account which is now posting this in all of the groups she’s in. It may even be requesting money from friends and so on.

Facebook does not provide a good avenue for reporting this sort of issue, and garage sale group admins aren’t always online. I went after the hosting company itself “Wix” to see if they can approach it, but at the time of writing no action was performed.

So, I clicked the link to see where it goes…

… I did it safely though, using a Liveboot of a Linux distro inside of a virtual machine. This sandboxes the attack from any valid sessions I may have open. At this point I didn’t understand the attack, so I was extra cautious.

At first, the link takes you to this page:

Broken Video
Pretend broken video

Looking here, you can see the image is warning you of gruesome content — you probably expected this consider it would show people hurled off of a roller coaster. (Alright, so it’s kind of sick you’d click this, but whatever). Simply hovering over the pretend video player reveals it takes you to another site entirely… but it isn’t what you think:


Here, I left the URL bar partially visible. You can see obviously that you’re not on Facebook, but it is looking for your login. This is where people fall victim, they enter their e-mail and password to see the video. At this point, the attacker gets a copy of this.

I did a “whois” inquiry, which may allow me to see who owns this hacking domain, but the owner was hidden. The registrar was (this is where they bought the domain). All of them have style e-mail addresses to report the phishing scams, though the turn around for these sites is often low.

How do I know if it is Facebook asking for my login?

When in doubt, don’t log in. In this case, it is obvious that the site is not Facebook. In some circumstances you can specify a fake email and password. If you don’t get a “bad username or password” message, it’s probably a bad site. (This is a guide, not a rule).

So I’ve been scammed, they have my FB login, but do I get to see the video?

Imgur wtf
Imgur wtf

Nope, rather hilariously, they dump you on imgur — at a “page broken” image. There is no video, there’s only you and your vacated account.


I worked with’s abuse contacts (who is the registrar of the domain) and they acted promptly and cleared all of the DNS records for the domain, effectively taking it down.

Unfortunately, I had also reached out to Wix about the initial hosting domain, and as of this update the page is still live, and they offered to “report it” even though it is one of their own customers. Obviously, clicking the link below exposes you to part of the phishing site: