Bug#395080: CVE-2006-5445: Denial of service in chan_sip

Ben Hutchings ben at decadent.org.uk
Sun Nov 19 01:29:35 CET 2006


The fix for CVE-2006-5445 in the 1.2 branch appears to be:
http://svn.digium.com/view/asterisk/branches/1.2/channels/chan_sip.c?r1=45306&r2=45380

There's no corresponding fix in the 1.0 branch.

Here's my attempt at backporting it.  This is untested, since I don't
run Asterisk myself.

The initialisation of the SIP context (sip_pvt) is a bit different in
1.0 and I've copied what looks like the corresponding code from
sip_alloc() into transmit_response_using_temp().  I added a call to
build_contact() because __send_response() indirectly uses the
our_contact member.

In 1.0 there's no validate commands before the call find_call() and
there's no sip_method array.  Therefore I wrote string comparisons
against all the commands that are allowed to create a new SIP context
based on the flags in the 1.2 code, minus "PUBLISH" because that isn't
supported at all (I'm not sure this is correct; we may end up sending
the wrong error message).

Ben.

--- asterisk-1.0.7.dfsg.1/channels/chan_sip.c.orig	2006-11-18 20:25:43.000000000 +0000
+++ asterisk-1.0.7.dfsg.1/channels/chan_sip.c	2006-11-18 23:22:41.000000000 +0000
@@ -557,6 +557,7 @@
 static struct ast_ha *localaddr;
 
 static struct ast_frame  *sip_read(struct ast_channel *ast);
+static int transmit_response_using_temp(char *callid, struct sockaddr_in *sin, int useglobal_nat, struct sip_request *req, char *msg);
 static int transmit_response(struct sip_pvt *p, char *msg, struct sip_request *req);
 static int transmit_response_with_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans);
 static int transmit_response_with_auth(struct sip_pvt *p, char *msg, struct sip_request *req, char *rand, int reliable, char *header);
@@ -2364,7 +2365,7 @@
 	char *callid;
 	char tmp[256] = "";
 	char iabuf[INET_ADDRSTRLEN];
-	char *cmd;
+	const char *cmd = req->rlPart1;
 	char *tag = "", *c;
 
 	callid = get_header(req, "Call-ID");
@@ -2378,11 +2379,6 @@
 		   SIP implementations, and thus Asterisk does not enable this behavior
 		   by default. Short version: You'll need this option to support conferencing
 		   on the pingtel */
-		strncpy(tmp, req->header[0], sizeof(tmp) - 1);
-		cmd = tmp;
-		c = strchr(tmp, ' ');
-		if (c)
-			*c = '\0';
 		if (!strcasecmp(cmd, "SIP/2.0"))
 			strncpy(tmp, get_header(req, "To"), sizeof(tmp) - 1);
 		else
@@ -2414,9 +2410,19 @@
 		p = p->next;
 	}
 	ast_mutex_unlock(&iflock);
-	p = sip_alloc(callid, sin, 1);
-	if (p)
-		ast_mutex_lock(&p->lock);
+
+	if (strcasecmp(cmd, "REGISTER")
+	    && strcasecmp(cmd, "OPTIONS")
+	    && strcasecmp(cmd, "INVITE")
+	    && strcasecmp(cmd, "SUBSCRIBE")
+	    && strcasecmp(cmd, "MESSAGE")) {
+		if (strcasecmp(cmd, "RESPONSE"))
+			transmit_response_using_temp(callid, sin, 1, req, "481 Call leg/transaction does not exist");
+	} else {
+		p = sip_alloc(callid, sin, 1);
+		if (p)
+			ast_mutex_lock(&p->lock);
+	}
 	return p;
 }
 
@@ -3218,6 +3224,45 @@
 	return send_response(p, &resp, reliable, seqno);
 }
 
+/*--- transmit_response_using_temp: Transmit response, no retransmits, using temporary pvt */
+static int transmit_response_using_temp(char *callid, struct sockaddr_in *sin, int useglobal_nat, struct sip_request *req, char *msg)
+{
+	struct sip_pvt *p = alloca(sizeof(*p));
+	char iabuf[INET_ADDRSTRLEN];
+
+	memset(p, 0, sizeof(*p));
+
+	if (sin) {
+		memcpy(&p->sa, sin, sizeof(p->sa));
+		if (ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip))
+			memcpy(&p->ourip, &__ourip, sizeof(p->ourip));
+	} else
+		memcpy(&p->ourip, &__ourip, sizeof(p->ourip));
+	p->branch = rand();
+	p->tag = rand();
+	p->ocseq = 101;
+
+	if (useglobal_nat && sin) {
+		/* Setup NAT structure according to global settings if we have an address */
+		p->nat = global_nat;
+		memcpy(&p->recv, sin, sizeof(p->recv));
+	}
+
+	strncpy(p->fromdomain, default_fromdomain, sizeof(p->fromdomain) - 1);
+	/* z9hG4bK is a magic cookie.  See RFC 3261 section 8.1.1.7 */
+	if (p->nat != SIP_NAT_NEVER)
+		snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
+	else
+		snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
+	strncpy(p->callid, callid, sizeof(p->callid) - 1);
+
+	build_contact(p);
+
+	__transmit_response(p, msg, req, 0);
+
+	return 0;
+}
+
 /*--- transmit_response: Transmit response, no retransmits */
 static int transmit_response(struct sip_pvt *p, char *msg, struct sip_request *req) 
 {
-- END --

-- 
Ben Hutchings
Reality is just a crutch for people who can't handle science fiction.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part
Url : http://lists.alioth.debian.org/pipermail/pkg-voip-maintainers/attachments/20061119/491d14e3/attachment.pgp


More information about the Pkg-voip-maintainers mailing list