CVE-2024-35190 (C, published 2024-05-17T17:15Z)
Description: value: Asterisk is an open source private branch exchange and telephony toolkit. After upgrade to 18.23.0, ALL unauthorized SIP requests are identified as PJSIP Endpoint of local asterisk server. This vulnerability is fixed in 18.23.1, 20.8.1, and 21.3.1.

Severity: nan (CVSS v3 base score: )
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/asterisk/asterisk
Files changed:
configs/samples/pjsip.conf.sample
contrib/ast-db-manage/config/versions/bd9c5159c7ea_revert_d5122576cca8_add_transport_.py
include/asterisk/res_pjsip.h
res/res_pjsip/pjsip_config.xml
res/res_pjsip/pjsip_configuration.c
res/res_pjsip_endpoint_identifier_ip.c
Commit message: Revert "res_pjsip_endpoint_identifier_ip: Add endpoint identifier transport address."

This reverts PR #602

Resolves: #GHSA-qqxj-v78h-hrf9


Vulnerable code:
;===============ENDPOINT IDENTIFIER TRANSPORT EXAMPLE==========================
;
; When Asterisk has multiple bound IP addresses, and endpoints don't use any
; other means of identification (e.g.: username), the transports' bind addresses
; can be used to identify them. Can be useful in case you're connecting to the
; same ITSP multiple times on different IPs / NICs.
;
;[transport-eth0]
;type=transport
;protocol=tcp
;bind=192.168.1.1:5060
;
;[transport-eth1]
;type=transport
;protocol=udp
;bind=192.168.2.1:5060
;
;
;[myprovider-a]
;type=endpoint
;transport=transport-eth0
;identify_by=transport
;
;[myprovider-b]
;type=endpoint
;transport=transport-eth1
;identify_by=transport
;
;
;[identify-a]
;type=identify
;endpoint=myprovider-a
;match=192.168.1.1:5060	; This is the bind address of [transport-eth0]
;;transport=tcp		; Optionally, this is the transport protocol of [transport-eth0]
;
;[identify-b]
;type=identify
;endpoint=myprovider-b
;match=192.168.2.1:5060	; This is the bind address of [transport-eth1]
;;transport=udp		; Optionally, This is the transport protocol of [transport-eth1]

                        ; "ip": Identify by the source (remote) IP address
                        ; "transport": Identify by the bound (local) IP address
            ; Currently, "ip", "header", "request_uri", "transport", "username",
            ; "auth_username" and "anonymous"  are valid identifiers as registered by
            ; the res_pjsip_endpoint_identifier_* modules.
            ; Some modules like res_pjsip_endpoint_identifier_user register
