Oracle 支援在資料庫內載入並執行 Java 類別,透過 PL/SQL Call Specs 公開靜態方法為 SQL 可呼叫函數。適用於檔案系統存取、外部程式呼叫、網路通訊等 PL/SQL 難以處理的場景。
注意:本文示範代碼包含反向 Shell、檔案讀寫、命令執行等高風險功能,僅供教學理解 Java Stored Procedure 機制,生產環境嚴禁部署此類程式碼,極易造成資安漏洞。
CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED "ISTO" AS
import java.io.*;
import java.net.*;
public class ISTO {
// 列舉目錄
public static String listFolder(String path) { ... }
// 儲存檔案
public static String saveFile(String filepath, String value) { ... }
// 讀取檔案
public static String readFile(String pathfile, String code) { ... }
// 執行外部程式
public static String execFile(String filepath, String code) { ... }
// 綁定 Shell (Bind Shell)
public static String bindShell(int port) { ... }
// 反向 Shell (Reverse Shell)
public static String reverseShell(String host, int port) { ... }
// 內部類別處理 Shell 互動
public static class optShell extends Thread { ... }
};
建立對應的 PL/SQL 函數對應 Java 靜態方法:
CREATE OR REPLACE FUNCTION isto_listfolder(p_path VARCHAR2) RETURN VARCHAR2
AS LANGUAGE JAVA NAME 'ISTO.listFolder(java.lang.String) return java.lang.String';
CREATE OR REPLACE FUNCTION isto_savefile(p_path VARCHAR2, p_value VARCHAR2) RETURN VARCHAR2
AS LANGUAGE JAVA NAME 'ISTO.saveFile(java.lang.String, java.lang.String) return java.lang.String';
CREATE OR REPLACE FUNCTION isto_readfile(p_path VARCHAR2, p_code VARCHAR2) RETURN VARCHAR2
AS LANGUAGE JAVA NAME 'ISTO.readFile(java.lang.String, java.lang.String) return java.lang.String';
CREATE OR REPLACE FUNCTION isto_execfile(p_path VARCHAR2, p_code VARCHAR2) RETURN VARCHAR2
AS LANGUAGE JAVA NAME 'ISTO.execFile(java.lang.String, java.lang.String) return java.lang.String';
CREATE OR REPLACE FUNCTION isto_bindshell(p_port NUMBER) RETURN VARCHAR2
AS LANGUAGE JAVA NAME 'ISTO.bindShell(int) return java.lang.String';
CREATE OR REPLACE FUNCTION isto_reverseshell(p_host VARCHAR2, p_port NUMBER) RETURN VARCHAR2
AS LANGUAGE JAVA NAME 'ISTO.reverseShell(java.lang.String, int) return java.lang.String';
預設 Java 在資料庫中運行於沙箱,需明確授予檔案、網路、執行權限:
BEGIN
DBMS_JAVA.GRANT_PERMISSION('用戶名', 'java.io.FilePermission', '<>', 'read,write,execute,delete');
DBMS_JAVA.GRANT_PERMISSION('用戶名', 'java.lang.RuntimePermission', '*', 'writeFileDescriptor');
DBMS_JAVA.GRANT_PERMISSION('用戶名', 'java.net.SocketPermission', '*:*', 'accept,connect,listen,resolve');
END;
/
SELECT isto_listfolder('/usr') FROM dual;
SELECT isto_execfile('C:\Windows\system32\cmd.exe /c dir c:\', 'GBK') FROM dual;
SELECT isto_readfile('/tmp/1.txt', 'GBK') FROM dual;
SELECT isto_savefile('/tmp/1.txt', '測試內容') FROM dual;
SELECT isto_bindshell(20000) FROM dual; -- 監聽埠,極高風險
FilePermission 路徑、禁止 RuntimePermission、限制 SocketPermission 目標主機/埠