From 3cfa8ba30115c6d5aec7a5b3194519a3d1fdd7a2 Mon Sep 17 00:00:00 2001 From: Sukchan Lee Date: Sat, 13 Apr 2024 13:22:19 +0900 Subject: [PATCH] [AMF/MME] NAS message in an invaild state (#3131) In InitialUEMessage, send a NAS message with a message type other than Registration Request, Deregistration Request, or Service Request, the following messages from UE will not be accepted. We found this issue in not only the initial state but multiple states. We believe if an attacker has the ability to inject a NAS message to the core, it can perform a DoS attack on the victim UE. So, I've fixed that The MME/AMF deletes MME_UE_S1AP_ID/AMF_UE_NGAP_ID, and will not accept any following messages from the UE. --- src/amf/ngap-path.c | 31 +++++++++++++++++++++++++++ src/mme/s1ap-handler.c | 12 ++++------- src/mme/s1ap-path.c | 34 ++++++++++++++++++++++++++++++ tests/attach/issues-test.c | 4 ++++ tests/registration/identity-test.c | 4 ++++ 5 files changed, 77 insertions(+), 8 deletions(-) diff --git a/src/amf/ngap-path.c b/src/amf/ngap-path.c index b7094a053..0c3488d24 100644 --- a/src/amf/ngap-path.c +++ b/src/amf/ngap-path.c @@ -200,6 +200,7 @@ int ngap_send_to_nas(ran_ue_t *ran_ue, default: ogs_error("Not implemented(security header type:0x%x)", sh->security_header_type); + ran_ue_remove(ran_ue); return OGS_ERROR; } @@ -207,12 +208,39 @@ int ngap_send_to_nas(ran_ue_t *ran_ue, if (nas_5gs_security_decode(ran_ue->amf_ue, security_header_type, nasbuf) != OGS_OK) { ogs_error("nas_eps_security_decode failed()"); + ran_ue_remove(ran_ue); return OGS_ERROR; } } h = (ogs_nas_5gmm_header_t *)nasbuf->data; ogs_assert(h); + if (procedureCode == NGAP_ProcedureCode_id_InitialUEMessage) { + if (h->extended_protocol_discriminator != + OGS_NAS_EXTENDED_PROTOCOL_DISCRIMINATOR_5GMM) { + + ogs_error("Invalid extended_protocol_discriminator [%d]", + h->extended_protocol_discriminator); + + ogs_pkbuf_free(nasbuf); + ran_ue_remove(ran_ue); + + return OGS_ERROR; + } + + if (h->message_type != OGS_NAS_5GS_REGISTRATION_REQUEST && + h->message_type != OGS_NAS_5GS_SERVICE_REQUEST && + h->message_type != OGS_NAS_5GS_DEREGISTRATION_REQUEST_FROM_UE) { + + ogs_error("Invalid 5GMM message type [%d]", h->message_type); + + ogs_pkbuf_free(nasbuf); + ran_ue_remove(ran_ue); + + return OGS_ERROR; + } + } + if (h->extended_protocol_discriminator == OGS_NAS_EXTENDED_PROTOCOL_DISCRIMINATOR_5GMM) { e = amf_event_new(AMF_EVENT_5GMM_MESSAGE); @@ -247,7 +275,10 @@ int ngap_send_to_nas(ran_ue_t *ran_ue, } else { ogs_error("Unknown NAS Protocol discriminator 0x%02x", h->extended_protocol_discriminator); + ogs_pkbuf_free(nasbuf); + ran_ue_remove(ran_ue); + return OGS_ERROR; } } diff --git a/src/mme/s1ap-handler.c b/src/mme/s1ap-handler.c index 8f2147563..dff401ded 100644 --- a/src/mme/s1ap-handler.c +++ b/src/mme/s1ap-handler.c @@ -586,10 +586,8 @@ void s1ap_handle_initial_ue_message(mme_enb_t *enb, ogs_s1ap_message_t *message) enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id, enb_ue->saved.tai.tac, enb_ue->saved.e_cgi.cell_id); - r = s1ap_send_to_nas(enb_ue, - S1AP_ProcedureCode_id_initialUEMessage, NAS_PDU); - ogs_expect(r == OGS_OK); - ogs_assert(r != OGS_ERROR); + ogs_expect(OGS_OK == s1ap_send_to_nas( + enb_ue, S1AP_ProcedureCode_id_initialUEMessage, NAS_PDU)); } void s1ap_handle_uplink_nas_transport( @@ -777,10 +775,8 @@ void s1ap_handle_uplink_nas_transport( ogs_error("No UE Context in UplinkNASTransport"); } - r = s1ap_send_to_nas(enb_ue, - S1AP_ProcedureCode_id_uplinkNASTransport, NAS_PDU); - ogs_expect(r == OGS_OK); - ogs_assert(r != OGS_ERROR); + ogs_expect(OGS_OK == s1ap_send_to_nas( + enb_ue, S1AP_ProcedureCode_id_uplinkNASTransport, NAS_PDU)); } void s1ap_handle_ue_capability_info_indication( diff --git a/src/mme/s1ap-path.c b/src/mme/s1ap-path.c index 2123aad17..c47bb5e37 100644 --- a/src/mme/s1ap-path.c +++ b/src/mme/s1ap-path.c @@ -207,6 +207,7 @@ int s1ap_send_to_nas(enb_ue_t *enb_ue, default: ogs_error("Not implemented(security header type:0x%x)", sh->security_header_type); + enb_ue_remove(enb_ue); return OGS_ERROR; } @@ -214,12 +215,42 @@ int s1ap_send_to_nas(enb_ue_t *enb_ue, if (nas_eps_security_decode(enb_ue->mme_ue, security_header_type, nasbuf) != OGS_OK) { ogs_error("nas_eps_security_decode failed()"); + enb_ue_remove(enb_ue); return OGS_ERROR; } } h = (ogs_nas_emm_header_t *)nasbuf->data; ogs_assert(h); + + if (procedureCode == S1AP_ProcedureCode_id_initialUEMessage) { + if (h->protocol_discriminator != OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM) { + + ogs_error("Invalid protocol_discriminator [%d]", + h->protocol_discriminator); + + ogs_pkbuf_free(nasbuf); + enb_ue_remove(enb_ue); + + return OGS_ERROR; + } + + if (h->security_header_type != + OGS_NAS_SECURITY_HEADER_FOR_SERVICE_REQUEST_MESSAGE && + h->message_type != OGS_NAS_EPS_ATTACH_REQUEST && + h->message_type != OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST && + h->message_type != OGS_NAS_EPS_EXTENDED_SERVICE_REQUEST && + h->message_type != OGS_NAS_EPS_DETACH_REQUEST) { + + ogs_error("Invalid EMM message type [%d]", h->message_type); + + ogs_pkbuf_free(nasbuf); + enb_ue_remove(enb_ue); + + return OGS_ERROR; + } + } + if (h->protocol_discriminator == OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM) { int rv; e = mme_event_new(MME_EVENT_EMM_MESSAGE); @@ -255,7 +286,10 @@ int s1ap_send_to_nas(enb_ue_t *enb_ue, } else { ogs_error("Unknown/Unimplemented NAS Protocol discriminator 0x%02x", h->protocol_discriminator); + ogs_pkbuf_free(nasbuf); + enb_ue_remove(enb_ue); + return OGS_ERROR; } } diff --git a/tests/attach/issues-test.c b/tests/attach/issues-test.c index b1fd2fd42..316737a17 100644 --- a/tests/attach/issues-test.c +++ b/tests/attach/issues-test.c @@ -1862,6 +1862,7 @@ static void issues_2287_v264_func(abts_case *tc, void *data) test_ue_remove_all(); } +#if 0 /* Deprecated to resolve issue #3131 */ static void pull_3122_v270_func(abts_case *tc, void *data) { int rv; @@ -1973,6 +1974,7 @@ static void pull_3122_v270_func(abts_case *tc, void *data) test_ue_remove(test_ue); } +#endif abts_suite *test_issues(abts_suite *suite) { @@ -1981,7 +1983,9 @@ abts_suite *test_issues(abts_suite *suite) abts_run_test(suite, issues_1431_func, NULL); abts_run_test(suite, issues_2287_v263_func, NULL); abts_run_test(suite, issues_2287_v264_func, NULL); +#if 0 /* Deprecated to resolve issue #3131 */ abts_run_test(suite, pull_3122_v270_func, NULL); +#endif return suite; } diff --git a/tests/registration/identity-test.c b/tests/registration/identity-test.c index 17fd9ac53..e80bb5836 100644 --- a/tests/registration/identity-test.c +++ b/tests/registration/identity-test.c @@ -354,6 +354,7 @@ static void test1_func(abts_case *tc, void *data) test_ue_remove(test_ue); } +#if 0 /* Deprecated to resolve issue #3131 */ static void pull_3122_v270_func(abts_case *tc, void *data) { int rv; @@ -469,13 +470,16 @@ static void pull_3122_v270_func(abts_case *tc, void *data) /* Clear Test UE Context */ test_ue_remove(test_ue); } +#endif abts_suite *test_identity(abts_suite *suite) { suite = ADD_SUITE(suite) abts_run_test(suite, test1_func, NULL); +#if 0 /* Deprecated to resolve issue #3131 */ abts_run_test(suite, pull_3122_v270_func, NULL); +#endif return suite; }