peirates

package module
v1.1.17 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 30, 2024 License: GPL-2.0 Imports: 36 Imported by: 1

README

Peirates

Release gosec

Logo

What is Peirates?

Peirates, a Kubernetes penetration tool, enables an attacker to escalate privilege and pivot through a Kubernetes cluster. It automates known techniques to steal and collect service account tokens, secrets, obtain further code execution, and gain control of the cluster.

Where do I run Peirates?

You run Peirates from a container running on Kubernetes or from a Kubernetes node, outside the container.

Does Peirates attack a Kubernetes cluster?

Yes, it absolutely does. Talk to your lawyer and the cluster owners before using this tool in a Kubernetes cluster.

Who creates Peirates?

InGuardians' CTO Jay Beale first conceived of Peirates and put together a group of InGuardians developers to create it with him, including Faith Alderson, Adam Crompton and Dave Mayer. Faith convinced us to all learn Golang, so she could implement the tool's use of the kubectl library from the Kubernetes project. Adam persuaded the group to use a highly-interactive user interface. Dave brought contagious enthusiasm. Together, these four developers implemented attacks and began releasing this tool that we use on our penetration tests.

Other contributors have helped as well - see GitHub to see more, but please also review credits.md.

Do you welcome contributions?

Yes, we absolutely do. Submit a pull request and/or reach out to peirates-dev@inguardians.com.

What license is this released under?

Peirates is released under the GPLv2 license.

Running Peirates

If you just want the peirates binary to start attacking things, grab the latest release from the releases page.

Peirates as a Container Image

You can find a useful alpine-peirates container image on Docker Hub, with a version number tag that tracks the Peirates version.

For example, for alpine-peirates:1.1.16, which contains peirates version 1.1.16, run:

docker pull bustakube/alpine-peirates:1.1.16

Building Peirates

However, if you want to build from source, read on!

Get peirates

go get -v "github.com/inguardians/peirates"

Get libary sources if you haven't already (Warning: this will take almost a gig of space because it needs the whole kubernetes repository)

go get -v "k8s.io/kubectl/pkg/cmd" "github.com/aws/aws-sdk-go"

Build the executable

cd $GOPATH/github.com/inguardians/peirates/scripts
./build.sh

This will generate an executable file named peirates in the same directory.

Documentation

Overview

commandline.go contains logic and data structures relevant to actually running peirates as a command line tool. Mainly this is just flag handling.

Index

Constants

View Source
const ServiceAccountPath = "/var/run/secrets/kubernetes.io/serviceaccount/"

Variables

View Source
var UseAuthCanI bool = true

If this option is on, kubectl commands will be preceded with an auth can-i check. Note that this only checks against RBAC, such that admission controllers can still block an action that RBAC permits.

View Source
var Verbose bool

Verbosity mode - if set to true, DEBUG messages will be printed to STDOUT.

Functions

func AddNewSecretFromPodViaNodeFS added in v1.1.9

func AddNewSecretFromPodViaNodeFS(secretName, secretPath, podName string, secretsFromPodsViaNodeFS *[]SecretFromPodViaNodeFS) bool

AddNewSecretFromPodViaNodeFS adds a new service account to the existing slice, but only if the the new one is unique Return whether one was added - if it wasn't, it's a duplicate.

func AddNewServiceAccount added in v1.1.5

func AddNewServiceAccount(name, token, discoveryMethod string, serviceAccountList *[]ServiceAccount) bool

AddNewServiceAccount adds a new service account to the existing slice, but only if the the new one is unique Return whether one was added - if it wasn't, it's a duplicate.

func DisplayAWSIAMCredentials

func DisplayAWSIAMCredentials(IAMCredentials AWSCredentials)

DisplayAWSIAMCredentials prints the IAM credentials gathered out to stdout.

func DoHTTPRequestAndGetBody

func DoHTTPRequestAndGetBody(req *http.Request, https bool, ignoreTLSErrors bool, caCertPath string) ([]byte, error)

