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