在你的 Linux 机器上”安全的”给别人开一个终端

这是我的需求:

折腾一圈下来真的太累了。

0x00 一切是怎么实现的?

我们可以从 sshd_config 的 man page 里发现 ChrootDirectory 这个设置项:

The ChrootDirectory must contain the necessary files and directo ries to support the user’s session. For an interactive session this requires at least a shell, typically sh(1), and basic /dev nodes such as null(4), zero(4), stdin(4), stdout(4), stderr(4), arandom(4) and tty(4) devices. For file transfer sessions using “sftp”, no additional configuration of the environment is necessary if the in-process sftp server is used, though sessions which use logging do require /dev/log inside the chroot directory.

简言之,通过创建一个 SSH chroot “监狱”,你可以给你不信任的用户 ssh 权限,并且可以限制他能运行的命令(例如 ls、date 和 bash 的内置命令)。

这篇教程是在 Debian 10 + OpenSSH 环境下作为例子的。

0x01 切换成 root 用户

尝试以下命令:

$ sudo -s
$ # 或者更干脆
$ su -

0x02 创建 chroot “监狱”

在这里,我创建一个目录叫做 /home/sshjail 作为该用户连接至的根目录:

# mkdir -p /home/sshjail

然后根据 sshd 的 man page 所说,你还需要这些必须的文件:

# ls -l /dev/{null,zero,stdin,stdout,stderr,random,tty}

在终端里的输出是类似这样的:

crw-rw-rw- 1 root root 1, 3 May 25 22:26 /dev/null
crw-rw-rw- 1 root root 1, 8 May 25 22:26 /dev/random
lrwxrwxrwx 1 root root   15 May 25 22:26 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx 1 root root   15 May 25 22:26 /dev/stdin -> /proc/self/fd/0
lrwxrwxrwx 1 root root   15 May 25 22:26 /dev/stdout -> /proc/self/fd/1
crw-rw-rw- 1 root tty  5, 0 May 26 00:28 /dev/tty
crw-rw-rw- 1 root root 1, 5 May 25 22:26 /dev/zero

为了创建相同的文件,我们需要使用 mknod 命令:

# mkdir -p /home/sshjail/dev/
# mknod -m 666 /home/sshjail/dev/null c 1 3
# mknod -m 666 /home/sshjail/dev/tty c 5 0
# mknod -m 666 /home/sshjail/dev/zero c 1 5
# mknod -m 666 /home/sshjail/dev/random c 1 8

0x03 设置权限

因为 ChrootDirectory 规定,上级目录的拥有者必须是 root,并且不能被任何人写:

# chown root:root /home/sshjail
# chmod 0755 /home/sshjail

你可以使用以下命令来验证是否正确:

# ls -ld /home/sshjail

在终端里的输出是类似这样的:

drwxr-xr-x 9 root root 4096 May 25 23:31 /home/sshjail

0x04 给一个 bash 终端

Nice,接下来我们需要一个终端,让用户可以运行我们想让他运行的命令。

首先,创建 /bin 目录:

# mkdir -p /home/sshjail/bin

然后复制 /bin/bash 到我们创建的 /bin 目录:

# cp -v /bin/bash /home/sshjail/bin

这里,-v 指的是 verbose,做了什么都输出出来

在终端里的输出是类似于这样的:

‘/bin/bash’ -> ‘/home/sshjail/bin/bash’

之后,我们还需要将 bash 使用的共享库一并复制进去,否则 bash 无法运行:

# ldd /bin/bash

在终端里的输出是类似于这样的:

        linux-vdso.so.1 (0x00007ffc9b5ea000)
        libtinfo.so.6 => /lib/x86_64-linux-gnu/libtinfo.so.6 (0x00007f6571ea9000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f6571ea4000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6571ce3000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f657200f000)

如果你的输出和我的略有出入,这是正常的现象。请仿照我使用的命令来完成,不要直接复制我的命令。

哈!现在我们知道要复制什么了,那就开工吧:

# mkdir -p /home/sshjail/lib/
# mkdir -p /home/sshjail/lib64/
# mkdir -p /home/sshjail/lib/x86_64-linux-gnu/
# cp -v /lib/x86_64-linux-gnu/{libtinfo.so.6,libdl.so.2,libc.so.6} /home/sshjail/lib/x86_64-linux-gnu/

在终端里的输出是类似于这样的:

