Server-side security war games: Part 16

This is the last level. We’re challenged with an improved version of level 9 – they’ve added additional “sanitation” to keep us out.

    if(preg_match('/[;|&`\'"]/',$key)) {
        print "Input contains an illegal character!";
    } else {
        passthru("grep -i \"$key\" dictionary.txt");

Okay, so we have to deal with two levels of escaping here:

  1. We can’t use semicolon, pipe, ampersand, backtick, single-quote, or double-quote
  2. $key is now double-quoted

There are still some tricks we can use. For example, we can still use command substitution ($()). I found this level very tricky, until I thought carefully about how to make that work for me. In particular, I needed to do a character-by-character guess/search, just like with the SQL injection attack in level 15.

Here’s the strategy. We want to get a boolean response for whether we guessed one character of the password correctly. Let’s use a word we know is in the dictionary to turn this search into a boolean response. If we grep for “hacker” in dictionary.txt, then it shows up. If we can make the command grep for “0hacker” on the other hand, it doesn’t show up, as that’s not a word in the dictionary. So, we can use that 0 to do a search. As with the blind SQL injection attack previously, we’ll go character-by-character.

We can inject $(grep -E ^%s /etc/natas_webpass/natas17)hacker. If the password in /etc/natas_webpass/natas17 contains the character we picked, then it’ll output that character. Then, the outer command will search for 0hacker, for example, which won’t be found in the dictionary, so we’ll see no output. So, if we see “hacker” in the output, we know we guessed the wrong letter. If we get nothing, we know we guessed the right character. Simply iterate through the alphabet for each of the 32 characters in the password, and you can figure out the whole thing.

As with the previous level, provide the right password as the first argument on the command line when running to do this search automatically:

Level 17

You can log in to verify you got the right password, but there’s nothing further. You won!

Lessons learned

As with level 15, a seemingly-limited opportunity for command injection turned out to be fatal. Don’t be injectable. For SQL, use parameterized queries. For system commands, be sure your invocation doesn’t involve the shell, and whitelist acceptable input rather than blacklist.

If you enjoyed this walkthrough, let me know in the comments! I’d love to hear about your alternative approaches. has a bunch more war games. If server-side security isn’t your thing, take a look at what else is available.