Command injection vulnerability

When the system() or popen() function is used with externally-influenced input, it's possible for a malicious user to inject a string and execute arbitrary commands and code with the privileges of the attacked process. For example, an attacker could inject a semi-colon to end one command and insert a new, unrelated command for execution.

Vulnerability and risk

A system() or popen() call that's vulnerable to command injection can result in

  • execution of malicious code
  • creation of a new user account to access a compromised system
  • arbitrary command execution with a higher privilege level than the standard user

In a worst-case scenario, an attacker could inject a string that takes control of the system, and for instance, delete the contents of the root partition.

Mitigation and prevention

To avoid this issue, it's best to

  • use only constant strings with a system call
  • add validation code before command execution
  • use library calls rather than external processes
  • use whitelist rather than blacklist input validation
  • use the exec family of functions to run external executables
  • make sure any external executable can't be written by the user
  • implement functionality directly in the program with calls to existing libraries

Vulnerable code example

  char *constbuf = "bash";
  int main()
       char buf[100];
       system("echo \"constant string: no warning\"");
      popen("echo OK","r");
      popen(constbuf, "r");
      popen(buf, "r");
      return 0;

In this example, Klocwork produces an issue report at line 9 indicating that system() function may accept a command line that can be influenced by the user, causing the execution of arbitrary code. A similar warning is reported for function popen() at line 12. In either of these cases, an attacker could inject commands to execute malicious code, even to the extent of taking control of the system or deleting the root partition. The system function calls in lines 6 and 8 use a constant string and a library call as arguments, so they aren't open to the possibility of code injection and aren't flagged.

Related checkers