[SQL]淺談SQL Injection發生後

這兩三年來,在跑的整合案,遇到了兩三次SQL Injection,這篇簡單描述當發生之後,
除了把資料庫恢復到正常狀態,還能多做些什麼。

1. 簡單介紹 SQL Injection 可能發生原因
2. 被觸發 SQL Injection 可能長的樣子
3. 被動式的防守
4. 主動式的防守

部分防毒軟體會判斷這是木馬網頁,因為文章顯示太多 SQL Injection 關鍵的一些程式碼,所以詳細程式碼改為以下載方式,詳細全文可下載檔案及線上縮圖預覽
全文縮圖 : http://cache.ppt.cc/1/5/d/src_15d2dc862cd9ed3d8f34afd5ef122009.png
檔案:[SQL]淺談SQL Injection發生後 - Dotjum學習筆記- 點部落.rar
本文全部程式碼.rar
 

簡介:

這兩三年來,在跑的整合案,遇到了兩三次SQL Injection,這篇簡單描述當發生之後,
除了把資料庫恢復到正常狀態,還能多做些什麼。

  1. 簡單介紹 SQL Injection 可能發生原因
  2. 被觸發 SQL Injection 可能長的樣子
  3. 被動式的防守
  4. 主動式的防守

 

一.簡單介紹 SQL Injection 可能發生原因

SQL Injection 算是很古老會發生在任何有與資料庫互動的程式方面,
詳細的介紹請大家可以直接參考 胡百敬 老師這篇 SQL Injection (資料隱碼)– 駭客的 SQL填空遊戲(上)
而在現行 ASP.NET 任何一個版本,如果你是使用 SqlParameter 來當作傳值的參數或正當的使用 Store Procedure
發生 SQL Injection 因該是已經低於1%,因為一般的 SQL Injection 都是依靠在使用「串」指令的方式,
而使用 SqlParameter  方式,就算後面被串上不乾淨的指令,也是被當做一個「值」傳入,而不會變成一串新的指令。
所以只要在 .NET 的開發中使用 SqlParameter ,基本上你已經可以避開基本的SQL Injection

二.被觸發 SQL Injection 可能長的樣子

下面我用一個實際發生的 SQL Injection 來給大家瞭解,這段是從去年發生事件的 IIS LOG 記錄下來的,
當然這是屬於 GET 模式,如果是 POST 模式,那 IIS LOG 是無法記錄到這段。

所以在Get方式會在Log中看到這樣的方式  abc.aspx?id=1234;dEcLaRe @s vArChAr(8000)sEt @s=0x4465636c61,
攻擊的指令為了要讓你看不懂所以他是用Binnay型別,所以要先把這串字,轉回來 varchar型別來瞭解他做了什麼

http://ppt.cc/cut/data/2/4/0/240f74d97fadcc81c7831d6580a2d00945820ade.png

 

再來就可以看出來,這段本來看不懂的指令,他做了哪些事情,
因為怕大家直接把TSQL複製就貼到自己環境執行,所以我把本來命令是 exec 的關鍵字換成 PRINT
而會塞入的 script 換成空白字串,以防止大家按錯。

所以可以看到以下的指令,就是透過 Cursor 的方式,來批次的把欄位中 char 的欄位進行 UPDATE

 


-- 2.我把他轉回來 (我把本來 exec 改為 PRINT 、Script髒字改為空白字串來做顯示的測試)

-- varchar 轉為 binary

print cast

