Skip to content

DoS vulnerability in Revel framework #1424

@SYM01

Description

@SYM01

Once the slices parameter feature is used, the website will be suffering from DoS attack.

When we need to get a slice parameter, we may use the following code snippet in our controller.

func (c App) DoS1(name []string) revel.Result {
	return c.RenderText(fmt.Sprint(name))
}

func (c App) DoS2() revel.Result {
	var name []string
	c.Params.Bind(&name, "name")
	return c.RenderText(fmt.Sprint(name))
}

It looks like everything is OK. However, we can exhaust the server's MEM with only one request.
e.g., when simply visit http://localhost:9000/dos1?name[1234567890]=1, the server's CPU and memory usage will soar, and the OOM killer will be triggered eventually.

This vulnerability was caused by the following code:

revel/binder.go

Lines 210 to 277 in a3d7a7c

func bindSlice(params *Params, name string, typ reflect.Type) reflect.Value {
// Collect an array of slice elements with their indexes (and the max index).
maxIndex := -1
numNoIndex := 0
sliceValues := []sliceValue{}
// Factor out the common slice logic (between form values and files).
processElement := func(key string, vals []string, files []*multipart.FileHeader) {
if !strings.HasPrefix(key, name+"[") {
return
}
// Extract the index, and the index where a sub-key starts. (e.g. field[0].subkey)
index := -1
leftBracket, rightBracket := len(name), strings.Index(key[len(name):], "]")+len(name)
if rightBracket > leftBracket+1 {
index, _ = strconv.Atoi(key[leftBracket+1 : rightBracket])
}
subKeyIndex := rightBracket + 1
// Handle the indexed case.
if index > -1 {
if index > maxIndex {
maxIndex = index
}
sliceValues = append(sliceValues, sliceValue{
index: index,
value: Bind(params, key[:subKeyIndex], typ.Elem()),
})
return
}
// It's an un-indexed element. (e.g. element[])
numNoIndex += len(vals) + len(files)
for _, val := range vals {
// Unindexed values can only be direct-bound.
sliceValues = append(sliceValues, sliceValue{
index: -1,
value: BindValue(val, typ.Elem()),
})
}
for _, fileHeader := range files {
sliceValues = append(sliceValues, sliceValue{
index: -1,
value: BindFile(fileHeader, typ.Elem()),
})
}
}
for key, vals := range params.Values {
processElement(key, vals, nil)
}
for key, fileHeaders := range params.Files {
processElement(key, nil, fileHeaders)
}
resultArray := reflect.MakeSlice(typ, maxIndex+1, maxIndex+1+numNoIndex)
for _, sv := range sliceValues {
if sv.index != -1 {
resultArray.Index(sv.index).Set(sv.value)
} else {
resultArray = reflect.Append(resultArray, sv.value)
}
}
return resultArray
}

When the function above is invoked, Revel will calc the maxIndex from user's input, and thus the attacker could make the maxIndex as large as possible. When reflect.MakeSlice is called, Golang will alloc a large memory as the maxIndex needed.

A possible solution for this vuln is to specify the upper bound of the maxIndex in the code or config file.

Before the problem is fixed, plz avoid using the slices parameter feature.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions