You are viewing a plain text version of this content. The canonical link for it is here.
Posted to xmlrpc-dev@ws.apache.org by Greg Smethells <gs...@medstrat.com> on 2010/04/01 18:06:45 UTC

Connection re-use bug in XML-RPC 3.1.3

---------- Forwarded message ----------
From: Greg Smethells <gs...@medstrat.com>
To: xmlrpc-auto@ws.apache.org
Date: Thu, 18 Mar 2010 10:22:21 -0500
Subject: Connection re-use bug in XML-RPC 3.1.3

XML-RPC Developers,

There is a security hole in the re-use of server connections when
basic authentication is involved.

Context:
We have an XML-RPC client that connects to a server over HTTPS and
requires basic authentication. Initially, the app starts up using a
1st username/password and our java.net.Authenticator does a
setDefault() to our own WebServerAuthenticator class. It's
getPasswordAuthentication() is called by HttpURLConnection and the
connection succeeds on the server. I cannot tell if it is ever used,
but the XmlRpcClientConfigImpl also has its setBasicUserName and
setBasicPassword set on the xmlrpcClient instance. Everything looks
good at that point.
Then, we have an administration dialog we use to configure the server
side, which is where the issue starts to come up. The
username/password at this point is different than when the app first
signed into the server. A new WebServerAuthenticator class is
setDefault()-ed with this admin (2nd) username/password and a new
XmlRpcClientConfigImpl is instantiated and set to the admin's (2nd)
user/pass and a new xmlrpcClient is also instantiated and set to the
new client config. On the server side, I can see the client try to log
in as the admin (2nd); however, if I provide a bogus password, I can
see the basic auth fail on the server side AND THEN the original
(1st) username/password (not the admin (2nd) credentials) are used to
sign in and the RPC returns successfully (no exception thrown for
password mismatch!). Unbeknownst to the app the xmlrpcClient has used
credentials that were not asked to be used!

Source Code:
This is called during construction of the client-side server proxy ...
                        // Assign an Authenticator to pass username
and password data during HTTPS requests
                        // Required for getting past Apache
authentication (.htaccess)
                        Authenticator.setDefault(new
WebServerAuthenticator(username, password));
                        // Create the XML-RPC client
XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
// Set-up the URL to the XML-RPC server
config.setServerURL(new URL("https://" + ipAddress + "/" + cgiScript));
// Set-up the log-in credentials that provide our actual security
config.setBasicUserName(username);
config.setBasicPassword(password);
config.setEnabledForExtensions(true);
// WARNING: must be as high enough to allow all timeouts given to call()
config.setConnectionTimeout(30 * 1000);        // Timeout for connecting
config.setReplyTimeout(MAX_TIMEOUT * 1000);    // Timeout for XML-RPC
replies
xmlrpcClient = new XmlRpcClient();
xmlrpcClient.setConfig(config);
// Timeout after "timeout" seconds ("timeout" seconds x 1000 milliseconds)
TimingOutCallback callback = new TimingOutCallback(15 * 1000);
// Fault tolerant connect
try {
Object[] result;
Object[] params = new Object[] {};
if( testRPC.length() > 0 ) {
// Asynchronous remote procedure call
xmlrpcClient.executeAsync(testRPC, getParams(params), callback);
result = (Object[]) callback.waitForResponse();

// If we did not throw an exception and got here, then we are connected
  state = CONNECTED;
// Finish any internal state set-up
setupState(result);
Console.print("Connection opened to " + toString());
}
else {
// Assume we are "connected"
state = CONNECTED;
Console.print("Proxy created for " + toString());
}
}
catch(TimeoutException e) {
setState(e.getMessage(), ADDRESS_UNREACHABLE);
}
catch(XmlRpcException xrex) {
parseState(xrex.getMessage());
}
catch(Exception ex) {
parseState(ex.getMessage());
}
catch(Throwable t) {
parseState(t.toString());
}
}
else {
state = CONNECTION_NOT_ALLOWED;
}
Thanks,
Greg