('Declare @T Varchar(255),@C Varchar(255) 

Declare Table_Cursor Cursor For Select A.Name,B.Name From

 Sysobjects A,Syscolumns B Where A.Id=B.Id And A.Xtype=''u'' And 

(B.Xtype=99 Or B.Xtype=35 Or B.Xtype=231 Or B.Xtype=167) 

Open Table_Cursor Fetch Next From  Table_Cursor Into 

@T,@C While(@@Fetch_Status=0) Begin PRINT(''update [''+@T+''] Set [''+@C+'']=Rtrim(Convert(Varchar(8000),[''+@C+'']))

+'''')Fetch Next

 From  Table_Cursor Into @T,@C End Close Table_Cursor Deallocate Table_Cursor' 

as binary)

-- 這段語法是透過指標用法來查出每個欄位在透過update方式

Declare @T Varchar(255),@C Varchar(255)

Declare Table_Cursor 

Cursor For Select A.Name,B.Name From Sysobjects A,Syscolumns B

 Where A.Id=B.Id And A.Xtype='u' And 

/*

ntext        99 text     35 varchar       167 sysname   231

*/

(B.Xtype=99 Or B.Xtype=35 Or B.Xtype=231 Or B.Xtype=167) 

--@T 為資料表名稱

--@C 為欄位名稱

Open Table_Cursor Fetch Next From  Table_Cursor Into @T,@C 

While(@@Fetch_Status=0) 

Begin 

print('update ['+@T+'] Set ['+@C+']

=Rtrim(Convert(Varchar(8000),['+@C+']))+

''髒的script''')

Fetch Next From  Table_Cursor Into @T,@C 

End Close Table_Cursor Deallocate Table_Cursor

 

在看完上面的這段程式碼,已經瞭解當會傷害系統的 SQL Injection 的長相為何,接下來來說明一下防守的技巧。

 

三.被動式的防守

在前面有說到「只要在 .NET 的開發中使用 SqlParameter ,基本上你已經可以避開基本的SQL Injection」,而如果你的情況,
是面臨到許多不同時代、不同廠商、不同時間點,在同一個主機下,無法在確定每一個程式是不是都使用正確的傳值方式,
而不是使用「串」指令的方式,那可能你適合以下幾種被動式防守。

  • 為有問題的系統開大小帳號,大帳號有寫入更新指定欄位的權限、小帳號只能讀取,而透過兩組帳號方式,如果是.asp就去每一個.inc (include)去增加一組新的連線,把呼叫建立 conn 的地方,依狀況來判斷給予哪一組連線帳號。(.NET也是依照這樣的方式,但這樣真的是「很被動的防守」)
  • 在連線字串中,加入 Applicaion Name 依照你的狀況來定義一個識別值, 這樣可以透過SQL Server Profiler,來確認出是哪一個系統或程式有這個漏洞。(這個狀況適合在當資料庫帳號散分在各地,已經無法統一管理,屬於「被動的防守」)
    詳細的使用請參考 Lolota 大的這篇 [KB]如何讓DBA精準的掌握效能不好的網頁?
  • 最後一招,就是依照上面那段 SQL Injection 來見招「猜」招,禁止使用 sys 系列的查詢資料表

在上面那段傷害系統的 SQL Injection ,可以發現要執行批次更新,關鍵是能不能查詢到 Sysobjects Syscolumns  這兩個資料表,如果能先關閉這兩個 Sysobjects Syscolumns 資料表查詢的權限,


DENY SELECT

ON Syscolumns

TO  你的帳號

GO 

DENY SELECT

ON Sysobjects

TO 你的帳號

GO

這樣的話,一般的 SQL Injection  來做這種加髒的script,批次更新指令就會失敗,

然而目前帳號這個權限,當被DENY某些權限後,

是無法自己下 GRANT 去開啟權限(因為不是sa、dbo、實體擁有者、information_schema、sys),

所以這個方法是被動的防守在混亂的系統環境中,能比較算是正向的方法之一,但只能先防止資料被竄改,
然後多出時間來想辦法,找出系統真正的問題

  

四.主動式的防守

而主動式的防守,要實際深入問題的地方,進行修正才能真正一勞永逸,解決系統的問題,
「被動式防守」只能擋過一時,但能撐多久, 沒有人可以給你一個真正的答案。
而我記錄下來屬於主動式防守招數

  • 重新瞭解有問題系統是否正確傳值 使用 SqlParameter 來當作傳值的參數或正當的使用 Store Procedure
  • 資料帳號權限在運行時,就先定義好 UPDATE 與 INSERT 資料表的權限範圍
  • 如果是一般運作的系統,加裝上 URL Scan 來做第一層的防守,過濾掉有問題的字眼

 

結論:

SQL Injection  慘案是每一天都在上演的悲劇,而根據自己的觀察,類似有機器人的方式批次的跑每一個網站的特定網頁,
可能是定時的執行,這個月來一次,下個月有空也來一次,而當發生的時候,除了趕緊恢復資料的正確性外,
被動及主動的防守,這幾招就給大家參考參考,畢竟是從程式設計的角度來看,有些觀念不是很完全正確,
就請以參考的角度,在依自己實際狀況,來做有效率的改善。

 

參考資料:

How To:使用 URLScan

SQL Injection (資料隱碼)– 駭客的 SQL填空遊戲(上)

[KB]如何讓DBA精準的掌握效能不好的網頁?