ssh $theRealSSHServer $SSH_ORIGINAL_COMMAND
This command, although somewhat flawed, doesn't allow command injection easily.
Even if unquoted, a variable containing; rm -rf whatever will not execute rm. Control operators like ; are identified before variable expansion occurs. When the variable gets expanded, the logic of the command line is already fixed, additional ; cannot alter it; it's just a literal ;. The same applies to a snippet like $(rm …) popping out upon variable expansion.
Still an unquoted variable undergoes variable expansion (obviously), word splitting and filename generation. See this. You can easily interfere with what an honest user wants to do on the target server. Examples:
- The user invokes
ssh proxy 'echo "I need double spaces"'. They get single spaces in the response.
- The user invokes
ssh proxy 'echo some/location/*'. * is expanded on the proxy and the result is passed to the target server to be arguments to echo there. The user will not see what they want.
- Not only they will not see what they want; they may trigger unwanted action on the target server. Imagine the expansion will get them
some/location/; rm -rf whatever (a legitimate name). This will be interpreted on the target server. There whatever will be removed (if permitted). Note rm can take multiple operands; so if there are more matches on the proxy that appear after some/location/; rm -rf whatever, their counterparts on the target server will be removed (if permitted).
A malicious user can take advantage. Examples:
- The user invokes
ssh proxy 'echo /etc/*'. It's almost like executing ls /etc/ on the proxy. How about /boot/, /lib/modules/ and subdirectories? Obtained information may help them prepare an attack.
- The user may pass options to
ssh your script invokes. E.g. if they type ssh proxy -- '-o HostName=another_server -o User=impostor -p 22' then they will initiate a connection to another server, regardless of $theRealSSHServer in your script (compare this answer). There are more options they can (ab)use. Double-quoting $SSH_ORIGINAL_COMMAND will make most such tries fail. The real countermeasure is double dash.
The command in your script should be
ssh -- "$theRealSSHServer" "$SSH_ORIGINAL_COMMAND"
Now you don't need to sanitize the original command, unless you want to do this for the target server maybe. Locally (on the proxy) this is safe.
Other parts of the script may still use the variable in a way that allows execution of (some part of) it. It's your job to make sure they don't. Examples:
The variable provides the first word of a command.
(obvious)
SSH_ORIGINAL_COMMAND="echo foo"
$SSH_ORIGINAL_COMMAND
SSH_ORIGINAL_COMMAND="date"
"$SSH_ORIGINAL_COMMAND"
(less obvious)
SSH_ORIGINAL_COMMAND="date"
cmmnd=""
$cmmnd "$SSH_ORIGINAL_COMMAND"
Note that strict double-quoting of all variables would prevent this one.
The expanded content gets interpreted on the proxy. (It is meant to be interpreted, but only on the target server).
(obvious)
SSH_ORIGINAL_COMMAND='date; echo foo'
eval "$SSH_ORIGINAL_COMMAND"
(less obvious)
SSH_ORIGINAL_COMMAND="foo'; date'"
sh -c "printf '%s\n' '$SSH_ORIGINAL_COMMAND'"
Compare this. The safe way is sh -c 'printf "%s\n" "$1"' sh "$SSH_ORIGINAL_COMMAND".
If your script doesn't do such things then double-quoted $SSH_ORIGINAL_COMMAND will not inject code on the proxy server.
Note users may specify options like -L, -t or -o in their ssh invocation. Options will not affect the connection to the target server. At least cover -t/-T, request tty or not, depending on whether the user got tty on the proxy or not:
if [ -t 0 ]; then t=-t; else t=-T; fi
ssh "$t" -- "$theRealSSHServer" "$SSH_ORIGINAL_COMMAND"
If your script was only to forward connections (not doing "extra stuff"), then it would be better to request users to use ProxyJump instead.
If your goal is to suppress some commands on the target server then you should probably apply some restrictions there, not on the proxy (set proper permissions, use some kind of restricted shell, …).