CWE-535, Exposure of Information Through Shell Error Message, describes a command shell error message that reaches the user. MITRE says it indicates an unhandled exception in the web application code, and that in many cases an attacker can use the conditions that cause the error to gain unauthorized access.
How it happens
An application runs a shell command, or something that behaves like one, and the command fails. The code has no handler for that failure, so the raw output from the shell is returned in the response.
That output can name commands, paths and arguments. It shows the attacker that user input is reaching a shell, which is a useful discovery by itself.
What an attacker gains
MITRE lists reading application data as the confidentiality impact. Beyond the text itself, the error is a signal. It tells an attacker where to probe next, because input that breaks a command is often input that can steer one.
How to find it
- Send unexpected input, such as empty values and odd characters, to every field that might reach a command and watch the response body.
- Review code that spawns processes and confirm every failure path is handled.
- Use static analysis. MITRE notes it can find some instances of this weakness.
How to fix it
The MITRE page for this entry lists no separate mitigations, so these steps follow from its description:
- Catch failures from any command execution and return a generic message to the user.
- Log the detail on the server where only your team reads it.
- Avoid passing user input to a shell at all. Call the program with an argument list instead of one built string.
import subprocess
# Safer: argument list, no shell, generic error to the user
try:
subprocess.run(["convert", filename, "out.png"], check=True, shell=False)
except subprocess.CalledProcessError:
return "Could not process the file.", 400
Quick check
Why is a shell error worse than an ordinary error page?
It shows that input is reaching a shell, which points an attacker toward command injection.