5 ms·
When you SSH into GitLab, you get a "shell," which at one point was a locked-down Unix shell where you could only run Git commands. That's a workable solution,
by chatmasta 3y ago
When you SSH into GitLab, you get a "shell," which at one point was a locked-down Unix shell where you could only run Git commands. That's a workable solution, but they (rightly) migrated off it [0], so now it's just a Go program [1] that runs an SSH server and interprets a small list of valid commands. This basically inverts the security model. The Unix shell approach is leaky, because you never know if you've plugged all the holes while only allowing the commands you want. Whereas the Go program is only capable of executing a narrow range of commands, which it interprets itself, in its own fake shell, while exposing an SSH server.
Fun fact: one of the commands [2] the shell implements is `personal_access_token`, so you can programmatically mint a new PAT, since you've already authenticated via your SSH key:
ssh git@gitlab.com personal_access_token someTokenName api,read_repository,read_api,read_user,read_registry 90
[0] https://about.gitlab.com/blog/2022/08/17/why-we-have-implemented-our-own-sshd-solution-on-gitlab-sass/ https://about.gitlab.com/blog/2022/08/17/why-we-have-impleme...
[1] https://gitlab.com/gitlab-org/gitlab-shell https://gitlab.com/gitlab-org/gitlab-shell
[2] https://gitlab.com/gitlab-org/gitlab-shell/-/blob/main/internal/command/commandargs/shell.go#L13-20 https://gitlab.com/gitlab-org/gitlab-shell/-/blob/main/inter...
- kccqzy 3y agoHow is that different from writing your own shell that implements a tiny subset of the functionality with support for a small number of commands? You can even write it in Go if that's your preferred language.
- chatmasta 3y agoThat's exactly what it is, but the point is that it's not a Unix shell, and it's not running as a subcommand of SSH (which you could also do with a custom shell). There's no tty involved, and so the attack surface is reduced - if you exploit a logic error in the Go code (e.g. parameter pollution), you won't be able to do more than run one of the commands that it already runs. But if you exploit a logic error in a Unix shell with parameter pollution, then the attack surface is much greater. That said, of course if an attacker finds a bug in the Go code that enables arbitrary code execution, then the attack surface is just as wide as any other binary on the system, including a Unix shell, so you still need to lock down the privileges of the process itself.
- jolmg 3y agoI think the point is: how is bundling a custom ssh server into the same executable that interprets the commands, a reduced surface as opposed to using standard openssh's sshd, and defining a simple shell like so: #!/bin/bash cmd_foo() { printf "called foo with %s\n" "$*" } cmd_bar() { printf "called bar with %s\n" "$*" } run_cmd_call() { local cmd="$1"; shift local cmd_args=("$@") case "$cmd" in foo) cmd_foo "${cmd_args[@]}" ;; bar) cmd_bar "${cmd_args[@]}" ;; *) printf "%s: unknown command\n" "$cmd" >&2 esac } while (( $# )); do case "$1" in -c) read -ra cmd_call <<< "$2" shift ;; *) printf "%s: unknown argument\n" "$1" >&2 exit 1 ;; esac shift done if [[ "$cmd_call" ]]; then run_cmd_call "${cmd_call[@]}" else while printf "> " read -ra cmd_call do run_cmd_call "${cmd_call[@]}" done fi (then, of course,) sudo useradd -ms /path/to/custom-shell.sh userfoo sudo -u userfoo bash -c 'mkdir ~/.ssh; printf "%s\n" "$your_pubkey" >> ~/.ssh/authorized_keys' How would you "do more than run one of the commands that it already runs" with this from a `ssh userfoo@localhost` call?
- garblegarble 3y agoDon't forget to disable sftp in your sshd_config. and ssh port forwarding. and hopefully there's no sneaky way that an attacker can push an environment variable to break something like with LD_PRELOAD, and are you sure there are no directly/indirectly exploitable bugs/omissions in your script logic for invoking complex commands like git, and that your distributed filesystem works quickly across a few million home folders for your authorized_keys files, ...
- jolmg 3y agoEDIT: Crap. You're right. Port forwarding worked... So there's that. `ssh -J userfoo@localhost other-place` also worked... I would imagine that's all able to be disabled, but I see that the user is not fundamentally limited to what the shell allows. That's disappointing. I thought it would wrap everything in `custom-shell.sh -c` calls like it does with the sftp and scp servers. I imagine/hope that under a default configuration one is still not able to touch the contents of the server if the shell doesn't permit it, but being able to use it as a proxy or listen on its ports is not what I expected. ORIG_REPLY: > Don't forget to disable sftp in your sshd_config Doing `strace -fp $(pgrep sshd)` then `sftp userfoo@localhost` in another terminal, I see: $ sftp userfoo@localhost Connection closed. Connection closed $ then in the `strace` output: [pid 408173] execve("/tmp/custom-shell.sh", ["custom-shell.sh", "-c", "/usr/lib/ssh/sftp-server"], 0x55c5f3bae0d0 /* 14 vars */) = 0 [pid 408173] write(1, "/usr/lib/ssh/sftp-server: unknown command\n", 42) = 42 As far as I understand, SSH's security of what a user can do is completely based on what the shell permits the user to do. > are you sure there are no directly/indirectly exploitable bugs/omissions in your script logic for invoking complex commands like git Including a ssh server in the same executable doesn't save you from such bugs. > and that your distributed filesystem works quickly across a few million home folders for your authorized_keys files OpenSSH's sshd seems quite flexible in ways to authenticate users. I don't think having a home folder per user is necessary if you don't want it. > and hopefully there's no sneaky way that an attacker can push an environment variable to break something like with LD_PRELOAD SSH's default is to not accept the client's environment, and this shell itself provides no way to manipulate them. They can be nonexistent in the shell's interface if you don't want them. I put the script so someone can offer some concrete way (as in show me some code) to bypass it in a way that having a custom integrated SSH server would prevent it. I'd love to see a `ssh/sftp userfoo@localhost` call that does something other than call cmd_foo, cmd_bar, or erring out.
- tedunangst 3y agoAttackers cannot get access to features which don't exist even if you forget to configure them off.
- deleted 3y ago[deleted]