Remote Code Execution

Remote Code Execution is when external code is able to execute internal, operating-system-level commands on a server from a distance.

Once an attacker has access to the internal OS-level, it is possible to perform any task a logged in user could do.

  • Read, add, modify, delete files
  • Change access privileges, passwords
  • Turn on and off configurations and services
  • Communicate to other servers

This is the most potent attack, but it is not easy to perform. This is because there is a divide between the operating system and the software running on it. There is no casual access between them, but that does not mean there are no access pathways. Most programming languages have functions which allow them to communicate directly with the underlying OS.

In order to pull off Remote Code Execution, two things are required:

  • A programmer must use a function which allows communication with the OS.
  • An attacker must be able to get dynamic data into that function call.

Common System Execution Functions

Every programming language has different names for these powerful OS-communication functions. But many of them borrow from a pool of common function names.

  • system, %x, exec, ``
  • shell, sh, shell_exec
  • open, popen, proc_open
  • call, subprocess, spawn
  • passthru, eval

This is not a complete list, but it does provide keywords that should send up red flags if you see them being used.

Here is an example in PHP where the system() function is being used to ask the OS for a list of files in a directory.

  // list_images.php
  $dir = $_GET['dir'];
  // list files in a subdirectory of images
  $cmd = 'ls images/' . $dir;
  system($cmd, $return_value);
  echo $return_value;

  // GET: /list_images.php?dir=Vacation
  // GET: /list_images.php?dir=Vacation%3Bcat+%2Fetc%2Fpasswd
(%3B is a semicolon; %2F is a slash)

It might seem that the dynamic value of dir will be limited to listing files in the images/ directory. But the injection is able to end that command and issue a second command which lists out the contents of the system's primary user password file.

File paths

Key OS-communication functions such as system() are not the only functions which have OS access. Any function which accesses the system's files is potentially vulnerable. Use caution whenever file paths are referenced. In PHP, the most commonly used functions are: include, include_once, require, require_once. But there are many others which open, read, or save information to files.

In the case of include/require, dynamic data can be used to change which file is loaded.


  // products.php
  $info_file = $_GET['category'] . '_info.php';

  // GET: /products.php?category=hats
  // GET: /products.php?category=..%2Fprivate%2Fdb_credentials.php%3Bhats
(%2F is a slash; %3B is a semicolon)

This example tells the file system to go backwards one directory (using ..) and then to include the private database credentials file.

Remote Code Execution Preventions

The best prevention is to avoid using system functions. This is generally true, but especially when working with dynamic data. Usually there is a better, safer way to do the same thing. In some programming languages (including PHP) it is possible to disable these functions entirely so that they cannot be used.

If it is unavoidable to use system functions and for more common functions like include/require, use extreme caution and plan for Defense in Depth.

  • Whitelist actions
  • Sanitize and validate input
  • Validate returned data

Third-party software

Even if a developer's code is free of all system-calling functions, it does not mean that the system has none. Code by third-parties such as applications, libraries, and plug-ins could be using RCE-vulnerable functions.

One recent example was ImageMagic. ImageMagick is a popular image processing library used by thousands of websites. Unfortunately, it had a Remote Code Execution vulnerability, dubbed ImageTragick.

This is a good reason to reduce code dependencies on third-party software (Simple is More Secure). Only use reputable third-party software or open source software where the code can be reviewed.

Even the best third-party developers make mistakes and have to issue security bug fixes. Regular check to ensure that all software versions are up to date.

Fork me on GitHub