[Pkg-voip-commits] r10126 - in /asterisk/branches/squeeze/debian: changelog patches/AST-2013-003 patches/series
tzafrir at alioth.debian.org
tzafrir at alioth.debian.org
Wed Apr 3 09:47:59 UTC 2013
Author: tzafrir
Date: Wed Apr 3 09:47:59 2013
New Revision: 10126
URL: http://svn.debian.org/wsvn/pkg-voip/?sc=1&rev=10126
Log:
Patch AST-2013-003 (CVE-2012-2264): Prevent username disclosure in
SIP channel driver (Closes: #704114).
Added:
asterisk/branches/squeeze/debian/patches/AST-2013-003
Modified:
asterisk/branches/squeeze/debian/changelog
asterisk/branches/squeeze/debian/patches/series
Modified: asterisk/branches/squeeze/debian/changelog
URL: http://svn.debian.org/wsvn/pkg-voip/asterisk/branches/squeeze/debian/changelog?rev=10126&op=diff
==============================================================================
--- asterisk/branches/squeeze/debian/changelog (original)
+++ asterisk/branches/squeeze/debian/changelog Wed Apr 3 09:47:59 2013
@@ -1,3 +1,10 @@
+asterisk (1:1.6.2.9-2+squeeze11) UNRELEASED; urgency=low
+
+ * Patch AST-2013-003 (CVE-2012-2264): Prevent username disclosure in
+ SIP channel driver (Closes: #704114).
+
+ -- Tzafrir Cohen <tzafrir at debian.org> Fri, 29 Mar 2013 00:59:24 +0200
+
asterisk (1:1.6.2.9-2+squeeze10) stable-security; urgency=high
* Fix typo in patch AST-2012-015 (Closes: #698112, #698118).
Added: asterisk/branches/squeeze/debian/patches/AST-2013-003
URL: http://svn.debian.org/wsvn/pkg-voip/asterisk/branches/squeeze/debian/patches/AST-2013-003?rev=10126&op=file
==============================================================================
--- asterisk/branches/squeeze/debian/patches/AST-2013-003 (added)
+++ asterisk/branches/squeeze/debian/patches/AST-2013-003 Wed Apr 3 09:47:59 2013
@@ -1,0 +1,319 @@
+From: Matthew Jordan <mjordan at digium.com>
+Date: Wed, 27 Mar 2013 14:53:13 +0000
+Subject: AST-2013-003: Prevent username disclosure in SIP channel driver
+Bug: https://issues.asterisk.org/jira/browse/ASTERISK-21013
+Origin: http://svnview.digium.com/svn/asterisk?view=rev&rev=383981
+CVE: CVE-2013-2264
+
+When authenticating a SIP request with alwaysauthreject enabled, allowguest
+disabled, and autocreatepeer disabled, Asterisk discloses whether a user
+exists for INVITE, SUBSCRIBE, and REGISTER transactions in multiple ways. The
+information is disclosed when:
+ * A "407 Proxy Authentication Required" response is sent instead of a
+ "401 Unauthorized" response
+ * The presence or absence of additional tags occurs at the end of "403
+ Forbidden" (such as "(Bad Auth)")
+ * A "401 Unauthorized" response is sent instead of "403 Forbidden" response
+ after a retransmission
+ * Retransmission are sent when a matching peer did not exist, but not when a
+ matching peer did exist.
+
+This patch resolves these various vectors by ensuring that the responses sent
+in all scenarios is the same, regardless of the presence of a matching peer.
+
+This issue was reported by Walter Doekes, OSSO B.V. A substantial portion of
+the testing and the solution to this problem was done by Walter as well - a
+huge thanks to his tireless efforts in finding all the ways in which this
+setting didn't work, providing automated tests, and working with Kinsey on
+getting this fixed.
+
+Patch adapted for branch 1.6.2 .
+
+See Also: http://downloads.asterisk.org/pub/security/AST-2013-003.html
+
+---
+ channels/chan_sip.c | 128 ++++++++++++++++++++++++++++----------------
+ channels/sip/include/sip.h | 1 -
+ 2 files changed, 83 insertions(+), 46 deletions(-)
+
+--- a/channels/chan_sip.c
++++ b/channels/chan_sip.c
+@@ -692,7 +692,6 @@ enum check_auth_result {
+ AUTH_SECRET_FAILED = -1,
+ AUTH_USERNAME_MISMATCH = -2,
+ AUTH_NOT_FOUND = -3, /*!< returned by register_verify */
+- AUTH_FAKE_AUTH = -4,
+ AUTH_UNKNOWN_DOMAIN = -5,
+ AUTH_PEER_NOT_DYNAMIC = -6,
+ AUTH_ACL_FAILED = -7,
+@@ -2029,6 +2028,11 @@ static struct ao2_container *threadt;
+ struct ao2_container *peers;
+ struct ao2_container *peers_by_ip;
+
++/*! \brief A bogus peer, to be used when authentication should fail */
++static struct sip_peer *bogus_peer;
++/*! \brief We can recognise the bogus peer by this invalid MD5 hash */
++#define BOGUS_PEER_MD5SECRET "intentionally_invalid_md5_string"
++
+ /*! \brief The register list: Other SIP proxies we register with and place calls to */
+ static struct ast_register_list {
+ ASTOBJ_CONTAINER_COMPONENTS(struct sip_registry);
+@@ -2293,7 +2297,7 @@ static int transmit_response_with_unsupp
+ static int transmit_response_with_auth(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *rand, enum xmittype reliable, const char *header, int stale);
+ static int transmit_provisional_response(struct sip_pvt *p, const char *msg, const struct sip_request *req, int with_sdp);
+ static int transmit_response_with_allow(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable);
+-static void transmit_fake_auth_response(struct sip_pvt *p, int sipmethod, struct sip_request *req, enum xmittype reliable);
++static void transmit_fake_auth_response(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable);
+ static int transmit_request(struct sip_pvt *p, int sipmethod, int inc, enum xmittype reliable, int newbranch);
+ static int transmit_request_with_auth(struct sip_pvt *p, int sipmethod, int seqno, enum xmittype reliable, int newbranch);
+ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init);
+@@ -12791,6 +12795,7 @@ static enum check_auth_result check_auth
+ char a1_hash[256];
+ char resp_hash[256]="";
+ char *c;
++ int is_bogus_peer = 0;
+ int wrongnonce = FALSE;
+ int good_response;
+ const char *usednonce = p->randdata;
+@@ -12881,8 +12886,14 @@ static enum check_auth_result check_auth
+ strsep(&c, " ,");
+ }
+
++ /* We cannot rely on the bogus_peer having a bad md5 value. Someone could
++ * use it to construct valid auth. */
++ if (md5secret && strcmp(md5secret, BOGUS_PEER_MD5SECRET) == 0) {
++ is_bogus_peer = 1;
++ }
++
+ /* Verify that digest username matches the username we auth as */
+- if (strcmp(username, keys[K_USER].s)) {
++ if (strcmp(username, keys[K_USER].s) && !is_bogus_peer) {
+ ast_log(LOG_WARNING, "username mismatch, have <%s>, digest has <%s>\n",
+ username, keys[K_USER].s);
+ /* Oops, we're trying something here */
+@@ -12920,7 +12931,8 @@ static enum check_auth_result check_auth
+ }
+
+ good_response = keys[K_RESP].s &&
+- !strncasecmp(keys[K_RESP].s, resp_hash, strlen(resp_hash));
++ !strncasecmp(keys[K_RESP].s, resp_hash, strlen(resp_hash)) &&
++ !is_bogus_peer; /* lastly, check that the peer isn't the fake peer */
+ if (wrongnonce) {
+ if (good_response) {
+ if (sipdebug)
+@@ -13031,7 +13043,7 @@ static int cb_extensionstate(char *conte
+ /*! \brief Send a fake 401 Unauthorized response when the administrator
+ wants to hide the names of local devices from fishers
+ */
+-static void transmit_fake_auth_response(struct sip_pvt *p, int sipmethod, struct sip_request *req, enum xmittype reliable)
++static void transmit_fake_auth_response(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable)
+ {
+ /* We have to emulate EXACTLY what we'd get with a good peer
+ * and a bad password, or else we leak information. */
+@@ -13070,13 +13082,13 @@ static void transmit_fake_auth_response(
+ }
+
+ if (!(buf = ast_str_thread_get(&check_auth_buf, CHECK_AUTH_BUF_INITLEN))) {
+- transmit_response(p, "403 Forbidden (Bad auth)", &p->initreq);
++ __transmit_response(p, "403 Forbidden", &p->initreq, reliable);
+ return;
+ }
+
+ /* Make a copy of the response and parse it */
+ if (ast_str_set(&buf, 0, "%s", authtoken) == AST_DYNSTR_BUILD_FAILED) {
+- transmit_response(p, "403 Forbidden (Bad auth)", &p->initreq);
++ __transmit_response(p, "403 Forbidden", &p->initreq, reliable);
+ return;
+ }
+
+@@ -13114,7 +13126,7 @@ static void transmit_fake_auth_response(
+ /* Schedule auto destroy in 32 seconds */
+ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+ } else {
+- transmit_response(p, "403 Forbidden (Bad auth)", &p->initreq);
++ __transmit_response(p, "403 Forbidden", &p->initreq, reliable);
+ }
+ }
+
+@@ -13211,6 +13223,14 @@ static enum check_auth_result register_v
+ }
+ }
+ peer = find_peer(name, NULL, TRUE, FINDPEERS, FALSE, 0);
++
++ /* If we don't want username disclosure, use the bogus_peer when a user
++ * is not found. */
++ if (!peer && sip_cfg.alwaysauthreject && !sip_cfg.autocreatepeer) {
++ peer = bogus_peer;
++ ref_peer(peer, "register_verify: ref the bogus_peer");
++ }
++
+ if (!(peer && ast_apply_ha(peer->ha, sin))) {
+ /* Peer fails ACL check */
+ if (peer) {
+@@ -13295,7 +13315,7 @@ static enum check_auth_result register_v
+ switch (parse_register_contact(p, peer, req)) {
+ case PARSE_REGISTER_DENIED:
+ ast_log(LOG_WARNING, "Registration denied because of contact ACL\n");
+- transmit_response_with_date(p, "403 Forbidden (ACL)", req);
++ transmit_response_with_date(p, "403 Forbidden", req);
+ peer->lastmsgssent = -1;
+ res = 0;
+ break;
+@@ -13337,7 +13357,7 @@ static enum check_auth_result register_v
+ switch (res) {
+ case AUTH_SECRET_FAILED:
+ /* Wrong password in authentication. Go away, don't try again until you fixed it */
+- transmit_response(p, "403 Forbidden (Bad auth)", &p->initreq);
++ transmit_response(p, "403 Forbidden", &p->initreq);
+ if (global_authfailureevents)
+ manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Rejected\r\nCause: AUTH_SECRET_FAILED\r\nAddress: %s\r\nPort: %d\r\n",
+ name, ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
+@@ -13351,7 +13371,7 @@ static enum check_auth_result register_v
+ case AUTH_PEER_NOT_DYNAMIC:
+ case AUTH_ACL_FAILED:
+ if (sip_cfg.alwaysauthreject) {
+- transmit_fake_auth_response(p, SIP_REGISTER, &p->initreq, XMIT_UNRELIABLE);
++ transmit_fake_auth_response(p, &p->initreq, XMIT_UNRELIABLE);
+ if (global_authfailureevents) {
+ manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Rejected\r\nCause: %s\r\nAddress: %s\r\nPort: %d\r\n",
+ name, res == AUTH_PEER_NOT_DYNAMIC ? "AUTH_PEER_NOT_DYNAMIC" : "URI_NOT_FOUND",
+@@ -14188,14 +14208,26 @@ static enum check_auth_result check_peer
+ if (debug)
+ ast_verbose("No matching peer for '%s' from '%s:%d'\n",
+ of, ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port));
+- return AUTH_DONT_KNOW;
++
++ /* If you don't mind, we can return 404s for devices that do
++ * not exist: username disclosure. If we allow guests, there
++ * is no way around that. */
++ if (sip_cfg.allowguest || !sip_cfg.alwaysauthreject) {
++ return AUTH_DONT_KNOW;
++ }
++
++ /* If you do mind, we use a peer that will never authenticate.
++ * This ensures that we follow the same code path as regular
++ * auth: less chance for username disclosure. */
++ peer = bogus_peer;
++ ref_peer(peer, "ref_peer: check_peer_ok: must ref bogus_peer so unreffing it does not fail");
+ }
+ if (!ast_apply_ha(peer->ha, sin)) {
+ ast_debug(2, "Found peer '%s' for '%s', but fails host access\n", peer->name, of);
+ unref_peer(peer, "unref_peer: check_peer_ok: from find_peer call, early return of AUTH_ACL_FAILED");
+ return AUTH_ACL_FAILED;
+ }
+- if (debug)
++ if (debug && peer != bogus_peer)
+ ast_verbose("Found peer '%s' for '%s' from %s:%d\n",
+ peer->name, of, ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port));
+
+@@ -14424,9 +14456,7 @@ static enum check_auth_result check_user
+ if (sip_cfg.allowguest) {
+ replace_cid(p, rpid_num, calleridname);
+ res = AUTH_SUCCESSFUL;
+- } else if (sip_cfg.alwaysauthreject)
+- res = AUTH_FAKE_AUTH; /* reject with fake authorization request */
+- else
++ } else
+ res = AUTH_SECRET_FAILED; /* we don't want any guests, authentication will fail */
+
+
+@@ -20237,13 +20267,8 @@ static int handle_request_invite(struct
+ goto request_invite_cleanup;
+ }
+ if (res < 0) { /* Something failed in authentication */
+- if (res == AUTH_FAKE_AUTH) {
+- ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", get_header(req, "From"));
+- transmit_fake_auth_response(p, SIP_INVITE, req, XMIT_RELIABLE);
+- } else {
+- ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From"));
+- transmit_response_reliable(p, "403 Forbidden", req);
+- }
++ ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From"));
++ transmit_response_reliable(p, "403 Forbidden", req);
+ p->invitestate = INV_COMPLETED;
+ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+ ast_string_field_set(p, theirtag, NULL);
+@@ -21526,18 +21551,13 @@ static int handle_request_subscribe(stru
+ event = (char *) eventheader; /* XXX is this legal ? */
+
+ /* Handle authentication */
+- res = check_user_full(p, req, SIP_SUBSCRIBE, e, 0, sin, &authpeer);
++ res = check_user_full(p, req, SIP_SUBSCRIBE, e, XMIT_UNRELIABLE, sin, &authpeer);
+ /* if an authentication response was sent, we are done here */
+ if (res == AUTH_CHALLENGE_SENT) /* authpeer = NULL here */
+ return 0;
+ if (res < 0) {
+- if (res == AUTH_FAKE_AUTH) {
+- ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", get_header(req, "From"));
+- transmit_fake_auth_response(p, SIP_SUBSCRIBE, req, XMIT_UNRELIABLE);
+- } else {
+- ast_log(LOG_NOTICE, "Failed to authenticate device %s for SUBSCRIBE\n", get_header(req, "From"));
+- transmit_response_reliable(p, "403 Forbidden", req);
+- }
++ ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From"));
++ transmit_response(p, "403 Forbidden", req);
+ pvt_set_needdestroy(p, "authentication failed");
+ return 0;
+ }
+@@ -25998,6 +26018,7 @@ static int sip_do_reload(enum channelrel
+ /*! \brief Force reload of module from cli */
+ static char *sip_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
++ static struct sip_peer *tmp_peer, *new_peer;
+
+ switch (cmd) {
+ case CLI_INIT:
+@@ -26020,6 +26041,18 @@ static char *sip_reload(struct ast_cli_e
+ ast_mutex_unlock(&sip_reload_lock);
+ restart_monitor();
+
++ tmp_peer = bogus_peer;
++ /* Create new bogus peer possibly with new global settings. */
++ if ((new_peer = temp_peer("(bogus_peer)"))) {
++ ast_string_field_set(new_peer, md5secret, BOGUS_PEER_MD5SECRET);
++ ast_clear_flag(&new_peer->flags[0], SIP_INSECURE);
++ bogus_peer = new_peer;
++ ao2_t_ref(tmp_peer, -1, "unref the old bogus_peer during reload");
++ } else {
++ ast_log(LOG_ERROR, "Could not update the fake authentication peer.\n");
++ /* You probably have bigger (memory?) issues to worry about though.. */
++ }
++
+ return CLI_SUCCESS;
+ }
+
+@@ -26088,6 +26121,17 @@ static int load_module(void)
+ if(reload_config(sip_reloadreason)) /* Load the configuration from sip.conf */
+ return AST_MODULE_LOAD_DECLINE;
+
++ /* Initialize bogus peer. Can be done first after reload_config() */
++ if (!(bogus_peer = temp_peer("(bogus_peer)"))) {
++ ast_log(LOG_ERROR, "Unable to create bogus_peer for authentication\n");
++ io_context_destroy(io);
++ sched_context_destroy(sched);
++ return AST_MODULE_LOAD_FAILURE;
++ }
++ /* Make sure the auth will always fail. */
++ ast_string_field_set(bogus_peer, md5secret, BOGUS_PEER_MD5SECRET);
++ ast_clear_flag(&bogus_peer->flags[0], SIP_INSECURE);
++
+ /* Prepare the version that does not require DTMF BEGIN frames.
+ * We need to use tricks such as memcpy and casts because the variable
+ * has const fields.
+@@ -26098,6 +26142,7 @@ static int load_module(void)
+ /* Make sure we can register our sip channel type */
+ if (ast_channel_register(&sip_tech)) {
+ ast_log(LOG_ERROR, "Unable to register channel type 'SIP'\n");
++ ao2_t_ref(bogus_peer, -1, "unref the bogus_peer");
+ io_context_destroy(io);
+ sched_context_destroy(sched);
+ return AST_MODULE_LOAD_FAILURE;
+@@ -26259,6 +26304,8 @@ static int unload_module(void)
+ ASTOBJ_CONTAINER_DESTROYALL(&submwil, sip_subscribe_mwi_destroy);
+ ASTOBJ_CONTAINER_DESTROY(&submwil);
+
++ ao2_t_ref(bogus_peer, -1, "unref the bogus_peer");
++
+ ao2_t_ref(peers, -1, "unref the peers table");
+ ao2_t_ref(peers_by_ip, -1, "unref the peers_by_ip table");
+ ao2_t_ref(dialogs, -1, "unref the dialogs table");
Modified: asterisk/branches/squeeze/debian/patches/series
URL: http://svn.debian.org/wsvn/pkg-voip/asterisk/branches/squeeze/debian/patches/series?rev=10126&op=diff
==============================================================================
--- asterisk/branches/squeeze/debian/patches/series (original)
+++ asterisk/branches/squeeze/debian/patches/series Wed Apr 3 09:47:59 2013
@@ -61,3 +61,4 @@
AST-2012-013
AST-2012-014
AST-2012-015
+AST-2013-003
More information about the Pkg-voip-commits
mailing list