DoHTTPRequestAndGetBody performs an HTTP request, and returns the full body of the reponse as a string. If ignoreTLSErrors is true, all TLS errors, such as invalid certificates, will be ignored. If caCertPath is not an empty string, a TLS certificate will be read from the provided path and added to the pool of valid certificates.

func DoKubernetesAPIRequest

func DoKubernetesAPIRequest(cfg ServerInfo, httpVerb, apiPath string, query interface{}, response interface{}) error

DoKubernetesAPIRequest makes an API request to a kubernetes API server, using the connection parameters and authentication from the provided ServerInfo. It marshals the provided query structure to JSON, and unmarshalls the response JSON to the response structure pointer. For an example of usage, see kubectlAuthCanI.

func ExecKubectlAndExit added in v1.0.30

func ExecKubectlAndExit()

ExecKubectlAndExit runs the internally compiled `kubectl` code as if this was the `kubectl` binary. stdin/stdout/stderr are process streams. args are process args.

func ExecuteCodeOnKubelet

func ExecuteCodeOnKubelet(connectionString ServerInfo, serviceAccounts *[]ServiceAccount)

ExecuteCodeOnKubelet runs a command on every pod on every node via their Kubelets.

func GetAWSRegionAndZone added in v1.0.31

func GetAWSRegionAndZone() (region string, zone string, err error)

func GetGCPBearerTokenFromMetadataAPI

func GetGCPBearerTokenFromMetadataAPI(account string) (string, time.Time, error)

GetGCPBearerTokenFromMetadataAPI takes the name of a GCP service account and returns a token, a time it will expire and an error

func GetMyIPAddress added in v1.1.13

func GetMyIPAddress(interfaceName string) (string, error)

func GetMyIPAddressesNative added in v1.0.29

func GetMyIPAddressesNative() []string

GetMyIPAddressesNative gets a list of IP addresses available via Golang's Net library

func GetNamespaces added in v1.0.32

func GetNamespaces(connectionString ServerInfo) ([]string, error)

GetNamespaces returns the list of active namespaces, using kubectl get namespaces

func GetNodesInfo

func GetNodesInfo(connectionString ServerInfo)

GetNodesInfo runs kubectl get nodes -o json.

func GetPodsInfo

func GetPodsInfo(connectionString ServerInfo, podDetails *PodDetails)

GetPodsInfo gets details for all pods in json output and stores in PodDetails struct

func GetRequest

func GetRequest(url string, headers []HeaderLine, ignoreTLSErrors bool) (string, int)

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 GetRoles

func GetRoles(connectionString ServerInfo, kubeRoles *KubeRoles)

GetRoles enumerates all roles in use on the cluster (in the default namespace). It parses all roles into a KubeRoles object.

func KopsAttackAWS added in v1.0.33

func KopsAttackAWS(serviceAccounts *[]ServiceAccount) (err error)

func KopsAttackGCP added in v1.0.33

func KopsAttackGCP(serviceAccounts *[]ServiceAccount) (err error)

func ListAWSBuckets added in v1.0.31

func ListAWSBuckets(IAMCredentials AWSCredentials) (bucketNamesList []string, err error)

ListBuckets lists the buckets accessible from this IAM account.

func ListBucketObjects

func ListBucketObjects(IAMCredentials AWSCredentials, bucket string) error

ListBucketObjects lists the objects in a specific bucket

func Main added in v1.0.30

func Main()

Main starts Peirates

func MountRootFS

func MountRootFS(allPodsListme []string, connectionString ServerInfo, callbackIP, callbackPort string)

MountRootFS creates a pod that mounts its node's root filesystem.

func PrintHostMountPoints

func PrintHostMountPoints(podInfo PodDetails)

PrintHostMountPoints prints all pods' host volume mounts parsed from the Spec.Volumes pod spec by GetPodsInfo()

func PrintHostMountPointsForPod

func PrintHostMountPointsForPod(podInfo PodDetails, pod string)

PrintHostMountPointsForPod prints a single pod's host volume mounts parsed from the Spec.Volumes pod spec by GetPodsInfo()

