OWASP’s Description of Command Injection:

Command injection is an attack in which the goal is execution of arbitrary commands on the host operating system via a vulnerable application. Command injection attacks are possible when an application passes unsafe user supplied data (forms, cookies, HTTP headers etc.) to a system shell. In this attack, the attacker-supplied operating system commands are usually executed with the privileges of the vulnerable application. Command injection attacks are possible largely due to insufficient input validation.

This attack differs from Code Injection in that code injection allows the attacker to add their own code that is then executed by the application. In Command Injection, the attacker extends the default functionality of the application, which execute system commands, without the necessity of injecting code.

The last part of that sentence, without the necessity of injecting code, is an important one when trying to differentiate between whether something would be considered a Code Injection or a Command Injection. Yes, we executed commands in a system shell in the previous example through a Python web application, but the only way we were able to execute those system commands was through the initial Python code injection.

In the following Command Injection example from TryHackMe’s Devie, we will be injecting commands into a bash script that is being run from a root owned cron job. This is the script being run by the root user every few minutes:

#!/bin/bash
cd /home/gordon/reports/
cp * /home/gordon/backups/

The shell script is using the * wildcard with cp to copy all files from /home/gordon/reports/ into /home/gordon/backups/, which is what will allow us to inject a command, or in this case, we will be creating a file name that will be interpreted as a switch by cp. This is similar to the tar exploit. The switch we’ll be injecting is --preseve=mode, which will save the file’s modes (e.g. srwx) from one file into another file. In this case we want to preserve the sticky bit that we will be adding to a copy of bash.

First change to the directory where the cron script will be copying files from

cd /home/gordon/reports/

Then copy bash into that directory and set it as a suid binary

cp /usr/bin/bash ./rootbash
chmod 4777 rootbash

This is what the file permissions and attributes will look like after we do that

Root Bash

Notice that after we copy /bin/bash to our current directory as rootbash that the owner and group has been changed to Gordon, rather than having root as the owner and group as is typical of /bin/bash. The cp command by default changes the group and owner to that of the user executing cp. If we left this as is, and the root cron script ran, then the rootbash file would be copied to /home/gordon/backups/, it’s new owner would be root since the cron job is owned by root, however the suid bit would get removed in the process, making the newly copied rootbash useless as a method to escalate to the root user. What we want to do is preserve the sticky bit when the file is copied, and to do that we will be using the --preserve switch with cp.

from the cp man page

–preserve[=ATTR_LIST] preserve the specified attributes (default: mode,ownership,timestamps), if possible additional attributes: context, links, xattr, all

We’ll be using mode with --preserve to preserve the sticky bit that we already set on the rootbash binary. The term mode might not be famililar to you, but if you understand that the chmod command stands for ‘change mode’, which is what we did when we added the numeric mode 4777 to the copied rootbash binary, then it might make more sense. If we were to use --perserve=all then not only would it copy over the binary’s mode, it would also copy the owner and the group, which for our rootbash binary is currently Gordon, which again would make the binary useless as a means to escalate to the root user. What we want to do is preserve the sticky bit only and have the user ownership switch over to root, which will happen automatically when the cronjob owned by root executes the script copying all those files.

To perform the command injection we will create the following file in /home/gordon/reports/

echo '' > '--preserve=mode'

The directory will then contain the following files

copy switch as a file

Once the cronjob executes we can see that rootbash was copied into the backups directory and that the sticky bit. In addition, rootbash is now owned by root. To elevate to the root user run ./rootbash -p

Rootbash Priv Esc