From cace22d6fb4682ed4f32e6c082acb2e64f23cbc8 Mon Sep 17 00:00:00 2001 From: neargle <7868679+neargle@users.noreply.github.com> Date: Sun, 31 Jul 2022 14:32:28 +0800 Subject: [PATCH] feat(evaluate): output all mount info and more colorfu (#64) * feat(evaluate): output all mount info and more colorful Co-authored-by: QiQi * perf(mount): string function with format major:minor root mountPoint opts - Fstype device SuperBlockOptions Co-authored-by: neargle Co-authored-by: QiQi --- pkg/evaluate/check_mount_escape.go | 76 +++++++++++------------------- pkg/util/cgroup.go | 10 +++- 2 files changed, 37 insertions(+), 49 deletions(-) diff --git a/pkg/evaluate/check_mount_escape.go b/pkg/evaluate/check_mount_escape.go index acc744c..070522d 100644 --- a/pkg/evaluate/check_mount_escape.go +++ b/pkg/evaluate/check_mount_escape.go @@ -1,4 +1,3 @@ - /* Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK . @@ -18,23 +17,14 @@ limitations under the License. package evaluate import ( - "bufio" "fmt" - "github.com/cdk-team/CDK/pkg/errors" "io" - "log" - "os" "regexp" "strings" - "syscall" -) -type Mount struct { - Device string - Path string - Filesystem string - Flags string -} + "github.com/cdk-team/CDK/pkg/errors" + "github.com/cdk-team/CDK/pkg/util" +) // The checkClose function calls close on a Closer and panics with a // runtime error if the Closer returns an error @@ -44,48 +34,38 @@ func checkClose(c io.Closer) { } } -func GetMounts() ([]Mount, error) { - readPath := "/proc/self/mounts" - file, err := os.Open(readPath) - if err != nil { - log.Printf("[Err] Open %s failed.", readPath) - return nil, err - } - defer checkClose(file) - mounts := []Mount(nil) - reader := bufio.NewReaderSize(file, 64*1024) - for { - line, isPrefix, err := reader.ReadLine() - if err != nil { - if err == io.EOF { - return mounts, nil - } - return nil, err - } - if isPrefix { - return nil, syscall.EIO - } - parts := strings.SplitN(string(line), " ", 5) - if len(parts) != 5 { - return nil, syscall.EIO - } - mounts = append(mounts, Mount{parts[0], parts[1], parts[2], parts[3]}) - } -} func MountEscape() { - mounts, _ := GetMounts() + + mounts, _ := util.GetMountInfo() for _, m := range mounts { - if strings.Contains(m.Device, "/") || strings.Contains(m.Filesystem, "ext") { - matched, _ := regexp.MatchString("/kubelet/|/dev/[\\w-]*?\\blog$|/etc/host[\\w]*?$|/etc/[\\w]*?\\.conf$", m.Path) + + // TODO: why so may null byte in the Mounts + // [Information Gathering - Mounts] + // : - + if m.Major == "" { + continue + } + + + // ? why match those mount points? + if strings.Contains(m.Device, "/") || strings.Contains(m.Fstype, "ext") { + matched, _ := regexp.MatchString("/kubelet/|/dev/[\\w-]*?\\blog$|/etc/host[\\w]*?$|/etc/[\\w]*?\\.conf$", m.Root) if !matched { - fmt.Printf("Device:%s Path:%s Filesystem:%s Flags:%s\n", m.Device, m.Path, m.Filesystem, m.Flags) + m.Root = util.RedBold.Sprint(m.Root) + m.Fstype = util.RedBold.Sprint(m.Fstype) } } - if m.Device == "lxcfs" && strings.Contains(m.Flags,"rw"){ - fmt.Println("Find mounted lxcfs with rw flags, run `cdk run lxcfs-rw` or `cdk run lxcfs-rw-cgroup` to escape container!") - fmt.Printf("Device:%s Path:%s Filesystem:%s Flags:%s\n", m.Device, m.Path, m.Filesystem, m.Flags) + + // find lxcfs mount point for escape exploit + if m.Device == "lxcfs" && util.StringContains(m.Opts, "rw"){ + fmt.Printf("Find mounted lxcfs with rw flags, run `%s` or `%s` to escape container!\n", util.RedBold.Sprint("cdk run lxcfs-rw"), util.RedBold.Sprint("cdk run lxcfs-rw-cgroup")) + m.Device = util.RedBold.Sprint(m.Device) + m.MountPoint = util.RedBold.Sprint(m.Device) } + + fmt.Println(m.String()) + } } diff --git a/pkg/util/cgroup.go b/pkg/util/cgroup.go index 733e2ac..e9c0801 100644 --- a/pkg/util/cgroup.go +++ b/pkg/util/cgroup.go @@ -36,7 +36,8 @@ const cgroupInfoPath string = "/proc/self/cgroup" // MountInfo // Sample: 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue // Sample2: 1659 1605 253:1 /var/lib/kubelet/pods/cc76265f-d44d-4624-91c8-6f6812f85c7e/etc-hosts /etc/hosts rw,noatime - ext4 /dev/vda1 rw -// format: mountID parentID major:minor root mountPoint opts fstype +// Sample3: 52 36 0:47 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:26 - cgroup cgroup rw,memory +// format: mountID parentID major:minor root mountPoint opts - Fstype device SuperBlockOptions type MountInfo struct { Device string Fstype string @@ -48,6 +49,13 @@ type MountInfo struct { SuperBlockOptions []string } +// String format: major:minor root mountPoint opts - Fstype device SuperBlockOptions +func (mi MountInfo) String() string { + optStr := strings.Join(mi.Opts, ",") + superBlockOptionsStr := strings.Join(mi.SuperBlockOptions, ",") + return fmt.Sprintf("%s:%s %s %s %s - %s %s %s", mi.Major, mi.Minor, mi.Root, mi.MountPoint, optStr, mi.Fstype, mi.Device, superBlockOptionsStr) +} + // find block device id func FindTargetDeviceID(mi *MountInfo) bool { if mi.MountPoint == hostDeviceFlag {