數據庫審計產品常見缺陷(3)多語句無法有效分割

2014-04-02 11:09:07來源:游俠安全網作者:

多語句是SQL Server上的一個特定情況。在其它的數據庫管理系統中,語句之間都有明確的分割標識;而在SQL Serve中語句之間可以沒有明確的分隔符。下面是一個示例:

多語句是SQL Server上的一個特定情況。在其它的數據庫管理系統中,語句之間都有明確的分割標識;而在SQL Serve中語句之間可以沒有明確的分隔符。下面是一個示例:

use opencms SET NOCOUNT ON select * from opencms.opencms.CMS_LOG? where 1=1 or ‘a’ =’b’ select * from opencms.opencms.CMS_HISTORY_PROJECTS where 1=1

在這些語句之間沒有類似于 ;號這樣的明確分隔標識符;它們實際代表了四條語句:

use opencms

SET NOCOUNT ON

select * from opencms.opencms.CMS_LOG? where 1=1 or ‘a’ =’b’

select * from opencms.opencms.CMS_HISTORY_PROJECTS where 1=1

SQL Server會將這些語句不加分割地組織在一個數據庫通訊包中發送;對于一些專業化程度不高的數據庫審計產品,會將這些語句作為一條語句審計下來。有效地實現多語句分割,需要非常專業的SQL解析技術。一些簡單的方法,比如用select、use 、set這樣的關鍵字來進行語句分割,稍微復雜的情況就不好處理了;下面這個示例,就無法用這種簡單的方法處理:

Select * from t1 where t1.col1 = 1 union     select * from? t2 where t2.col1 = 1 select * from t2 where t2.col1 = 1

即使采用稍微復雜一些的技術,比如正則表達式,也很難做到準確切割;非專業化的數據庫審計產品都存在這個缺陷。 對無法準確切割多語句的缺陷,在不同的產品中表現不同,所造成的審計問題也不同,但大體可以總結為如下幾點:

(1)在審計記錄中,不能準確記錄下每條語句的SQL操作類型,從而造成一些高危操作不能不有效地被識別或告警,比如drop、truncate這些語句。

(2)在審計記錄中,不能準確記錄下每條SQL語句的數據庫對象,從而對敏感對象的訪問不能有效地被識別或告警。

(3)在審計記錄中,不能準確地記錄每條語句是否執行成功;比如多條語句中第一條語句執行成功,后面的語句執行失敗了,往往會被整體記錄為一個結果,往往是成功。

(4)在審計記錄中,不能準確地反饋出每條語句造成的影響行數,從而也無法觸發基于影響行的安全策略;往往記錄下來的都是第一條語句的影響行,其余語句的影響行都被扔掉了。

下面的結果是一個專業數據庫審計產品的執行結果,該產品準確實現了多語句切割,同時準確審計了每條語句的執行成功與否和影響行:

db

以上結果,根據語句發送的先后順序進行了倒排顯示,同時審計了每條語句的操作對象、SQL語句、執行成功與否,影響行數。

這里進一步提供了一些用例,來幫助讀者驗證數據庫審計產品能否完成多語句切割,是否準確地審計了每條語句的訪問對象、返回結果和影響行:

用例一(一個很基本的多語句例子)

INSERT INTO #AM_DBFILEIO(COLLECTION_TIME,TOTAL_IO_BYTES)VALUES(@CURRENT_COLLECTION_TIME,@CURRENT_TOTAL_IO_MB)

insert #t1 ( object_id, object_type, rank)

select t.relative_id, t.relative_type, 1 from #t1 t where t.relative_id not in ( select t2.object_id from #t1 t2 where not t2.object_id is null )

用例二(一個稍顯復雜點的,與游標相關的多語句示例):

DECLARE tables_cursor CURSOR

FOR

SELECT name FROM sysobjects WHERE type = ‘U’

OPEN tables_cursor

DECLARE @tablename sysname

FETCH NEXT FROM tables_cursor INTO @tablename

WHILE (@@FETCH_STATUS <> -1)

BEGIN

/* A @@FETCH_STATUS of -2 means that the row has been deleted.

There is no need to test for this because this loop drops all user-defined tables. */

EXEC (‘DROP TABLE ‘ + @tablename)

FETCH NEXT FROM tables_cursor INTO @tablename

END

PRINT ‘All user-defined tables have been dropped from the database.’

DEALLOCATE tables_cursor ;

用例三:(一個更復雜的的多語句示例)

SET NOCOUNT ON;

– Check Agent Status

CREATE TABLE #TempAgentStatus (AgentStatus nvarchar(50))

IF (IS_SRVROLEMEMBER(‘sysadmin’) > 0)

INSERT #TempAgentStatus (AgentStatus)

EXEC master..xp_servicecontrol N’QUERYSTATE’,N’SQLServerAGENT’ ;

ELSE

INSERT #TempAgentStatus (AgentStatus) — sometimes this check doesn’t work – there are complains on the www

SELECT ‘running’ FROM master.dbo.sysprocesses WHERE program_name like N’SQLAgent%Generic%Refresher%’

DECLARE @AgentRunning int;

SET @AgentRunning = 0

SELECT @AgentRunning =1 from #TempAgentStatus where CharIndex(N’running’, Lower(AgentStatus)) > 0

DROP TABLE #TempAgentStatus

– End Check Agent Status

DECLARE @can_see_all_running_jobs int;

SET @can_see_all_running_jobs = ISNULL(IS_SRVROLEMEMBER(N’sysadmin’), 0);

DECLARE @current_execution_status int;

DECLARE @job_owner sysname;

SET @job_owner = SUSER_SNAME();

CREATE TABLE #xp_results

(

job_id UNIQUEIDENTIFIER NOT NULL,

last_run_date int NOT NULL,

last_run_time int NOT NULL,

next_run_date int NOT NULL,

next_run_time int NOT NULL,

next_run_schedule_id int NOT NULL,

requested_to_run int NOT NULL, — BOOL

request_source int NOT NULL,

request_source_id sysname COLLATE database_default NULL,

running int NOT NULL, — BOOL

current_step int NOT NULL,

current_retry_attempt int NOT NULL,

job_state int NOT NULL

);

IF @AgentRunning = 1

BEGIN

INSERT INTO #xp_results

EXECUTE master.dbo.xp_sqlagent_enum_jobs @can_see_all_running_jobs, @job_owner;

END

SELECT DISTINCT

COUNT(1)

FROM

msdb.dbo.sysjobs_view obj LEFT OUTER JOIN msdb.dbo.sysjobservers js ON js.job_id = obj.job_id

LEFT OUTER JOIN msdb.dbo.sysjobhistory jh ON (jh.job_id = obj.job_id) AND

(jh.step_id = 0) AND

(jh.instance_id = (SELECT Max(ijh.instance_id)

FROM msdb.dbo.sysjobhistory ijh

WHERE ijh.job_id = obj.job_id))

LEFT OUTER JOIN #xp_results res on js.job_id = res.job_id

DROP TABLE #xp_results;

說明:本文來自數據庫安全廠家“安華金和” 的投稿,首發“游俠安全網”(www.youxia.org),轉載請包括本聲明。

贊助商鏈接:

牛牛视频