Journal / Process tree

Detection · process tree

A web server should not start a shell.

Sixteen rows in the working set are server applications, and nine of those end in code or command execution on the server. Whatever the bug, the next step usually looks the same from the operating system.

The question

Did the process that serves web requests start a command interpreter or a reconnaissance tool? On most servers the honest answer is "never, except for these three things", and that makes the exceptions short enough to list.

Parents and children

Parent: serves requestsChild worth a look
IIS worker w3wp.execmd.exe, powershell.exe, pwsh.exe, whoami.exe, net.exe
Apache httpd or apache2, nginxsh, bash, dash, python, perl, id, uname
php-fpm or php-cgiSame as above. Note that PHP itself runs inside this process
Java application servers, Node.jsAny shell, and any download tool

Match on the full image path, not the file name. A shell in a temporary directory with a familiar name is a finding of its own.

The logs you need

  • Windows: Sysmon event ID 1, process creation, which carries the parent image and command line. Or Security event 4688 with command-line auditing switched on. Without the command line you get half of the answer.
  • Linux: auditd rules on execve, or the process events from your EDR.
  • The web server's own access log, kept long enough to look up the request that arrived just before the child process started.

Build the exception list first

Some applications start child processes on purpose. GitLab calls git constantly. PHP's mail function may call sendmail. Image-processing plugins call ImageMagick. Record two weeks of parent and child pairs on each server role, review them with whoever owns the application, and write the exceptions as exact paths. Anything outside the list is worth a person's time.

The rule, in words

Parent is a web-serving process. Child is an interpreter or a reconnaissance tool. Child path and command line are not on the reviewed list for that server role. Alert with the parent's process ID and the timestamp, so the access log lookup is one step.

What it misses

Code that runs inside the interpreter and never starts a new process will not trip this. A PHP web shell that only reads files or talks to the database stays inside php-fpm. Pair the process check with a file check: new or changed script files in web-served directories, written by the service account, outside a deployment window.

It also misses activity after the attacker has moved to a different account. That is what the credential questions in Patched is not the same as clean are for.

When it fires

  1. Do not kill the process first. Record the parent, the child, the command line and the user.
  2. Pull the access-log lines for the seconds before the child started. The URL and source address are your entry point.
  3. Check the web root for files written around that time.
  4. Match the product against the working set. If it is a server application row with the triage flag, you are already in the look-back.

Sources