A shell is used (and first executed) when an interactive login happens for this user-id. Putting a value such as bin/false or /usr/sbin/nologin terminates this session and essentially logs the user out.
Many system services / daemons do not use interactive logins and are started by other processes, they are assigned a user-id and group-id though, to direct what permissions its processes are running under.
Running a shell through a processes such as shell_exec()
, system()
or execve()
pretty much means to "run a shell under this UID/GID". There's no login process happening, thus the required shell (/bin/...) is not read.
Why does it still happen?
Because humans are lazy. Command injection It is bad practice, but often a quick and dirty way to get things done (ping a system, perform file operations, ...). Developers know how to do this using the shell, so use that knowledge to perform the same. Think about (yes, very messy PHP code, ...):
$pattern = $_GET["pattern"];
$fin = fopen('/path/to/your/input/file.txt', 'r');
$fout = fopen('/path/to/your/output/file.txt', 'w');
while (!feof($fin)) {
$line = fgets($fin, 4096);
if (preg_match($pattern, $line)) {
fwrite($fout, $line);
}
}
fclose($fin);
fclose($fout);
Or simply
shell_exec("cat input/file.txt | grep ".$_GET["pattern"]." > output/file.txt");
It does the same in essence, but the 2nd one is easier and quicker.