CVE-2023-49786 (C, published 2023-12-14T20:15Z)
Description: value: Asterisk is an open source private branch exchange and telephony toolkit. In Asterisk prior to versions 18.20.1, 20.5.1, and 21.0.1; as well as certified-asterisk prior to 18.9-cert6; Asterisk is susceptible to a DoS due to a race condition in the hello handshake phase of the DTLS protocol when handling DTLS-SRTP for media setup. This attack can be done continuously, thus denying new DTLS-SRTP encrypted calls during the attack. Abuse of this vulnerability may lead to a massive Denial of Service on vulnerable Asterisk servers for calls that rely on DTLS-SRTP. Commit d7d7764cb07c8a1872804321302ef93bf62cba05 contains a fix, which is part of versions 18.20.1, 20.5.1, 21.0.1, amd 18.9-cert6.
Severity: nan (CVSS v3 base score: 5.9)
Weakness: CWE-362 \u2014 Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')
The product contains a code sequence that can run concurrently with other code, and the code sequence requires temporary, exclusive access to a shared resource, but a timing window exists in which the shared resource can be modified by another code sequence that is operating concurrently.
Repository: https://github.com/asterisk/asterisk
Files changed:
res/res_rtp_asterisk.c
Commit message: res_rtp_asterisk.c: Check DTLS packets against ICE candidate list

When ICE is in use, we can prevent a possible DOS attack by allowing
DTLS protocol messages (client hello, etc) only from sources that
are in the active remote candidates list.

Resolves: GHSA-hxj9-xwr8-w8pq


Vulnerable code:

Fixed code:
		/*
		 * If ICE is in use, we can prevent a possible DOS attack
		 * by allowing DTLS protocol messages (client hello, etc)
		 * only from sources that are in the active remote
		 * candidates list.
		 */

		if (rtp->ice) {
			int pass_src_check = 0;
			struct ao2_iterator i;
			struct ast_rtp_engine_ice_candidate *candidate;
			int cand_cnt = 0;

			/*
			 * You'd think that this check would cause a "deadlock"
			 * because ast_rtp_ice_start_media calls dtls_perform_handshake
			 * before it sets ice_media_started = 1 so how can we do a
			 * handshake if we're dropping packets before we send them
			 * to openssl.  Fortunately, dtls_perform_handshake just sets
			 * up openssl to do the handshake and doesn't actually perform it
			 * itself and the locking prevents __rtp_recvfrom from
			 * running before the ice_media_started flag is set.  So only
			 * unexpected DTLS packets can get dropped here.
			 */
			if (!rtp->ice_media_started) {
				ast_log(LOG_WARNING, "%s: DTLS packet from %s dropped. ICE not completed yet.\n",
					ast_rtp_instance_get_channel_id(instance),
					ast_sockaddr_stringify(sa));
				return 0;
			}

			/*
			 * If we got this far, then ice_active_remote_candidates
			 * can't be NULL.
			 */
			i = ao2_iterator_init(rtp->ice_active_remote_candidates, 0);
			while ((candidate = ao2_iterator_next(&i)) && (cand_cnt < PJ_ICE_MAX_CAND)) {
				res = ast_sockaddr_cmp_addr(&candidate->address, sa);
				ao2_ref(candidate, -1);
				if (res == 0) {
					pass_src_check = 1;
					break;
				}
				cand_cnt++;
			}
			ao2_iterator_destroy(&i);

			if (!pass_src_check) {
				ast_log(LOG_WARNING, "%s: DTLS packet from %s dropped. Source not in ICE active candidate list.\n",
					ast_rtp_instance_get_channel_id(instance),
					ast_sockaddr_stringify(sa));
				return 0;
			}
		}