Software Architect
Medstrat, Inc.




--
Germanys national anthem is the most boring in the world - how telling!

Re: Connection re-use bug in XML-RPC 3.1.3

Posted by Greg Smethells <gs...@medstrat.com>.
>
> You start by configuring the client with an initial user name and
> password. Later on, you reconfigure it to use another, "bogus"
> password. As soon as the server rejects the "bogus" user name and
> password, the client starts using the initial credentials again and
> authenticates successfully. Right?
>

Actually, not quite right.

There are two instances of the class XMLRPCProxy whose init source code was
provided. The first instance is configured to use a regular user's
username/password. The second instance is configured to use an admin user's
username/password.

When the human giving the admin password provides an incorrect password to
the second instance, then the regular user's credentials configured in the
first instance appear to be used instead by the second instance when
authenticating to Apache. This can be seen by checking
the os.environ.get('REMOTE_USER') on the server side (which is running
Apache httpd). The /var/log/messages trace from our server code's use of
logger shows the admin RPCs are being called by a regular user and failing
(because the REMOTE_USER var is not "admin").

The first instance's regular user's credentials are never invalid. There can
be more than one connection to httpd using the same regular user's
credentials.
Both ends of the connection are Apache. This is Apache XML-RPC talking to
the Apache Server.

I don't know what Apache is doing when talking to Apache as far as it's use
of a protocol under the hood, but I'm sure that's an implementation detail a
user of the library should not have to deal with directly, which is why when
I saw this behavior, I took time to point it out.

*without* the use of the Authenticator class (indeed, I haven't got
> the slightest idea, why you are using both) and with a complete source
> code example.
>

I am using the Authenticator class because the basic authentication over
https has failed otherwise. I'd rather not use it.

Thanks,
Greg

Software Architect
Medstrat, Inc.



