MFH: r459011 r459013 r459492
net-p2p/transmission-daemon: Mitigate DNS rebinding attack Incorporate upstream pull request 468, proposed by Tavis Ormandy from Google Project Zero, which mitigates this attack by requiring a host whitelist for requests that cannot be proven to be secure, but it can be disabled if a user does not want security. PR: 225150 Submitted by: Tavis Ormandy Approved by: crees (maintainer) Obtained from: https://github.com/transmission/transmission/pull/468#issuecomment-357098126 Security: https://www.vuxml.org/freebsd/3e5b8bd3-0c32-452f-a60e-beab7b762351.html Add note to UPDATING for net-p2p/transmission-daemon explaining how to allow client access with the new DNS rebinding mitigations. PR: 225150 Security: https://www.vuxml.org/freebsd/3e5b8bd3-0c32-452f-a60e-beab7b762351.html net-p2p/transmission-daemon: Improve UPDATING entry and add pkg-message This will ensure users who do not read UPDATING are still presented with the message about how to allow clients to connect to the daemon using DNS when they upgrade the package. PR: 225150 Reported by: swills Security: https://www.vuxml.org/freebsd/3e5b8bd3-0c32-452f-a60e-beab7b762351.html Approved by: ports-secteam (swills)
This commit is contained in:
parent
6739b20a60
commit
a2389f045c
Notes:
svn2git
2021-03-31 03:12:20 +00:00
svn path=/branches/2018Q1/; revision=459493
24
UPDATING
24
UPDATING
@ -5,6 +5,30 @@ they are unavoidable.
|
||||
You should get into the habit of checking this file for changes each time
|
||||
you update your ports collection, before attempting any port upgrades.
|
||||
|
||||
20180115
|
||||
AFFECTS: users of net-p2p/transmission-daemon
|
||||
AUTHOR: woodsb02@FreeBSD.org
|
||||
|
||||
The transmission-daemon port has been updated to 2.92_4 to incorporate
|
||||
a patch which mitigates DNS rebinding attacks. This will prevent
|
||||
clients from being able to connect to the transmission daemon using
|
||||
DNS with any hostname other than localhost, unless one of the
|
||||
following is done:
|
||||
- Enable password authentication, then any hostname is allowed.
|
||||
This can be achieved by either:
|
||||
- setting rpc-authentication-required to true, and adding
|
||||
credentials to the rpc-username and rpc-password fields in
|
||||
settings.json (must be done whilst the transmission service is
|
||||
stopped); or
|
||||
- running transmission-daemon with the following arguments
|
||||
(these can be set with transmission_flags in /etc/rc.conf):
|
||||
-t -u USERNAME -v PASSWORD
|
||||
OR
|
||||
- Add the allowed server hostnames to the rpc-host-whitelist setting
|
||||
in settings.json (must be done whilst the transmission service is
|
||||
stopped). Note that this value is NOT a list of allowed CLIENTS,
|
||||
but instead a list of allowed SERVER hostnames.
|
||||
|
||||
20171230:
|
||||
AFFECTS: users of net-im/ejabberd
|
||||
AUTHOR: ashish@FreeBSD.org
|
||||
|
302
net-p2p/transmission-cli/files/patch-fix_dns_rebinding_vuln
Normal file
302
net-p2p/transmission-cli/files/patch-fix_dns_rebinding_vuln
Normal file
@ -0,0 +1,302 @@
|
||||
Fix a weakness that allows remote code execution via the Transmission
|
||||
RPC server using DNS rebinding:
|
||||
|
||||
https://bugs.chromium.org/p/project-zero/issues/detail?id=1447
|
||||
|
||||
Patch adapted from Tavis Ormandy's patch on the Transmission master
|
||||
branch to the Transmission 2.92 release by Leo Famulari
|
||||
<leo@famulari.name>:
|
||||
|
||||
https://github.com/transmission/transmission/pull/468/commits
|
||||
|
||||
From fe2d3c6e75088f3d9b6040ce06da3d530358bc2f Mon Sep 17 00:00:00 2001
|
||||
From: Tavis Ormandy <taviso@google.com>
|
||||
Date: Thu, 11 Jan 2018 10:00:41 -0800
|
||||
Subject: [PATCH] mitigate dns rebinding attacks against daemon
|
||||
|
||||
---
|
||||
libtransmission/quark.c | 2 +
|
||||
libtransmission/quark.h | 2 +
|
||||
libtransmission/rpc-server.c | 116 +++++++++++++++++++++++++++++++++++++----
|
||||
libtransmission/rpc-server.h | 4 ++
|
||||
libtransmission/session.c | 2 +
|
||||
libtransmission/transmission.h | 1 +
|
||||
libtransmission/web.c | 3 ++
|
||||
7 files changed, 121 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/libtransmission/quark.c b/libtransmission/quark.c
|
||||
index 30cc2bca4..b4fd7aabd 100644
|
||||
--- libtransmission/quark.c.orig
|
||||
+++ libtransmission/quark.c
|
||||
@@ -289,6 +289,8 @@ static const struct tr_key_struct my_static[] =
|
||||
{ "rpc-authentication-required", 27 },
|
||||
{ "rpc-bind-address", 16 },
|
||||
{ "rpc-enabled", 11 },
|
||||
+ { "rpc-host-whitelist", 18 },
|
||||
+ { "rpc-host-whitelist-enabled", 26 },
|
||||
{ "rpc-password", 12 },
|
||||
{ "rpc-port", 8 },
|
||||
{ "rpc-url", 7 },
|
||||
diff --git a/libtransmission/quark.h b/libtransmission/quark.h
|
||||
index 7f5212733..17464be8f 100644
|
||||
--- libtransmission/quark.h.orig
|
||||
+++ libtransmission/quark.h
|
||||
@@ -291,6 +291,8 @@ enum
|
||||
TR_KEY_rpc_authentication_required,
|
||||
TR_KEY_rpc_bind_address,
|
||||
TR_KEY_rpc_enabled,
|
||||
+ TR_KEY_rpc_host_whitelist,
|
||||
+ TR_KEY_rpc_host_whitelist_enabled,
|
||||
TR_KEY_rpc_password,
|
||||
TR_KEY_rpc_port,
|
||||
TR_KEY_rpc_url,
|
||||
diff --git a/libtransmission/rpc-server.c b/libtransmission/rpc-server.c
|
||||
index a3485f3fa..292cd5fce 100644
|
||||
--- libtransmission/rpc-server.c.orig
|
||||
+++ libtransmission/rpc-server.c
|
||||
@@ -52,6 +52,7 @@ struct tr_rpc_server
|
||||
bool isEnabled;
|
||||
bool isPasswordEnabled;
|
||||
bool isWhitelistEnabled;
|
||||
+ bool isHostWhitelistEnabled;
|
||||
tr_port port;
|
||||
char * url;
|
||||
struct in_addr bindAddress;
|
||||
@@ -63,6 +64,7 @@ struct tr_rpc_server
|
||||
char * password;
|
||||
char * whitelistStr;
|
||||
tr_list * whitelist;
|
||||
+ tr_list * hostWhitelist;
|
||||
|
||||
char * sessionId;
|
||||
time_t sessionIdExpiresAt;
|
||||
@@ -588,6 +590,49 @@ isAddressAllowed (const tr_rpc_server * server, const char * address)
|
||||
return false;
|
||||
}
|
||||
|
||||
+static bool isHostnameAllowed(tr_rpc_server const* server, struct evhttp_request* req)
|
||||
+{
|
||||
+ /* If password auth is enabled, any hostname is permitted. */
|
||||
+ if (server->isPasswordEnabled)
|
||||
+ {
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ char const* const host = evhttp_find_header(req->input_headers, "Host");
|
||||
+
|
||||
+ // If whitelist is disabled, no restrictions.
|
||||
+ if (!server->isHostWhitelistEnabled)
|
||||
+ return true;
|
||||
+
|
||||
+ /* No host header, invalid request. */
|
||||
+ if (host == NULL)
|
||||
+ {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ /* Host header might include the port. */
|
||||
+ char* const hostname = tr_strndup(host, strcspn(host, ":"));
|
||||
+
|
||||
+ /* localhost or ipaddress is always acceptable. */
|
||||
+ if (strcmp(hostname, "localhost") == 0 || strcmp(hostname, "localhost.") == 0 || tr_addressIsIP(hostname))
|
||||
+ {
|
||||
+ tr_free(hostname);
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ /* Otherwise, hostname must be whitelisted. */
|
||||
+ for (tr_list* l = server->hostWhitelist; l != NULL; l = l->next) {
|
||||
+ if (tr_wildmat(hostname, l->data))
|
||||
+ {
|
||||
+ tr_free(hostname);
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ tr_free(hostname);
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
static bool
|
||||
test_session_id (struct tr_rpc_server * server, struct evhttp_request * req)
|
||||
{
|
||||
@@ -663,6 +708,23 @@ handle_request (struct evhttp_request * req, void * arg)
|
||||
handle_upload (req, server);
|
||||
}
|
||||
#ifdef REQUIRE_SESSION_ID
|
||||
+ else if (!isHostnameAllowed(server, req))
|
||||
+ {
|
||||
+ char* tmp = tr_strdup_printf(
|
||||
+ "<p>Transmission received your request, but the hostname was unrecognized.</p>"
|
||||
+ "<p>To fix this, choose one of the following options:"
|
||||
+ "<ul>"
|
||||
+ "<li>Enable password authentication, then any hostname is allowed.</li>"
|
||||
+ "<li>Add the hostname you want to use to the whitelist in settings.</li>"
|
||||
+ "</ul></p>"
|
||||
+ "<p>If you're editing settings.json, see the 'rpc-host-whitelist' and 'rpc-host-whitelist-enabled' entries.</p>"
|
||||
+ "<p>This requirement has been added to help prevent "
|
||||
+ "<a href=\"https://en.wikipedia.org/wiki/DNS_rebinding\">DNS Rebinding</a> "
|
||||
+ "attacks.</p>");
|
||||
+ send_simple_response(req, 421, tmp);
|
||||
+ tr_free(tmp);
|
||||
+ }
|
||||
+
|
||||
else if (!test_session_id (server, req))
|
||||
{
|
||||
const char * sessionId = get_current_session_id (server);
|
||||
@@ -674,7 +736,7 @@ handle_request (struct evhttp_request * req, void * arg)
|
||||
"<li> When you get this 409 error message, resend your request with the updated header"
|
||||
"</ol></p>"
|
||||
"<p>This requirement has been added to help prevent "
|
||||
- "<a href=\"http://en.wikipedia.org/wiki/Cross-site_request_forgery\">CSRF</a> "
|
||||
+ "<a href=\"https://en.wikipedia.org/wiki/Cross-site_request_forgery\">CSRF</a> "
|
||||
"attacks.</p>"
|
||||
"<p><code>%s: %s</code></p>",
|
||||
TR_RPC_SESSION_ID_HEADER, sessionId);
|
||||
@@ -875,19 +937,14 @@ tr_rpcGetUrl (const tr_rpc_server * server)
|
||||
return server->url ? server->url : "";
|
||||
}
|
||||
|
||||
-void
|
||||
-tr_rpcSetWhitelist (tr_rpc_server * server, const char * whitelistStr)
|
||||
+static void
|
||||
+tr_rpcSetList (char const* whitelistStr, tr_list** list)
|
||||
{
|
||||
void * tmp;
|
||||
const char * walk;
|
||||
|
||||
- /* keep the string */
|
||||
- tmp = server->whitelistStr;
|
||||
- server->whitelistStr = tr_strdup (whitelistStr);
|
||||
- tr_free (tmp);
|
||||
-
|
||||
/* clear out the old whitelist entries */
|
||||
- while ((tmp = tr_list_pop_front (&server->whitelist)))
|
||||
+ while ((tmp = tr_list_pop_front (list)) != NULL)
|
||||
tr_free (tmp);
|
||||
|
||||
/* build the new whitelist entries */
|
||||
@@ -896,7 +953,7 @@ tr_rpcSetWhitelist (tr_rpc_server * server, const char * whitelistStr)
|
||||
const char * delimiters = " ,;";
|
||||
const size_t len = strcspn (walk, delimiters);
|
||||
char * token = tr_strndup (walk, len);
|
||||
- tr_list_append (&server->whitelist, token);
|
||||
+ tr_list_append (list, token);
|
||||
if (strcspn (token, "+-") < len)
|
||||
tr_logAddNamedInfo (MY_NAME, "Adding address to whitelist: %s (And it has a '+' or '-'! Are you using an old ACL by mistake?)", token);
|
||||
else
|
||||
@@ -909,6 +966,21 @@ tr_rpcSetWhitelist (tr_rpc_server * server, const char * whitelistStr)
|
||||
}
|
||||
}
|
||||
|
||||
+void tr_rpcSetHostWhitelist(tr_rpc_server* server, char const* whitelistStr)
|
||||
+{
|
||||
+ tr_rpcSetList(whitelistStr, &server->hostWhitelist);
|
||||
+}
|
||||
+
|
||||
+void tr_rpcSetWhitelist(tr_rpc_server* server, char const* whitelistStr)
|
||||
+{
|
||||
+ /* keep the string */
|
||||
+ char* const tmp = server->whitelistStr;
|
||||
+ server->whitelistStr = tr_strdup(whitelistStr);
|
||||
+ tr_free(tmp);
|
||||
+
|
||||
+ tr_rpcSetList(whitelistStr, &server->whitelist);
|
||||
+}
|
||||
+
|
||||
const char*
|
||||
tr_rpcGetWhitelist (const tr_rpc_server * server)
|
||||
{
|
||||
@@ -930,6 +1002,11 @@ tr_rpcGetWhitelistEnabled (const tr_rpc_server * server)
|
||||
return server->isWhitelistEnabled;
|
||||
}
|
||||
|
||||
+void tr_rpcSetHostWhitelistEnabled(tr_rpc_server* server, bool isEnabled)
|
||||
+{
|
||||
+ server->isHostWhitelistEnabled = isEnabled;
|
||||
+}
|
||||
+
|
||||
/****
|
||||
***** PASSWORD
|
||||
****/
|
||||
@@ -1063,6 +1140,28 @@ tr_rpcInit (tr_session * session, tr_variant * settings)
|
||||
else
|
||||
tr_rpcSetWhitelistEnabled (s, boolVal);
|
||||
|
||||
+ key = TR_KEY_rpc_host_whitelist_enabled;
|
||||
+
|
||||
+ if (!tr_variantDictFindBool(settings, key, &boolVal))
|
||||
+ {
|
||||
+ missing_settings_key(key);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ tr_rpcSetHostWhitelistEnabled(s, boolVal);
|
||||
+ }
|
||||
+
|
||||
+ key = TR_KEY_rpc_host_whitelist;
|
||||
+
|
||||
+ if (!tr_variantDictFindStr(settings, key, &str, NULL) && str != NULL)
|
||||
+ {
|
||||
+ missing_settings_key(key);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ tr_rpcSetHostWhitelist(s, str);
|
||||
+ }
|
||||
+
|
||||
key = TR_KEY_rpc_authentication_required;
|
||||
if (!tr_variantDictFindBool (settings, key, &boolVal))
|
||||
missing_settings_key (key);
|
||||
diff --git a/libtransmission/rpc-server.h b/libtransmission/rpc-server.h
|
||||
index e0302c5ea..8c9e6b24e 100644
|
||||
--- libtransmission/rpc-server.h.orig
|
||||
+++ libtransmission/rpc-server.h
|
||||
@@ -49,6 +49,10 @@ void tr_rpcSetWhitelist (tr_rpc_server * server,
|
||||
|
||||
const char* tr_rpcGetWhitelist (const tr_rpc_server * server);
|
||||
|
||||
+void tr_rpcSetHostWhitelistEnabled(tr_rpc_server* server, bool isEnabled);
|
||||
+
|
||||
+void tr_rpcSetHostWhitelist(tr_rpc_server* server, char const* whitelist);
|
||||
+
|
||||
void tr_rpcSetPassword (tr_rpc_server * server,
|
||||
const char * password);
|
||||
|
||||
diff --git a/libtransmission/session.c b/libtransmission/session.c
|
||||
index 844cadba8..58b717913 100644
|
||||
--- libtransmission/session.c.orig
|
||||
+++ libtransmission/session.c
|
||||
@@ -359,6 +359,8 @@ tr_sessionGetDefaultSettings (tr_variant * d)
|
||||
tr_variantDictAddStr (d, TR_KEY_rpc_username, "");
|
||||
tr_variantDictAddStr (d, TR_KEY_rpc_whitelist, TR_DEFAULT_RPC_WHITELIST);
|
||||
tr_variantDictAddBool (d, TR_KEY_rpc_whitelist_enabled, true);
|
||||
+ tr_variantDictAddStr(d, TR_KEY_rpc_host_whitelist, TR_DEFAULT_RPC_HOST_WHITELIST);
|
||||
+ tr_variantDictAddBool(d, TR_KEY_rpc_host_whitelist_enabled, true);
|
||||
tr_variantDictAddInt (d, TR_KEY_rpc_port, atoi (TR_DEFAULT_RPC_PORT_STR));
|
||||
tr_variantDictAddStr (d, TR_KEY_rpc_url, TR_DEFAULT_RPC_URL_STR);
|
||||
tr_variantDictAddBool (d, TR_KEY_scrape_paused_torrents_enabled, true);
|
||||
diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h
|
||||
index 4f76adfd6..e213a8f4e 100644
|
||||
--- libtransmission/transmission.h.orig
|
||||
+++ libtransmission/transmission.h
|
||||
@@ -123,6 +123,7 @@ const char* tr_getDefaultDownloadDir (void);
|
||||
#define TR_DEFAULT_BIND_ADDRESS_IPV4 "0.0.0.0"
|
||||
#define TR_DEFAULT_BIND_ADDRESS_IPV6 "::"
|
||||
#define TR_DEFAULT_RPC_WHITELIST "127.0.0.1"
|
||||
+#define TR_DEFAULT_RPC_HOST_WHITELIST ""
|
||||
#define TR_DEFAULT_RPC_PORT_STR "9091"
|
||||
#define TR_DEFAULT_RPC_URL_STR "/transmission/"
|
||||
#define TR_DEFAULT_PEER_PORT_STR "51413"
|
||||
diff --git a/libtransmission/web.c b/libtransmission/web.c
|
||||
index ee495e9fc..c7f062730 100644
|
||||
--- libtransmission/web.c.orig
|
||||
+++ libtransmission/web.c
|
||||
@@ -594,6 +594,7 @@ tr_webGetResponseStr (long code)
|
||||
case 415: return "Unsupported Media Type";
|
||||
case 416: return "Requested Range Not Satisfiable";
|
||||
case 417: return "Expectation Failed";
|
||||
+ case 421: return "Misdirected Request";
|
||||
case 500: return "Internal Server Error";
|
||||
case 501: return "Not Implemented";
|
||||
case 502: return "Bad Gateway";
|
@ -1,6 +1,6 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PORTREVISION= 3
|
||||
PORTREVISION= 4
|
||||
PKGNAMESUFFIX= -daemon
|
||||
|
||||
MAINTAINER= crees@FreeBSD.org
|
||||
@ -12,6 +12,7 @@ DESCR= ${.CURDIR}/pkg-descr
|
||||
MASTERDIR= ${.CURDIR}/../transmission-cli
|
||||
PLIST= ${.CURDIR}/pkg-plist
|
||||
SLAVEPORT= daemon
|
||||
PKGMESSAGE= ${.CURDIR}/pkg-message
|
||||
|
||||
USE_RC_SUBR= transmission
|
||||
USERS= transmission
|
||||
|
18
net-p2p/transmission-daemon/pkg-message
Normal file
18
net-p2p/transmission-daemon/pkg-message
Normal file
@ -0,0 +1,18 @@
|
||||
------------------------------------------------------------------------
|
||||
To allow clients to connect to the transmission daemon using DNS with
|
||||
any hostname other than localhost, do one of the following:
|
||||
- Enable password authentication, then any hostname is allowed.
|
||||
This can be achieved by either:
|
||||
- setting rpc-authentication-required to true, and adding
|
||||
credentials to the rpc-username and rpc-password fields in
|
||||
settings.json (must be done whilst the transmission service is
|
||||
stopped); or
|
||||
- running transmission-daemon with the following arguments
|
||||
(these can be set with transmission_flags in /etc/rc.conf):
|
||||
-t -u USERNAME -v PASSWORD
|
||||
OR
|
||||
- Add the allowed server hostnames to the rpc-host-whitelist setting
|
||||
in settings.json (must be done whilst the transmission service is
|
||||
stopped). Note that this value is NOT a list of allowed CLIENTS,
|
||||
but instead a list of allowed SERVER hostnames.
|
||||
------------------------------------------------------------------------
|
Loading…
Reference in New Issue
Block a user