‘/lib/x86_64-linux-gnu/libtinfo.so.6’ -> ‘/home/sshjail/lib/libtinfo.so.6’
‘/lib/x86_64-linux-gnu/libdl.so.2’ -> ‘/home/sshjail/lib/libdl.so.2’
‘/lib/x86_64-linux-gnu/libc.so.6’ -> ‘/home/sshjail/lib/libc.so.6’

我们还有一个 ld-linux-x86-64.so.2 也需要复制过来:

# cp -v /lib64/ld-linux-x86-64.so.2 /home/sshjail/lib64/

在终端里的输出是类似于这样的:

‘/lib64/ld-linux-x86-64.so.2’ -> ‘/home/sshjail/lib64/ld-linux-x86-64.so.2’

最后,复制 /lib/x86_64-linux-gnu/libnss_files*

# cp -va /lib/x86_64-linux-gnu/libnss_files* /home/sshjail/lib/x86_64-linux-gnu/

在终端里的输出是类似于这样的:

 '/lib/x86_64-linux-gnu/libnss_files-2.28.so' -> '/home/sshjail/lib/x86_64-linux-gnu/libnss_files-2.28.so'
'/lib/x86_64-linux-gnu/libnss_files.so.2' -> '/home/sshjail/lib/x86_64-linux-gnu/libnss_files.so.2'

0x05 添加用户

万事俱备,只欠用户。首先,我们要创建一名用户,在这里,你也可以创建多名用户:

# adduser andy

然后,我们要将 /etc/{passwd,group} 复制到我们的”监狱”里。

# mkdir -p /home/sshjail/etc/
# cp -vf /etc/{passwd,group} /home/sshjail/etc/

在终端里的输出是类似于这样的:

‘/etc/passwd’ -> ‘/home/sshjail/etc/passwd’
‘/etc/group’ -> ‘/home/sshjail/etc/group’

注意!如果你后面对用户或者用户的密码做了任何更改,都请重新复制这两个文件。

0x06 设置 sshd

编辑 /etc/ssh/sshd_config,我们要设置登录相关的东西了:

# nano /etc/ssh/sshd_config

在文件最后输入这些:

##  Apply the chrooted jail to the user called andy ##
Match User andy
ChrootDirectory /home/sshjail
## Allow sftp to chrooted jail ##
ForceCommand internal-sftp

如果是多名用户的话,那么第一行应该改成这样:

Match User andy,antis,goblin

0x07 重启 sshd 服务

这个很简单吧!

# systemctl restart sshd

0x08 测试 & 给用户必要的目录

接下来,登入你之前设置的账号吧!可以发现,我们的确有了一个 bash,但我们连 ls 和 date 这种命令都运行不了,只能运行 pwd 之类的内置命令。不慌,我们还要做进一步的调整。

在此之前,我们可以发现在测试时,终端提醒我们没有家目录。先给用户家目录吧:

# mkdir -p /home/sshjail/home/andy
# chown -R andy:andy /home/sshjail/home/andy/
# chmod -R 0700 /home/sshjail/home/andy/

然后,我们需要给用户他的网站目录,让他可以查看和编辑。我们还要保证在重启之后,这个目录会被自动挂载上(因为第一句话是手动挂载):

# mkdir /home/sshjail/home/andy/web
# mount --bind /home/wwwroot/andy_web /home/sshjail/home/andy/web
# echo "/home/wwwroot/andy_web /home/sshjail/home/andy/web none bind" >> /etc/fstab

至于目录的权限,我是给了 andy:www,然后把 www 添加进了 andy 用户组以备不时之需,静态网站是够了的。

0x09 安装其它的命令

首先,是不需要任何共享库的:

# cp -v /bin/ls /home/sshjail/bin/
# cp -v /bin/date /home/sshjail/bin/
# cp -v /bin/cp /home/sshjail/bin/
# cp -v /bin/mv /home/sshjail/bin/

直接复制过去就好了。如果是需要共享库的,那么首先使用 ldd 命令查看一下,再复制就好了。以下是我自己的环境所需要的东西的折腾过程:

xterm

可以发现,此时使用左右键(上下键可能有用)或者 Backspace 键的话,是无法正常执行我们的操作的。

如果你现在也安装了 nano 的话,你可以发现 nano 会报 Error opening terminal: Xterm 的错误。解决方法也很简单:

# mkdir -p /home/sshjail/usr/share/terminfo
# cp -r -v /usr/share/terminfo /home/sshjail/usr/share/
# cp -r -v /lib/terminfo /home/sshjail/lib/

