But the OpenSSH they have in OpenBSD is maintained in-tree I think. And then they have the portable OpenSSH that they maintain separately for other systems to use. And then changes in either are probably integrated into the other keeping them largely the same.
But there surely are some features in either that are intentionally kept out of the other?
Yes, that is what I am talking about. This has no use for it in the in-tree openssh of BSD, so it wouldn't surprise me if this specific patch is omitted from the in-tree variant.
> This is a port of OpenBSD's OpenSSH to most Unix-like operating systems, including Linux, OS X and Cygwin. Portable OpenSSH polyfills OpenBSD APIs that are not available elsewhere, adds sshd sandboxing for more operating systems and includes support for OS-native authentication and auditing (e.g. using PAM).
Privilege separation[1], most likely. If your system needs to do three things, it could either just do all of them using a single executable requiring all three permissions (thus also theoretically allowing an attacker to use it to do all three things as well) or split your system into three executables, each only having the permission to do one thing (thus reducing the amount of potential damage).
Yes and no. At least one process needs to run as root to be able to become any (other) user. It doesn't have to be the one accepting incoming connections, or the one handling user authentication and authorisation. OpenBSD already contains several examples of this e.g. OpenBGPd limits the attack surface by putting the BGP session handling (and protocol parsing) in one process running with reduced privs (dedicated user and group, chroot(), pledge()/unveil()). To communicate with the other processes the parent creates unix socket pairs to be inherited. The children also re-exec after fork() so they're re-randomised and can't be abused as oracles for the memory layout of other processes.
Assuming that baseline protections (ASLR, DEP/Nx etc.) are present, the goal when pruning parts of a binary is probably to reduce the availability of ROP gadgets [1]. This will make it harder to exploit any remaining bugs in the "useful" code.
OpenBSD appears to be taking a safe/conservative approach based on linking. More aggressive approaches have also been researched, where the pruning is driven by dynamic analysis, and applied using binary rewriting.
The best source for the history of the work are probably the OpenBSD mailing list archives and commit logs, but digging through that is slow and requires context.
OpenBSD recently added a bunch of new security mitigations most hardening processes against remote code execution. As of the latest release (OpenBSD 7.4) the runtime linker registers all system call entry points per memory mapping with the kernel (offset in the mapping + the system call number). They also removed the indirect system call (where the syscall number is the first argument). With this in place a process can only perform those system calls still allowed by its pledge()+unveil() for which there exists an entry point. If dead code elimination removed all fork() and exec() syscalls from your process your attack won't be able to turn the compromised process into a (useful) reverse shell.
The idea appears something like this:
You have a very small TCP listener that probably that forks+execs per accepted connection. The reduced complexity of this piece makes it both easier to audit and harder to exploit.
* The per session binary only contains the code to handle authentication and authorization (and accounting) of a single connection and fork/exec() into the next stage.
* The listener could also re-exec() itself every so-and-so number of connection attempts to replace its image with a newly randomised instance of the same executable. This would limit the number of attempts an attacker has to reuse any information learned about the current listener process's memory layout should such a leak be found.
The goal is to provide defense in depth instead of a single "magic bullet" e.g. rewriting it a "safe language" (trading new logic bugs in new code against memory safety bugs not yet found in old code). Splitting the OpenSSH server into multiple smaller processes also allows existing mitigations (some of them OpenBSD specific) to become more effective.
In addition, it says that, like sshd before, sshd-session will be randomly re-linked on boot/upgrade (along with the kernel and libc I believe) and so have different addresses.
22 comments
[ 3.0 ms ] story [ 33.9 ms ] threadThere is only one OpenSSH, and it is developed by the OpenBSD folks and used by everyone else.
But there surely are some features in either that are intentionally kept out of the other?
But the notification mechanism isn't really systemd specific, so maybe they can make use of it somehow for something, dunno.
?
* https://github.com/openssh/openssh-portable
Perhaps see specifically the "openbsd-compat" directory, otherwise I think the source tree is very close the the 'OpenBSD version':
* https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/
(Presumably it reduces attack surface by getting exploits in the session out of the listener but does it have greater significance?)
[1]: https://en.wikipedia.org/wiki/Privilege_separation
OpenBSD appears to be taking a safe/conservative approach based on linking. More aggressive approaches have also been researched, where the pruning is driven by dynamic analysis, and applied using binary rewriting.
[1] https://en.wikipedia.org/wiki/Return-oriented_programming
Any place(s) one can read more about this research?
The best source for the history of the work are probably the OpenBSD mailing list archives and commit logs, but digging through that is slow and requires context.
[1] https://bibbase.org/network/publication/kroes-altinay-nash-n...
The idea appears something like this:
You have a very small TCP listener that probably that forks+execs per accepted connection. The reduced complexity of this piece makes it both easier to audit and harder to exploit.
* The per session binary only contains the code to handle authentication and authorization (and accounting) of a single connection and fork/exec() into the next stage.
* The listener could also re-exec() itself every so-and-so number of connection attempts to replace its image with a newly randomised instance of the same executable. This would limit the number of attempts an attacker has to reuse any information learned about the current listener process's memory layout should such a leak be found.
The goal is to provide defense in depth instead of a single "magic bullet" e.g. rewriting it a "safe language" (trading new logic bugs in new code against memory safety bugs not yet found in old code). Splitting the OpenSSH server into multiple smaller processes also allows existing mitigations (some of them OpenBSD specific) to become more effective.
And from the article, looks like more to come.