func ReadLine added in v1.0.33

func ReadLine() (string, error)

readLine reads up through the next \n from stdin. The returned string does not include the \n.

func ReadLineStripWhitespace added in v1.0.33

func ReadLineStripWhitespace() (string, error)

func Request

func Request(path string, cfgs ...func(*RequestConfig)) string

Request takes a path such as "/pod" and requests it from an HTTP server, returning the full response body as a string.

Functions may be optionally passed in to modify the default configuration. The default configuration is:

RequestConfig {
    Host: "127.0.0.1",
    Port: 6443,          // The default Kubernetes port
    Method: "GET",
    Https: true,
    IgnoreHttpsErrors: true,
}

For example:

func RequestSimple(path string, host string, port int) string {
    // This passes a function literal (also known as a lambda or anonymous function)
    // to RequestPath to configure the host and port.
    return Request(path, func (cfg *RequestConfig) {
        cfg.Host = host
        cfg.Port = port
    })
}

func RequestSimple

func RequestSimple(path string, host string, port int) string

func StartS3Session

func StartS3Session(IAMCredentials AWSCredentials) *s3.S3

StartS3Session creates a session with S3 using AWS Credentials.

Types

type AWSCredentials

type AWSCredentials struct {

	// InstanceProfileArn  string
	// If we parse this, we can freshen this only as necessary
	// Expiration			string `json:"Expiration"`
	AccessKeyId     string `json:"AccessKeyId"`
	SecretAccessKey string `json:"SecretAccessKey"`
	SessionToken    string `json:"Token"`
	// contains filtered or unexported fields
}

AWSCredentials stores the credentials

func AWSSTSAssumeRole added in v1.0.31

func AWSSTSAssumeRole(IAMCredentials AWSCredentials, roleToAssumeArn string) (AssumedCredentials AWSCredentials, err error)

func EnterIamCredentialsForAWS added in v1.0.31

func EnterIamCredentialsForAWS() (AWSCredentials, error)

func PullIamCredentialsFromAWS

func PullIamCredentialsFromAWS() (AWSCredentials, error)

PullIamCredentialsFromAWS requests access credentials from the AWS metadata API

func PullIamCredentialsFromEnvironmentVariables added in v1.0.31

func PullIamCredentialsFromEnvironmentVariables() AWSCredentials

type AWSS3BucketObject added in v1.0.31

type AWSS3BucketObject struct {
	Data string `json:"Data"`
}

type ClientCertificateKeyPair added in v1.0.36

type ClientCertificateKeyPair struct {
	Name string // Client cert-key pair name
	// ClientKeyPath         string // Client key file path
	// ClientCertificatePath string // Client cert file path
	ClientKeyData         string // Client key data
	ClientCertificateData string // Client cert data
	APIServer             string // URL like https://10.96.0.1:443
	CACert                string // Content of a CA cert
}

ClientCertificateKeyPair stores certificate and key information for one principal.

func MakeClientCertificateKeyPair added in v1.0.36

func MakeClientCertificateKeyPair(name, clientCertificateData, clientKeyData, APIServer, CACert string) ClientCertificateKeyPair

type CloudProvider added in v1.1.13

type CloudProvider struct {
	Name              string
	URL               string
	HTTPMethod        string
	CustomHeader      string
	CustomHeaderValue string
	ResultString      string
}

type CommandLineOptions

type CommandLineOptions struct {
	// contains filtered or unexported fields
}

type GCPToken added in v1.0.35

type GCPToken struct {
	Token          string `json:"access_token"`
	Expires        int64  `json:"expires_in"`
	ExpirationTime time.Time
	Type           string `json:"token_type"`
}

Tokens returned by the metadata API will look like this, unless error has occurred: {"access_token":"xxxxxxx","expires_in":2511,"token_type":"Bearer"}

type GetNodeDetails added in v1.0.30