i18n 问题

虽然英文能正常显示,但是中文是不能正常显示和输入的。这该怎么办呢?我想,大概是因为缺少了 locales 包吧。万幸的是,运行 locale 命令发现本身已经是 en_US.UTF-8 了。

# cp -v /usr/bin/locale /home/sshjail/usr/bin/
# cp -r -v /usr/share/i18n /home/sshjail/usr/share
# cp -r -v /usr/lib/locale /home/sshjail/usr/lib/
# cp -v /etc/default/locale /home/sshjail/etc/default

提示:如果知道包名,但不知道要复制哪些文件,可以去 pks.org 去看一看。例如 Debian 10 上 locales 这个包,在这个网站上可以显示包内有什么文件,这样你就知道要手动复制什么文件了。

不能用 SCP 协议上传下载文件

现在我们弄好了中文显示和 xterm,但不能用 SFTP。不过在此之前,我们可以先试试 SCP 协议!SCP 协议虽然能看目录,但是不能上传下载文件。解决方法也很简单:

# cp -v /usr/bin/scp /home/sshjail/usr/bin

SFTP 协议不能用

蛤,我 SSH 都起来了。一看,原来是缺少 openssh 相关的库。

# cp -v /usr/lib/sftp-server /home/sshjail/usr/lib/
# cp -r -v /usr/lib/openssh/ /home/sshjail/usr/lib/

tar 和 zip

tar 的安装很简单:

# cp -v /bin/tar /home/sshjail/bin

万一用户要用其它的打包算法呢:

# cp -v /bin/gzip /home/sshjail/bin
# cp -v /bin/bzip2 /home/sshjail/bin
# cp -v /lib/x86_64-linux-gnu/libbz2.so.1.0 /home/sshjail/lib/x86_64-linux-gnu
# cp -v /usr/bin/xz /home/sshjail/usr/bin
# cp -v /lib/x86_64-linux-gnu/liblzma.so.5 /home/sshjail/lib/x86_64-linux-gnu

zip 的安装也很简单:

# cp -v /usr/bin/zip /home/sshjail/usr/bin/
# cp -v /usr/bin/unzip /home/sshjail/usr/bin/

其它

失败的 locale 相关

# mkdir -p /home/sshjail/usr/sbin
# cp -v /usr/sbin/locale-gen /home/sshjail/usr/sbin
## locale-gen 还需要这些东西
# cp -v /bin/sh /home/sshjail/bin/
# cp -v /bin/sed /home/sshjail/bin/
# cp -v /bin/rm /home/sshjail/bin/
# cp -v /usr/bin/localedef /home/sshjail/usr/bin/

结果好像还是没运行起来?我也忘了运行结果了。

# cp -v /usr/sbin/update-locale /home/sshjail/usr/sbin
# # 草,这个东西要 perl
# cp -v /usr/bin/perl /home/sshjail/usr/bin/
# cp -r -v /usr/lib/x86_64-linux-gnu/perl /home/sshjail/usr/lib/x86_64-linux-gnu/perl
# cp -r -v /usr/share/perl /home/sshjail/usr/share
# cp -v /lib/x86_64-linux-gnu/libm.so.6 /home/sshjail/lib/x86_64-linux-gnu/
# cp -v /lib/x86_64-linux-gnu/libcrypt.so.1 /home/sshjail/lib/x86_64-linux-gnu/
# # 但其实还是不行,它需要 sudo,即使我们复制 sudo 过去还是不能直接用的

sudo 相关

# cp -v /usr/bin/sudo /home/sshjail/usr/bin/
# cp -r -v /usr/lib/sudo /home/sshjail/usr/lib/
# cp -v /lib/x86_64-linux-gnu/libaudit.so.1 /home/sshjail/lib/x86_64-linux-gnu/
# cp -v /lib/x86_64-linux-gnu/libutil.so.1 /home/sshjail/lib/x86_64-linux-gnu/
# cp -v /lib/x86_64-linux-gnu/libcap-ng.so.0 /home/sshjail/lib/x86_64-linux-gnu/

参考文献


如果喜欢本文,欢迎点击下方的「鼓掌」按钮!

如果上面没有加载出任何东西,可以点击这里


如果喜欢本文,欢迎点击下方的「鼓掌」按钮!

如果上面没有加载出任何东西,可以点击这里