CVE-2023-28095 (published 2023-03-15T22:15Z)

OpenSIPS is a Session Initiation Protocol (SIP) server implementation. Versions prior to 3.1.7 and 3.2.4 have a potential issue in `msg_translator.c:2628` which might lead to a server crash. This issue was found while fuzzing the function `build_res_buf_from_sip_req` but could not be reproduced against a running instance of OpenSIPS. This issue could not be exploited against a running instance of OpenSIPS since no public function was found to make use of this vulnerable code. Even in the case of exploitation through unknown vectors, it is highly unlikely that this issue would lead to anything other than Denial of Service. This issue has been fixed in versions 3.1.7 and 3.2.4.

CVSS v3 base score: 7.5, HIGH (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)

Weakness information:
cwe_id: NVD-CWE-noinfo
cwe_name: Insufficient Information
description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/OpenSIPS/opensips
commit_details: repo_url: https://github.com/OpenSIPS/opensips
author: Bogdan-Andrei Iancu
author_date: 2021-11-08 10:16:54+02:00
msg: [core] build_res_buf_from_sip_req(): fix hdr correlation

Issue discovered during OpenSIPS Security Audit 2021,
        by Alfred Farrugia & Sandro Gauci (Enable Security)

https://github.com/OpenSIPS/opensips/security/advisories/GHSA-7pf3-24qg-8v9h
repository: repo_url: https://github.com/OpenSIPS/opensips
repo_name: OpenSIPS/opensips
description: OpenSIPS is a GPL implementation of a multi-functionality SIP Server that targets to deliver a high-level technical solution (performance, security and quality) to be used in professional SIP server platforms.
repo_language: C
owner: OpenSIPS
file_changes: filename: msg_translator.c
change_type: ModificationType.MODIFY
diff: @@ -134,9 +134,6 @@ int disable_503_translation = 0;
 		(_dest) += (_len) ;\
 	}while(0);
 
-#define append_str_trans(_dest,_src,_len,_msg) \
-	append_str( (_dest), (_src), (_len) );
-
 extern char version[];
 extern int version_len;
 
