“Although we believe it is the user's responsibility to ensure
validity of arguments passed to ssh(1), especially across a
security boundary such as the git example above, OpenSSH 9.6 now
bans most shell metacharacters from user and hostnames supplied
via the command-line. This countermeasure is not guaranteed to be
effective in all situations, as it is infeasible for ssh(1) to
universally filter shell metacharacters potentially relevant to
user-supplied commands.” --https://www.openssh.com/txt/release-9.6
It's not quite a “root can do things as root” CVE, but honestly it's not far off that level of “well, duh”. You can't inject untrusted input (a hostname in this case) into a general purpose command stream (i.e., the arguments to bash -c or an exec call), and not expect to have trouble.
I guess the real issue is that ProxyCommand is evaluated by a shell, but the substitutions is done textually by ssh rather than by the shell, i.e., by providing the hostname via a environment variable.
Yeah, I missed the cutoff to edit my original comment. It's quite the footgun due to the combination of a forced involvement of a shell and a built-in naive value substitution.
If ssh made the parameters available as environment variables, you could do “ProxyCommand connect -5 -S localhost:9050 "$(tor-resolve "$HOST")" "$PORT"”, which wouldn't be vulnerable to this as long as connect and tor-resolve don't themselves have similar issues with their parameter handling: $HOST could still expand to other switches on tor-resolve, but it couldn't expand to extra commands or quotemarks that bash (or whatever) would process.
Which still isn't great, but at least it would be possible to get it right with sufficient care and attention.
The OpenSSH fix isn't a fix though, it depends on ssh knowing what badness needs to be filtered out, but the shell is set by the user.
It needs to be changed to pass data in a way that doesn't require escaping to reference, such as an environment variable: "$HOST" would then be expanded by the shell, and all the usual rules for safely using environment variables would apply, because ssh wouldn't be the thing performing the variable expansion like it is now.
(For most purposes, my original take in the top level was wrong, but it's too late to edit it now)
OP here. Another interesting attack vector I have been working on is OSC 8 for hyperlink support in terminals. Mostly they allow arbitrary url schemes including "ssh://" without any prompt or user interaction to consent to open an external tool like ssh client in this case.
This is interesting insight, would you care to share some parts of your ssh config indicating how you use ssh over a proxy here, most likely through a VPN?
ProxyJump is to connect to one SSH server by another SSH, right? It doesn't work against GFW. GFW throttles SSH traffic across borders to ensure that SSH can only be used for running commands rather than tunneling data.
Yeah I assumed that's what you were doing, since you mentioned Github blocked specifically. If you need to proxy through a protocol other than SSH, likely need to keep using ProxyCommand.
“Although we believe it is the user's responsibility to ensure validity of arguments passed to ssh(1), especially across a security boundary such as the git example above, OpenSSH 9.6 now bans most shell metacharacters from user and hostnames supplied via the command-line. This countermeasure is not guaranteed to be effective in all situations, as it is infeasible for ssh(1) to universally filter shell metacharacters potentially relevant to user-supplied commands.” --https://www.openssh.com/txt/release-9.6
It's not quite a “root can do things as root” CVE, but honestly it's not far off that level of “well, duh”. You can't inject untrusted input (a hostname in this case) into a general purpose command stream (i.e., the arguments to bash -c or an exec call), and not expect to have trouble.