Execution of special command for a chrooted user

Hi !

I have a FreeBSD server 11.1 and I'm stuck on a peculiar problem.
I would like to set a special user who has no right except to poweroff the system. This server is only accessible via ssh.

At first, I added this user to the operator group and that works for the prime purpose. To secure the thing, I chrooted this user to /home/user/prison with the help of sshd_config. Once there, I was obliged to copy sh in prison/bin/ to make login possible.

Obviously, this user has no longer access to poweroff. The problem is: if I put a copy of poweroff in prison/bin/, its execution answers: poweroff: NOT super-user

Is there a means to allow this chrooted user to shutdown the system?
 
Last edited by a moderator:
Perhaps instead of playing with chroot, make the "poweroff" command the user's default shell in /etc/passwd. That way simply logging the user in will trigger the poweroff. So many NIX variants. You may also have to define poweroff as a valid shell in /etc/shells?
 
I like this idea. Nothing could be more efficient than that. Alas, it doesn't work.

I added /sbin/poweroff to /etc/shells and used adduser to make a test. The created user belongs to the operator group.
When I connect with this user, I get this:
usage: shutdown [-] [-h | -p | -r | -k] [-o [-n]] time [warning-message ...]
poweroff
The connection is then closed by the server.

It's a kinda like a wrong argument has been passed but without a warning such as: "poweroff: illegal option..."
 
Setting up poweroff as the shell isn't going to work due to the required parameters.

Why not install security/sudo, then configure Sudo to allow this user to run 1 elevated commands: shutdown -p now, and you're done.

Then the user can log on, and start this command using sudo, but nothing else. So if he would try and use -r to reboot the system then sudo would deny this because the command would no longer match.

I think this is your safest option. No need for chrooted environments or anything.
 
Problem with sudo is that it still defines the user as a "regular user" with a regular shell. If the only possible function of that user is poweroff then forcing the poweroff command upon login is the safest option, from a security standpoint.

I just verified that the /etc/passwd file will take a properly written sh script as a shell itself. I implemented the shutdown user as:

in /home/shutdown:
Code:
$ cat > poweroff
#! /bin/sh
/sbin/shutdown -p now
chmod 700 /home/shutdown/poweroff
sudo vipw
set /home/shutdown/poweroff as the shell of the shutdown user.

make sure shutdown user is in operator group.
 
Problem with sudo is that it still defines the user as a "regular user" with a regular shell. If the only possible function of that user is poweroff then forcing the poweroff command upon login is the safest option, from a security standpoint.
Not exactly true.

Because if your systems security is already threatened by a regular user logging on then you have bigger issues to address. Sure: I'm well aware of several local root exploits from the past, which basically always form a risk of some sort. Still, even those can often be prevented in some ways.

And from a security perspective I can say that your solution is even worse. Because if someone does log on remotely; what's to stop them from pressing control-c at the right time and thus forcing a fallback onto the shell?
 
Not exactly true.

Because if your systems security is already threatened by a regular user logging on then you have bigger issues to address. Sure: I'm well aware of several local root exploits from the past, which basically always form a risk of some sort. Still, even those can often be prevented in some ways.

And from a security perspective I can say that your solution is even worse. Because if someone does log on remotely; what's to stop them from pressing control-c at the right time and thus forcing a fallback onto the shell?


Once you let a user in and give them a shell, that is a much larger security hole than an automatic command execution as a consequence of logging in. Let's see, gimme a shell and I can probably compile code, check system status to look for insecure daemons or directories, possibly screw with device files if their permissions are not correct...

and regarding ^C breakout of the user shell, which is the head of their process group, I don't believe so. If you disagree then I'd love to see a demonstration using the current freeBSD RELEASE.

In the end, the op will do what they want. My way was the standard on the UNIX servers at all the LARGE shops I worked at. Yours attempts to herd the barbarians once they are already in the castle.

Anyway, I've said what I know. I won't argue the point anymore, but would love to see your shell breakout demonstration, of a properly hardenned shell script run as the default /etc/passwd shell.
 
I just verified that the /etc/passwd file will take a properly written sh script as a shell itself. I implemented the shutdown user as:

in /home/shutdown:
Code:
$ cat > poweroff
#! /bin/sh
/sbin/shutdown -p now
chmod 700 /home/shutdown/poweroff
sudo vipw
set /home/shutdown/poweroff as the shell of the shutdown user.

make sure shutdown user is in operator group.
It just perfectly works and it's more than I expected when I posted this question.

Funny enough, yesterday, I though to include poweroff in a script to workaround this "bad option" but I said to myself: impossible to make a shell from a script. Sometimes, one create its own prison...

However, questions on the utility to chroot a user remains (need to copy in his/her home dir all the commands he/she needs?).

I understand the security point that ShelLuser mentions, even if I tried Ctrl-C in vain. But if one stops the poweroff command before execution, what is the shell used after?

Here, the very important thing is indeed that this user cannot login and thus stroll among the files.

Thanks to both of you for taking time to answer. :)
 
Once you let a user in and give them a shell, that is a much larger security hole than an automatic command execution as a consequence of logging in. Let's see, gimme a shell and I can probably compile code, check system status to look for insecure daemons or directories, possibly screw with device files if their permissions are not correct...
Not on FreeBSD. That is; not per definition.

Take for example security.bsd.see_other_uids, security.bsd.unprivileged_read_msgbuf and there's a whole lot more where that came from. The easiest / best being: kern.securelevel. See also security(7). At level 1 most device files get blocked on the kernel level, file permissions no longer matter. At level 2 this will even include storage devices.