;match_request_uri= ; SIP request URI to match against (default: "")
;transport= ; Match ageinst the transport protocol (tcp or udp) (default: "")
	/*! Identify based on bound (local) IP address */
	AST_SIP_ENDPOINT_IDENTIFY_BY_TRANSPORT = (1 << 5),
							<enum name="transport">
								<para>Matches the endpoint based on the destination IP
								address.
								</para>
								<para>This method of identification is not configured here
								but simply allowed by this configuration option.
								</para>
							</enum>
	case AST_SIP_ENDPOINT_IDENTIFY_BY_TRANSPORT:
		str = "transport";
		break;
	} else if (!strcasecmp(str, "transport")) {
		method = AST_SIP_ENDPOINT_IDENTIFY_BY_TRANSPORT;
				<configOption name="transport">
					<synopsis>Match against a transport type.</synopsis>
					<description>
						<para>When using the ip or transport identifier, this option
						can be used to match the transport type <literal>(udp or tcp)
						</literal> as well.</para>
						<para>When omitted, or left empty, which is the default, it
						won't match against the transport type.</para>
					</description>
				</configOption>
		/*! The name of the transport type */
		AST_STRING_FIELD(transport);
/*! \brief Structure for a socket address with transport */
struct ast_sockaddr_with_tp {
	struct ast_sockaddr addr;
	char tp[128];
};

	struct ast_sockaddr_with_tp *addr_with_tp = arg;
	struct ast_sockaddr address = addr_with_tp->addr;
	sense = ast_apply_ha(identify->matches, &address);
		ast_debug(3, "Address %s matches identify '%s'\n",
				ast_sockaddr_stringify(&address),
				ast_sorcery_object_get_id(identify));
		if (ast_strlen_zero(identify->transport) || !strcasecmp(identify->transport, addr_with_tp->tp)) {
			ast_debug(3, "Transport %s matches identify '%s'\n",
				addr_with_tp->tp,
				ast_sorcery_object_get_id(identify));
			return CMP_MATCH;
		} else {
			ast_debug(3, "Transport %s match not matched identify '%s'\n",
				addr_with_tp->tp,
			return 0;
		}
		ast_debug(3, "Address %s does not match identify '%s'\n",
				ast_sockaddr_stringify(&address),
	struct ast_sockaddr_with_tp addr_with_tp = { { { 0, } }, };
	pj_ansi_strxcpy(addr_with_tp.tp, rdata->tp_info.transport->type_name, sizeof(addr_with_tp.tp));

	ast_sockaddr_parse(&addr_with_tp.addr, rdata->pkt_info.src_name, PARSE_PORT_FORBID);
	ast_sockaddr_set_port(&addr_with_tp.addr, rdata->pkt_info.src_port);

	return common_identify(ip_identify_match_check, &addr_with_tp);
}

static struct ast_sip_endpoint *transport_identify(pjsip_rx_data *rdata)
{
	char buffer[PJ_INET6_ADDRSTRLEN];
	pj_status_t status;
	struct ast_sockaddr_with_tp addr_with_tp = { { { 0, } }, };
	union pj_sockaddr sock = rdata->tp_info.transport->local_addr;

	pj_ansi_strxcpy(addr_with_tp.tp, rdata->tp_info.transport->type_name, sizeof(addr_with_tp.tp));

	if (sock.addr.sa_family == PJ_AF_INET6) {
		status = pj_inet_ntop(PJ_AF_INET6, &(sock.ipv6.sin6_addr), buffer, PJ_INET6_ADDRSTRLEN);
		if (status == PJ_SUCCESS && !strcmp(buffer, "::")) {
			ast_log(LOG_WARNING, "Matching against '::' may be unpredictable.\n");
		}
	} else {
		status = pj_inet_ntop(PJ_AF_INET, &(sock.ipv4.sin_addr), buffer, PJ_INET_ADDRSTRLEN);
		if (status == PJ_SUCCESS && !strcmp(buffer, "0.0.0.0")) {
			ast_log(LOG_WARNING, "Matching against '0.0.0.0' may be unpredictable.\n");
		}
	}
	if (status == PJ_SUCCESS) {
		ast_sockaddr_parse(&addr_with_tp.addr, buffer, PARSE_PORT_FORBID);
		ast_sockaddr_set_port(&addr_with_tp.addr, rdata->tp_info.transport->local_name.port);
		return common_identify(ip_identify_match_check, &addr_with_tp);
	} else {
		return NULL;
	}
static struct ast_sip_endpoint_identifier transport_identifier = {
	.identify_endpoint = transport_identify,
};

	if (!ast_strlen_zero(identify->transport)) {
		if (ast_string_field_set(identify, transport, identify->transport)) {
			return -1;
		}
	}

		if (!ast_strlen_zero(ident->transport)) {
			ast_str_append(&context->output_buffer, 0, "%*s: %s\n",
				indent,
				"Transport",
				ident->transport);
		}

	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ip_identify_match, transport));
	ast_sip_register_endpoint_identifier_with_name(&transport_identifier, "transport");
	ast_sip_unregister_endpoint_identifier(&transport_identifier);

Fixed code:
                        ; "ip": Identify by the source IP address
            ; Currently, "ip", "header", "username", "auth_username" and "anonymous"
            ; are valid identifiers as registered by the res_pjsip_endpoint_identifier_*
            ; modules.  Some modules like res_pjsip_endpoint_identifier_user register
"""Revert d5122576cca8 add transport attribute to identify

Revision ID: bd9c5159c7ea
Revises: 6c475a93f48a
Create Date: 2024-05-17 08:30:58.299083

"""

# revision identifiers, used by Alembic.
revision = 'bd9c5159c7ea'
down_revision = '6c475a93f48a'

from alembic import op
import sqlalchemy as sa


def upgrade():
    op.drop_column('ps_endpoint_id_ips', 'transport')


def downgrade():
    op.add_column('ps_endpoint_id_ips', sa.Column('transport', sa.String(128)))
	struct ast_sockaddr *addr = arg;
	sense = ast_apply_ha(identify->matches, addr);
		ast_debug(3, "Source address %s matches identify '%s'\n",
				ast_sockaddr_stringify(addr),
		return CMP_MATCH;
		ast_debug(3, "Source address %s does not match identify '%s'\n",
				ast_sockaddr_stringify(addr),
	struct ast_sockaddr addr = { { 0, } };
	ast_sockaddr_parse(&addr, rdata->pkt_info.src_name, PARSE_PORT_FORBID);
	ast_sockaddr_set_port(&addr, rdata->pkt_info.src_port);
	return common_identify(ip_identify_match_check, &addr);