type GetNodeDetails struct {
	Items []struct {
		Metadata struct {
			Name string `json:"name"`
		} `json:"metadata"`
		Status struct {
			Addresses []struct {
				Address string `json:"address"`
				Type    string `json:"type"`
			} `json:"addresses"`
		} `json:"status"`
	} `json:"items"`
}

GetNodeDetails unmarshalls node data

type HeaderLine

type HeaderLine struct {
	LHS string
	RHS string
}

HeaderLine contains the left hand side (header name) and right hand side (header value) of an HTTP header.

type KubeRoles

type KubeRoles struct {
	APIVersion string `json:"apiVersion"`
	Items      []struct {
		APIVersion string `json:"apiVersion"`
		Kind       string `json:"kind"`
		Metadata   struct {
			Annotations struct {
				KubectlKubernetesIoLastAppliedConfiguration string `json:"kubectl.kubernetes.io/last-applied-configuration"`
			} `json:"annotations"`
			CreationTimestamp time.Time `json:"creationTimestamp"`
			Name              string    `json:"name"`
			Namespace         string    `json:"namespace"`
			ResourceVersion   string    `json:"resourceVersion"`
			SelfLink          string    `json:"selfLink"`
			UID               string    `json:"uid"`
		} `json:"metadata"`
		Rules []struct {
			APIGroups []string `json:"apiGroups"`
			Resources []string `json:"resources"`
			Verbs     []string `json:"verbs"`
		} `json:"rules"`
	} `json:"items"`
	Kind     string `json:"kind"`
	Metadata struct {
		ResourceVersion string `json:"resourceVersion"`
		SelfLink        string `json:"selfLink"`
	} `json:"metadata"`
}

KubeRoles are used for JSON parsing

type MountInfo

type MountInfo struct {
	// contains filtered or unexported fields
}

MountInfo is used by mountRootfs

type PodDetails

type PodDetails struct {
	APIVersion string `json:"apiVersion"`
	Items      []struct {
		APIVersion string `json:"apiVersion"`
		Kind       string `json:"kind"`
		Metadata   struct {
			Annotations struct {
				KubectlKubernetesIoLastAppliedConfiguration string `json:"kubectl.kubernetes.io/last-applied-configuration"`
			} `json:"annotations"`
			CreationTimestamp time.Time `json:"creationTimestamp"`
			Labels            struct {
				App string `json:"app"`
			} `json:"labels"`
			Name            string `json:"name"`
			Namespace       string `json:"namespace"`
			ResourceVersion string `json:"resourceVersion"`
			SelfLink        string `json:"selfLink"`
			UID             string `json:"uid"`
		} `json:"metadata"`
		Spec struct {
			Containers []struct {
				Image           string `json:"image"`
				ImagePullPolicy string `json:"imagePullPolicy"`
				Name            string `json:"name"`
				Ports           []struct {
					ContainerPort int    `json:"containerPort"`
					Protocol      string `json:"protocol"`
				} `json:"ports"`
				Resources struct {
				} `json:"resources"`
				TerminationMessagePath   string `json:"terminationMessagePath"`
				TerminationMessagePolicy string `json:"terminationMessagePolicy"`
				VolumeMounts             []struct {
					MountPath string `json:"mountPath"`
					Name      string `json:"name"`
					ReadOnly  bool   `json:"readOnly"`
				} `json:"volumeMounts"`
			} `json:"containers"`
			DNSPolicy    string `json:"dnsPolicy"`
			NodeName     string `json:"nodeName"`
			NodeSelector struct {
				KubernetesIoHostname string `json:"kubernetes.io/hostname"`
			} `json:"nodeSelector"`
			RestartPolicy   string `json:"restartPolicy"`
			SchedulerName   string `json:"schedulerName"`
			SecurityContext struct {
			} `json:"securityContext"`
			ServiceAccount                string `json:"serviceAccount"`
			ServiceAccountName            string `json:"serviceAccountName"`
			TerminationGracePeriodSeconds int    `json:"terminationGracePeriodSeconds"`
			Tolerations                   []struct {
				Effect            string `json:"effect"`
				Key               string `json:"key"`
				Operator          string `json:"operator"`
				TolerationSeconds int    `json:"tolerationSeconds"`
			} `json:"tolerations"`
			Volumes []struct {
				HostPath struct {
					Path string `json:"path"`
					Type string `json:"type"`
				} `json:"hostPath,omitempty"`
				Name   string `json:"name"`
				Secret struct {
					DefaultMode int    `json:"defaultMode"`
					SecretName  string `json:"secretName"`
				} `json:"secret,omitempty"`
			} `json:"volumes"`
		} `json:"spec"`
		Status struct {
			Conditions []struct {
				LastProbeTime      interface{} `json:"lastProbeTime"`
				LastTransitionTime time.Time   `json:"lastTransitionTime"`
				Status             string      `json:"status"`
				Type               string      `json:"type"`
			} `json:"conditions"`
			ContainerStatuses []struct {
				ContainerID string `json:"containerID"`
				Image       string `json:"image"`
				ImageID     string `json:"imageID"`
				LastState   struct {
					Terminated struct {
						ContainerID string    `json:"containerID"`
						ExitCode    int       `json:"exitCode"`
						FinishedAt  time.Time `json:"finishedAt"`
						Reason      string    `json:"reason"`
						StartedAt   time.Time `json:"startedAt"`
					} `json:"terminated"`
				} `json:"lastState"`
				Name         string `json:"name"`
				Ready        bool   `json:"ready"`
				RestartCount int    `json:"restartCount"`
				State        struct {
					Running *struct {
						StartedAt time.Time `json:"startedAt"`
					} `json:"running"`
				} `json:"state"`
			} `json:"containerStatuses"`
			HostIP    string    `json:"hostIP"`
			Phase     string    `json:"phase"`
			PodIP     string    `json:"podIP"`
			QosClass  string    `json:"qosClass"`
			StartTime time.Time `json:"startTime"`
		} `json:"status"`
	} `json:"items"`
	Kind     string `json:"kind"`
	Metadata struct {
		ResourceVersion string `json:"resourceVersion"`
		SelfLink        string `json:"selfLink"`
	} `json:"metadata"`
}