@@ -2489,39 +2486,40 @@ char * build_res_buf_from_sip_req( unsigned int code, const str *text ,str *new_
 	/* first line */
 	len += SIP_VERSION_LEN + 1/*space*/ + 3/*code*/ + 1/*space*/ +
 		text->len + CRLF_LEN/*new line*/;
-	/*headers that will be copied (TO, FROM, CSEQ,CALLID,VIA)*/
-	for ( hdr=msg->headers ; hdr ; hdr=hdr->next ) {
-		switch (hdr->type) {
-			case HDR_TO_T:
-				if (new_tag && new_tag->len) {
-					to_tag=get_to(msg)->tag_value;
-					if (to_tag.len )
-						len+=new_tag->len-to_tag.len;
-					else
-						len+=new_tag->len+TOTAG_TOKEN_LEN/*";tag="*/;
-				}
-				len += hdr->len;
-				break;
-			case HDR_VIA_T:
-				/* we always add CRLF to via*/
-				len+=(hdr->body.s+hdr->body.len)-hdr->name.s+CRLF_LEN;
-				if (hdr==msg->h_via1) len += received_len+rport_len;
-				break;
-			case HDR_RECORDROUTE_T:
-				/* RR only for 1xx and 2xx replies */
-				if (code<180 || code>=300)
-					break;
-			case HDR_FROM_T:
-			case HDR_CALLID_T:
-			case HDR_CSEQ_T:
-				/* we keep the original termination for these headers*/
-				len += hdr->len;
-				break;
-			default:
-				/* do nothing, we are interested only in the above headers */
-				;
+	/* copy the TO hdr */
+	if (msg->to) {
+		if (new_tag && new_tag->len) {
+			to_tag=get_to(msg)->tag_value;
+			if (to_tag.len )
+				len+=new_tag->len-to_tag.len;
+			else
+				len+=new_tag->len+TOTAG_TOKEN_LEN/*";tag="*/;
 		}
-	}
+		len += msg->to->len;
+	}
+
+	/* copy all VIA hdrs */
+	for( hdr=msg->h_via1 ; hdr ; hdr=hdr->sibling) {
+		/* we always add CRLF to via*/
+		len+=(hdr->body.s+hdr->body.len)-hdr->name.s+CRLF_LEN;
+		if (hdr==msg->h_via1) len += received_len+rport_len;
+	}
+	/* copy all Record-Route hdrs */
+	for( hdr=msg->record_route ; hdr ; hdr=hdr->sibling) {
+		/* RR only for 1xx and 2xx replies */
+		if (code>=180 && code<300)
+			len += hdr->len;
+	}
+	/* copy the FROM hdr */
+	if (msg->from)
+		len += msg->from->len;
+	/* copy the CALLID hdr */
+	if (msg->callid)
+		len += msg->callid->len;
+	/* copy the CSEQ hdr */
+	if (msg->cseq)
+		len += msg->cseq->len;
+
 	/* lumps length */
 	for(lump=msg->reply_lump;lump;lump=lump->next) {
 		len += lump->text.len;
@@ -2570,100 +2568,103 @@ char * build_res_buf_from_sip_req( unsigned int code, const str *text ,str *new_
 	p += text->len;
 	memcpy( p, CRLF, CRLF_LEN );
 	p+=CRLF_LEN;
-	/* headers*/
-	for ( hdr=msg->headers ; hdr ; hdr=hdr->next ) {
-		switch (hdr->type)
-		{
-			case HDR_VIA_T:
-				if (hdr==msg->h_via1){
-					i = 0;
-					if (received_buf) {
-						i = msg->via1->host.s - msg->via1->hdr.s +
-							msg->via1->host.len + (msg->via1->port?
-							msg->via1->port_str.len + 1 : 0);
-						/* copy via1 up to params */
-						append_str( p, hdr->name.s, i);
-						/* copy received param */
-						append_str( p, received_buf, received_len);
-					}
-					if (rport_buf){
-						if (msg->via1->rport){ /* delete the old one */
-							/* copy until rport */
-							append_str_trans( p, hdr->name.s+i ,
-								msg->via1->rport->start-hdr->name.s-1-i,msg);
-							/* copy new rport */
-							append_str(p, rport_buf, rport_len);
-							/* copy the rest of the via */
-							append_str_trans(p, msg->via1->rport->start+
-												msg->via1->rport->size,
-												hdr->body.s+hdr->body.len-
-												msg->via1->rport->start-
-												msg->via1->rport->size, msg);
-						}else{ /* just copy rport and rest of hdr */
-							append_str(p, rport_buf, rport_len);
-							append_str_trans( p, hdr->name.s+i ,
-								(hdr->body.s+hdr->body.len)-hdr->name.s-i,msg);
-						}
-					}else{
-						/* normal whole via copy */
-						append_str_trans( p, hdr->name.s+i ,
-							(hdr->body.s+hdr->body.len)-hdr->name.s-i, msg);
-					}
-				}else{
-					/* normal whole via copy */
-					append_str_trans( p, hdr->name.s,
-							(hdr->body.s+hdr->body.len)-hdr->name.s, msg);
-				}
-				append_str( p, CRLF,CRLF_LEN);
-				break;
-			case HDR_RECORDROUTE_T:
-				/* RR only for 1xx and 2xx replies */
-				if (code<180 || code>=300) break;
-				append_str(p, hdr->name.s, hdr->len);
-				break;
-			case HDR_TO_T:
-				if (new_tag && new_tag->len){
-					if (to_tag.len ) { /* replacement */
-						/* before to-tag */
-						append_str( p, hdr->name.s, to_tag.s-hdr->name.s);
-						/* to tag replacement */
-						bmark->to_tag_val.s=p;
-						bmark->to_tag_val.len=new_tag->len;
-						append_str( p, new_tag->s,new_tag->len);
-						/* the rest after to-tag */
-						append_str( p, to_tag.s+to_tag.len,
-							hdr->name.s+hdr->len-(to_tag.s+to_tag.len));
-					}else{ /* adding a new to-tag */
-						after_body=hdr->body.s+hdr->body.len;
-						append_str( p, hdr->name.s, after_body-hdr->name.s);
-						append_str(p, TOTAG_TOKEN, TOTAG_TOKEN_LEN);
-						bmark->to_tag_val.s=p;
-						bmark->to_tag_val.len=new_tag->len;
-						append_str( p, new_tag->s,new_tag->len);
-						append_str( p, after_body,
-										hdr->name.s+hdr->len-after_body);
-					}
-					break;
-				} /* no new to-tag -- proceed to 1:1 copying  */
-				totags=((struct to_body*)(hdr->parsed))->tag_value.s;
-				if (totags) {
-					bmark->to_tag_val.s=p+(totags-hdr->name.s);
-					bmark->to_tag_val.len=
-							((struct to_body*)(hdr->parsed))->tag_value.len;
-				} else {
-					bmark->to_tag_val.s = NULL;
-					bmark->to_tag_val.len = 0;
-				}
-			case HDR_FROM_T:
-			case HDR_CALLID_T:
-			case HDR_CSEQ_T:
-					append_str(p, hdr->name.s, hdr->len);
-					break;
-			default:
-				/* do nothing, we are interested only in the above headers */
-				;
-		} /* end switch */
-	} /* end for */
+	/* VIA headers */
+	if ( (hdr=msg->h_via1)!=NULL ) {
+		/* handle the VIA1, subject to changes */
+		i = 0;
+		if (received_buf) {
+			i = msg->via1->host.s - msg->via1->hdr.s +
+				msg->via1->host.len + (msg->via1->port?
+				msg->via1->port_str.len + 1 : 0);
+			/* copy via1 up to params */
+			append_str( p, hdr->name.s, i);
+			/* copy received param */
+			append_str( p, received_buf, received_len);
+		}
+		if (rport_buf){
+			if (msg->via1->rport){ /* delete the old one */
+				/* copy until rport */
+				append_str( p, hdr->name.s+i ,
+					msg->via1->rport->start-hdr->name.s-1-i);
+				/* copy new rport */
+				append_str(p, rport_buf, rport_len);
+				/* copy the rest of the via */
+				append_str(p, msg->via1->rport->start+
+									msg->via1->rport->size,
+									hdr->body.s+hdr->body.len-
+									msg->via1->rport->start-
+									msg->via1->rport->size);
+			}else{ /* just copy rport and rest of hdr */
+				append_str(p, rport_buf, rport_len);
+				append_str( p, hdr->name.s+i ,
+					(hdr->body.s+hdr->body.len)-hdr->name.s-i);
+			}
+		}else{
+			/* normal whole via copy */
+			append_str( p, hdr->name.s+i ,
+				(hdr->body.s+hdr->body.len)-hdr->name.s-i);
+		}
+		append_str( p, CRLF,CRLF_LEN);
+		/* and now the rest of the VIA hdrs */
+		for( hdr=hdr->sibling ; hdr ; hdr=hdr->sibling) {
+			/* normal whole via copy */
+			append_str( p, hdr->name.s,
+					(hdr->body.s+hdr->body.len)-hdr->name.s);
+			append_str( p, CRLF,CRLF_LEN);
+		}
+	}
+	/* Record-Route headers */
+	for( hdr=msg->record_route ; hdr ; hdr=hdr->sibling) {
+		/* RR only for 1xx and 2xx replies */
+		if (code>=180 && code<300)
+			append_str(p, hdr->name.s, hdr->len);
+	}
+	/* TO hdr */
+	if ( (hdr=msg->to)!=NULL ) {
+		if (new_tag && new_tag->len){
+			if (to_tag.len ) { /* replacement */
+				/* before to-tag */
+				append_str( p, hdr->name.s, to_tag.s-hdr->name.s);
+				/* to tag replacement */
+				bmark->to_tag_val.s=p;
+				bmark->to_tag_val.len=new_tag->len;
+				append_str( p, new_tag->s,new_tag->len);
+				/* the rest after to-tag */
+				append_str( p, to_tag.s+to_tag.len,
+					hdr->name.s+hdr->len-(to_tag.s+to_tag.len));
+			}else{ /* adding a new to-tag */
+				after_body=hdr->body.s+hdr->body.len;
+				append_str( p, hdr->name.s, after_body-hdr->name.s);
+				append_str(p, TOTAG_TOKEN, TOTAG_TOKEN_LEN);
+				bmark->to_tag_val.s=p;
+				bmark->to_tag_val.len=new_tag->len;
+				append_str( p, new_tag->s,new_tag->len);
+				append_str( p, after_body,
+								hdr->name.s+hdr->len-after_body);
+			}
+		} else {
+			/* no new to-tag -- proceed to 1:1 copying  */
+			totags=((struct to_body*)(hdr->parsed))->tag_value.s;
+			if (totags) {
+				bmark->to_tag_val.s=p+(totags-hdr->name.s);
+				bmark->to_tag_val.len=
+					((struct to_body*)(hdr->parsed))->tag_value.len;
+			} else {
+				bmark->to_tag_val.s = NULL;
+				bmark->to_tag_val.len = 0;
+			}
+			append_str(p, hdr->name.s, hdr->len);
+		}
+	}
+	/* FROM header */
+	if (msg->from)
+		append_str(p, msg->from->name.s, msg->from->len);
+	/* CALLID header */
+	if (msg->callid)
+		append_str(p, msg->callid->name.s, msg->callid->len);
+	/* copy the CSEQ hdr */
+	if (msg->cseq)
+		append_str(p, msg->cseq->name.s, msg->cseq->len);
 	/* lumps */
 	for(lump=msg->reply_lump;lump;lump=lump->next)
 		if (lump->flags&LUMP_RPL_HDR){

programming_language: C++