COMMAND
informix
SYSTEMS AFFECTED
Systems running informix
PROBLEM
Nathan Neulinger found following. The security hole is severe
enough to basically null out any security database/table
permissions that you use.
The problem boiled down to - they are using BSD ruserok() type
security for their remote database access for other unix hosts,
but they don't bother to check the source port. So, if you enable
another host (that you rightly trust on a secure network) to
connect to your database server, you have unwittingly given ALL
users on that host access to ALL users in the database server.
What's worse, within a couple of minutes, a user on the remote
machine can run a program (rinetd for example) that will allow
ANYONE from ANYWHERE to connect to the database as any user.
Informix 5.x and 7.x (probably all versions using Informix-NET)
purport to support BSD rhosts()/hosts.equiv mechanism for network
access control. However, the server relay process (sqlexecd)
does not verify that the connection is from a reserved port.
The basic setup is that you have a database server, and several
other client unix stations. You (root) are the only one who has
administrator authority on all the stations. Each client station
has lots of users on them, only some of which have database
access. For each client station that you want to be able to
access the database server, you add it to the hosts.equiv file on
the database server.
So far, nothing out of the ordinary. Since (in my case) the
network between all the stations is secure there is no security
issue at this point.
Since the informix daemon process (sqlexecd) does not verify the
source port, this results in a major security problem, since the
ONLY way of trusting a socket connection from a remote host is if
you trust the remote host, AND the connection comes from a secure
port.
Hard Method:
============
Any user on a trusted host can (by learning the informix sqlexecd
protocol, or replaying a previously captured conversation from
another copy of informix software) establish a connection to the
database server AS -ANY- userid.
Easy Method:
============
Any user can run a rinetd type of relay on a trusted host that
relays the connection from the trusted host to the database
server. After doing this, anyone from any host on the internet
can use their own personal copy of informix and open a connection
to the trusted host, as if it were the real database server. The
connection will then be passed on through, and the remote sqlexecd
will accept what it is told without checking the remote userid.
A similar problem occurs using .rhosts instead of hosts.equiv.
When using rhosts, assuming the entry "host1.domain anything" in
'joe's account, any user on host1.domain can connect to the
database server as joe. The value of 'anything' doesn't matter.
In summary, when you add a trusted host - the BSD r-tools are
only giving access from one userid to the matching userid. The
sqlexecd is giving access from ANY userid to ANY other userid.
In all of the above (trusted host == host in /etc/hosts.equiv).
b) How would you envision it being used in an attack scenario:
Case 1:
=======
A local user decides they want to make a change to a database they
have no permissions to modify.
Step 1: Start rinetd on a trusted host (HOST-T) that connects to
the database server host (HOST-DB)
Step 2: Install informix on another unix host anywhere (HOST-C)
Step 3: Create a userid on HOST-C that matches a userid on HOST-DB
that has database privileges, i.e. 'informix', the DBA
userid.
Step 4: Log in as 'informix' on HOST-C
Step 5: Point Informix software on HOST-C at HOST-T, and open a
connection
Voila. You now have a SQL connection to the database server as
'informix', and can do whatever you want.
Case 2:
=======
Local user grants access using rinetd type facility to the entire
database server to other users outside the organization, even
though the local user only has minimal or no database privileges.
Case 3:
=======
Current employee leaves (fired/quits/etc). Before leaving, they
put in a rinetd service on a trusted host. After leaving, they
can still access the databases.
This has been tested under HpUX 9.x and 10.x. Nathan tested and
verified that the problem occurs with the following connections:
- 5.x client -> 5.x server (Online)
- 7.x client -> 7.x server (Informix-SE)
- 7.x client -> 5.x server (Online)
Here is more detailed explaination. First, a short explanation
of BSD ruserok() security mechanisms. First requirement is that
you trust the network between the two computers. (i.e. two ports
on a switch, an internal network that you have complete control
over, etc.), or even a network hooked to the internet, provided
that the two hosts have a trusted network between them, and that
you have a reasonable router configuration (i.e. protect against
spoofing).
Second, you trust root on both machines. With that, since unix
won't let non-root users (or not setuid-root) users bind to ports
less than 1024, you know that if you receive a connection from a
trusted host, and it's from a port less than 1024 then you can
trust that either root or a root authorized process initiated the
connection. Once that is established, you can trust the
information that is sent over the connection, i.e. the userid.
Based on documentation in informix manuals, people often configure
their trusted hosts to be able to access the database via these
mechanisms, putting the hosts in hosts.equiv or having individual
users set up .rhosts files. Heres where the problem is. The
Informix sqlexecd's do not bother to check the source port to make
sure it is less than 1024. This gives up ALL the security in the
ruserok() mechanism. Since anyone can open the connection at that
point and send whatever data they want. (i.e. a different userid
than who they really are).
Now, the 5-minute-give-me-full-access-to-everything exploit:
1. Get a userid on any trusted machine - i.e. you are a
current/ex employee, a hole in a cgi script, whatever
2. Compile a program like 'rinetd' - basically it accepts
inbound tcp connections on one port, and opens a connection
to another host on the same or different port. (This is as
simple as a 20-30 line c program.) This program can be run
by any normal user and requires no special privileges.
3. Configure the program to accept connections on port 37843
or some other arbitrary port number, and tell them to
connect to port 1525 (or whatever you have in your
services/sqlhosts file) on your database server. Run the
program.
4. Go to ANY other host on the internet, get a copy of
informix, or Info-Maker, or pretty much anything that can
talk to an informix database server.
5. Tell the software to open up a connection to the database
server running at port 37843 on the host where you ran the
rinetd. Claim to be whoever you want to be. The database
server will log you in without a password.
If you use hosts.equiv, all userids on the database server are
vulnerable. If you use .rhosts, any user that uses .rhosts is
vulnerable - no matter what userids they list in the file.
SOLUTION
The problem is that sqlexecd is not verifying the source port.
There are two possible fixes:
1) If client software will automatically try a <1024 source port
if it is setuid, then just change sqlexecd to require a source
port <1024. (As is pretty much mandated by saying that you're
doing BSD security).
2) Alternatively, sqlexecd could attempt to verify the remote user
using ident. Since you've already stated that root on the
remote host is trusted, this isn't a security problem.