Compiling code is fun. How are you going to execute it though? On my setup /tmp, /var/tmp and /home all have noexec set. And those are the only places where a regular user has write permissions.

Now... don't get me wrong here. You're absolutely right when you say that allowing a user to log on can enhance the risks. But there are also dozens of ways (sometimes very easy) which can limit all that.

For me security starts with paranoia. Which means: don't put all your money on a single 'solution'. You're also assuming that while /sbin/shutdown is active with the shutdown a user can't sent it any more input...

Anyway... you're right about discussing, we'd hijack the thread and that's not the idea behind this.
 
Last thing: I just understood why poweroff answered "Not super-user" despite the fact that it works for operator group.

This poweroff file was copied from /rescue/ because the executables are there statically linked. In /sbin/ they need differents libs so they can't work in a chrooted directory.

I glanced at the shutdown code and noticed:

Code:
if (geteuid())
        errx(1, "NOT super-user");


One man page later, I eventually understood that /rescue/poweroff just needed the setuid permission, given the owner is root... :oops:
 
There are more ways of doing this but I'd say using sshd to chroot user is actually a good idea. Now you don't even need shell in that chrooted environment for it to work. Long story short all binary files in /rescue are actually one binary and it's the name of the binary (argv[0]) that determines what to do.
You could write a small wrapper in C:

C:
#include <stdio.h>
#include <unistd.h>

#define POWEROFF        "/halt"

int main(void) {
        char* args[] = { POWEROFF, "halt", NULL };
        execve(*args, args, NULL);

        fprintf(stderr, "oops: failed to execute %s\n", *args);
        return 1;
}

Compile it, set the proper ownership/permissions and copy the halt from rescue:
clang -static -o powerdown powerdown.c
chown root:pc powerdown && chmod 4750 powerdown
cp -p /rescue/halt /pc


With the following configuration:
/etc/ssh/sshd_config
Code:
Match User pc
    ChrootDirectory /pc/

/etc/passwd
Code:
pc:*:1002:1002:User &:/pc:/powerdown

This way chroot /pc needs to have only two files and doesn't require to have sh at all. And of course one could ask why not to write a small C program to shut the system down. ;-)
 
I think all of this setup with a chroot etc is a bit overkill. If the user only connects via SSH then you could also create ~/.ssh/authorized_keys to restrict the user to only being able to run /sbin/shutdown -p now
Code:
restrict,command="/sbin/shutdown -p now" $public_key
Simply connecting to the host with ssh -i $private_key user@host will then shut it down and the user won't be able to do anything else. Of course this assumes that you have disabled password auth in SSH and are only using public key auth.

This approach is also extensible if you want the user to do other things later like e.g. rebooting.
 
There are more ways of doing this but I'd say using sshd to chroot user is actually a good idea. Now you don't even need shell in that chrooted environment for it to work. Long story short all binary files in /rescue are actually one binary and it's the name of the binary (argv[0]) that determines what to do.
You could write a small wrapper in C:

It' an interesting variation on the theme: use an executable instead of a script. The script works well or, at least, it seems. You showed me that one can use this "shell" technique and keep a chrooted user without need of sh in its home directory. From a security point of view, I feel that this is better.

It appears to me that there is a problem in your code. What you wrote doesn't shut off the system but halt it. The first argument you give, "halt" (args[1]) is useless and must be replaced by "-p" if you want that the server really goes off.
C:
#include <stdio.h>
#include <unistd.h>

#define POWEROFF        "/halt"

int main(void) {
        char* args[] = { POWEROFF, "-p", NULL };
        execve(*args, args, NULL);

        fprintf(stderr, "oops: failed to execute %s\n", *args);
        return 1;
}

I think all of this setup with a chroot etc is a bit overkill. If the user only connects via SSH then you could also create ~/.ssh/authorized_keys to restrict the user to only being able to run /sbin/shutdown -p now
To me, that seems more complicated than to chroot an user. I don't want to deactivate authentication by password. Partly because I'm not at all accustomed to use keys. Where can I find some documentation on ~/.ssh/authorized_keys?
 
Given enough thought, every problem will degenerate to its most complicated form.
 
It' an interesting variation on the theme: use an executable instead of a script. The script works well or, at least, it seems. You showed me that one can use this "shell" technique and keep a chrooted user without need of sh in its home directory. From a security point of view, I feel that this is better.

It appears to me that there is a problem in your code. What you wrote doesn't shut off the system but halt it. The first argument you give, "halt" (args[1]) is useless and must be replaced by "-p" if you want that the server really goes off.
C:
#include <stdio.h>
#include <unistd.h>

#define POWEROFF        "/halt"

int main(void) {
        char* args[] = { POWEROFF, "-p", NULL };
        execve(*args, args, NULL);

        fprintf(stderr, "oops: failed to execute %s\n", *args);
        return 1;
}


To me, that seems more complicated than to chroot an user. I don't want to deactivate authentication by password. Partly because I'm not at all accustomed to use keys. Where can I find some documentation on ~/.ssh/authorized_keys?
It's documented in detail in sshd(8) and the handbook has a brief section on SSH key management too: https://www.freebsd.org/doc/handbook/openssh.html#security-ssh-keygen
 
Emrion Right, but you got the idea. It's easy to change the args to whatever you need.

Sometimes you do want to chroot the users (e.g. sftp users), sometimes it's easier to use tobik@'s approach. There's always more ways to skin a cat ;)
 
Back
Top