> On Thu, Apr 1, 2010 at 6:06 PM, Greg Smethells <gs...@medstrat.com>
> wrote:
>  > ---------- Forwarded message ----------
> > From: Greg Smethells <gs...@medstrat.com>
> > To: xmlrpc-auto@ws.apache.org
> > Date: Thu, 18 Mar 2010 10:22:21 -0500
> > Subject: Connection re-use bug in XML-RPC 3.1.3
> >
> > XML-RPC Developers,
> >
> > There is a security hole in the re-use of server connections when
> > basic authentication is involved.
> >
> > Context:
> > We have an XML-RPC client that connects to a server over HTTPS and
> > requires basic authentication. Initially, the app starts up using a
> > 1st username/password and our java.net.Authenticator does a
> > setDefault() to our own WebServerAuthenticator class. It's
> > getPasswordAuthentication() is called by HttpURLConnection and the
> > connection succeeds on the server. I cannot tell if it is ever used,
> > but the XmlRpcClientConfigImpl also has its setBasicUserName and
> > setBasicPassword set on the xmlrpcClient instance. Everything looks
> > good at that point.
> > Then, we have an administration dialog we use to configure the server
> > side, which is where the issue starts to come up. The
> > username/password at this point is different than when the app first
> > signed into the server. A new WebServerAuthenticator class is
> > setDefault()-ed with this admin (2nd) username/password and a new
> > XmlRpcClientConfigImpl is instantiated and set to the admin's (2nd)
> > user/pass and a new xmlrpcClient is also instantiated and set to the
> > new client config. On the server side, I can see the client try to log
> > in as the admin (2nd); however, if I provide a bogus password, I can
> > see the basic auth fail on the server side AND THEN the original
> > (1st) username/password (not the admin (2nd) credentials) are used to
> > sign in and the RPC returns successfully (no exception thrown for
> > password mismatch!). Unbeknownst to the app the xmlrpcClient has used
> > credentials that were not asked to be used!
> >
> > Source Code:
> > This is called during construction of the client-side server proxy ...
> >                        // Assign an Authenticator to pass username
> > and password data during HTTPS requests
> >                        // Required for getting past Apache
> > authentication (.htaccess)
> >                        Authenticator.setDefault(new
> > WebServerAuthenticator(username, password));
> >                        // Create the XML-RPC client
> > XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
> > // Set-up the URL to the XML-RPC server
> > config.setServerURL(new URL("https://" + ipAddress + "/" + cgiScript));
> > // Set-up the log-in credentials that provide our actual security
> > config.setBasicUserName(username);
> > config.setBasicPassword(password);
> > config.setEnabledForExtensions(true);
> > // WARNING: must be as high enough to allow all timeouts given to call()
> > config.setConnectionTimeout(30 * 1000);        // Timeout for connecting
> > config.setReplyTimeout(MAX_TIMEOUT * 1000);    // Timeout for XML-RPC
> > replies
> > xmlrpcClient = new XmlRpcClient();
> > xmlrpcClient.setConfig(config);
> > // Timeout after "timeout" seconds ("timeout" seconds x 1000
> milliseconds)
> > TimingOutCallback callback = new TimingOutCallback(15 * 1000);
> > // Fault tolerant connect
> > try {
> > Object[] result;
> > Object[] params = new Object[] {};
> > if( testRPC.length() > 0 ) {
> > // Asynchronous remote procedure call
> > xmlrpcClient.executeAsync(testRPC, getParams(params), callback);
> > result = (Object[]) callback.waitForResponse();
> >
> > // If we did not throw an exception and got here, then we are connected
> >  state = CONNECTED;
> > // Finish any internal state set-up
> > setupState(result);
> > Console.print("Connection opened to " + toString());
> > }
> > else {
> > // Assume we are "connected"
> > state = CONNECTED;
> > Console.print("Proxy created for " + toString());
> > }
> > }
> > catch(TimeoutException e) {
> > setState(e.getMessage(), ADDRESS_UNREACHABLE);
> > }
> > catch(XmlRpcException xrex) {
> > parseState(xrex.getMessage());
> > }
> > catch(Exception ex) {
> > parseState(ex.getMessage());
> > }
> > catch(Throwable t) {
> > parseState(t.toString());
> > }
> > }
> > else {
> > state = CONNECTION_NOT_ALLOWED;
> > }
> > Thanks,
> > Greg
> >
> > Software Architect
> > Medstrat, Inc.
> >
> >
> >
> >
> > --
> > Germanys national anthem is the most boring in the world - how telling!
> >
>
>
>
> --
> Germanys national anthem is the most boring in the world - how telling!
>

Re: Connection re-use bug in XML-RPC 3.1.3

Posted by Jochen Wiedmann <jo...@gmail.com>.
Hi, Greg,

I am not sure, whether I do understand the issue completely, so let me
repeat it first:

You start by configuring the client with an initial user name and
password. Later on, you reconfigure it to use another, "bogus"
password. As soon as the server rejects the "bogus" user name and
password, the client starts using the initial credentials again and
authenticates successfully. Right?

If that's right: First of all, I'd consider that the server has a
*much more* important security problem, if it does accept the initial
(and no longer valid) credentials again. Second, I'd be interested to
see your proof of your assertion first before I believe it. For
example, a network protocol, or something like that. Third, I am not
believing that the problem is in the Apache XML-RPC code, unless you
also demonstrate me that you can create said network protocol
*without* the use of the Authenticator class (indeed, I haven't got
the slightest idea, why you are using both) and with a complete source
code example.

Sorry,

Jochen


On Thu, Apr 1, 2010 at 6:06 PM, Greg Smethells <gs...@medstrat.com> wrote:
> ---------- Forwarded message ----------
> From: Greg Smethells <gs...@medstrat.com>
> To: xmlrpc-auto@ws.apache.org
> Date: Thu, 18 Mar 2010 10:22:21 -0500
> Subject: Connection re-use bug in XML-RPC 3.1.3
>
> XML-RPC Developers,
>
> There is a security hole in the re-use of server connections when
> basic authentication is involved.
>
> Context:
> We have an XML-RPC client that connects to a server over HTTPS and
> requires basic authentication. Initially, the app starts up using a
> 1st username/password and our java.net.Authenticator does a
> setDefault() to our own WebServerAuthenticator class. It's
> getPasswordAuthentication() is called by HttpURLConnection and the
> connection succeeds on the server. I cannot tell if it is ever used,
> but the XmlRpcClientConfigImpl also has its setBasicUserName and
> setBasicPassword set on the xmlrpcClient instance. Everything looks
> good at that point.
> Then, we have an administration dialog we use to configure the server
> side, which is where the issue starts to come up. The
> username/password at this point is different than when the app first
> signed into the server. A new WebServerAuthenticator class is
> setDefault()-ed with this admin (2nd) username/password and a new
> XmlRpcClientConfigImpl is instantiated and set to the admin's (2nd)
> user/pass and a new xmlrpcClient is also instantiated and set to the
> new client config. On the server side, I can see the client try to log
> in as the admin (2nd); however, if I provide a bogus password, I can
> see the basic auth fail on the server side AND THEN the original
> (1st) username/password (not the admin (2nd) credentials) are used to
> sign in and the RPC returns successfully (no exception thrown for
> password mismatch!). Unbeknownst to the app the xmlrpcClient has used
> credentials that were not asked to be used!
>
> Source Code:
> This is called during construction of the client-side server proxy ...
>                        // Assign an Authenticator to pass username
> and password data during HTTPS requests
>                        // Required for getting past Apache
> authentication (.htaccess)
>                        Authenticator.setDefault(new
> WebServerAuthenticator(username, password));
>                        // Create the XML-RPC client
> XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
> // Set-up the URL to the XML-RPC server
> config.setServerURL(new URL("https://" + ipAddress + "/" + cgiScript));
> // Set-up the log-in credentials that provide our actual security
> config.setBasicUserName(username);
> config.setBasicPassword(password);
> config.setEnabledForExtensions(true);
> // WARNING: must be as high enough to allow all timeouts given to call()
> config.setConnectionTimeout(30 * 1000);        // Timeout for connecting
> config.setReplyTimeout(MAX_TIMEOUT * 1000);    // Timeout for XML-RPC
> replies
> xmlrpcClient = new XmlRpcClient();
> xmlrpcClient.setConfig(config);
> // Timeout after "timeout" seconds ("timeout" seconds x 1000 milliseconds)
> TimingOutCallback callback = new TimingOutCallback(15 * 1000);
> // Fault tolerant connect
> try {
> Object[] result;
> Object[] params = new Object[] {};
> if( testRPC.length() > 0 ) {
> // Asynchronous remote procedure call
> xmlrpcClient.executeAsync(testRPC, getParams(params), callback);
> result = (Object[]) callback.waitForResponse();
>
> // If we did not throw an exception and got here, then we are connected
>  state = CONNECTED;
> // Finish any internal state set-up
> setupState(result);
> Console.print("Connection opened to " + toString());
> }
> else {
> // Assume we are "connected"
> state = CONNECTED;
> Console.print("Proxy created for " + toString());
> }
> }
> catch(TimeoutException e) {
> setState(e.getMessage(), ADDRESS_UNREACHABLE);
> }
> catch(XmlRpcException xrex) {
> parseState(xrex.getMessage());
> }
> catch(Exception ex) {
> parseState(ex.getMessage());
> }
> catch(Throwable t) {
> parseState(t.toString());
> }
> }
> else {
> state = CONNECTION_NOT_ALLOWED;
> }
> Thanks,
> Greg
>
> Software Architect
> Medstrat, Inc.
>
>
>
>
> --
> Germanys national anthem is the most boring in the world - how telling!
>



-- 
Germanys national anthem is the most boring in the world - how telling!