PodDetails is populated by GetPodsInfo (JSON parsing from kubectl get pods)

type PodNamespaceContainerTuple

type PodNamespaceContainerTuple struct {
	PodName       string
	PodNamespace  string
	ContainerName string
}

type RequestConfig

type RequestConfig struct {
	Host              string
	Port              int
	Method            string
	Https             bool
	IgnoreHttpsErrors bool
}

type SecretDetails added in v1.0.30

type SecretDetails struct {
	Data []struct {
		Namespace string `json:"namespace"`
		Token     string `json:"token"`
	}
	Metadata struct {
		Name string `json:"name"`
	}
	SecretType string `json:"type"`
}

SecretDetails unmarshalls secrets

type SecretFromPodViaNodeFS added in v1.1.9

type SecretFromPodViaNodeFS struct {
	DiscoveryTime   time.Time // Time the secret was found on the node's filesystem.
	DiscoveryMethod string
	// contains filtered or unexported fields
}

type ServerInfo

type ServerInfo struct {
	APIServer      string // URL for the API server - this replaces RIPAddress and RPort
	Token          string // service account token ASCII text, if present
	TokenName      string // name of the service account token, if present
	ClientCertData string // client certificate, if present
	ClientKeyData  string // client key, if present
	ClientCertName string // name of the client cert, if present
	CAPath         string // path to Certificate Authority's certificate (public key)
	Namespace      string // namespace that this pod's service account is tied to
	UseAuthCanI    bool
}

func ImportPodServiceAccountToken added in v1.1.9

func ImportPodServiceAccountToken() ServerInfo

type ServiceAccount

type ServiceAccount struct {
	Name            string    // Service account name
	Token           string    // Service account token
	DiscoveryTime   time.Time // Time the service account was discovered
	DiscoveryMethod string    // How the service account was discovered (file on disk, secrets, user input, etc.)
}

ServiceAccount stores service account information.

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL