前言
前几天写了篇突破某线上教育平台身份校验的文章,当时中午没睡觉,写的时候非常的困倦,很多地方可能表达的不是那么清楚,但是我也懒得去改了。今天正好休息,我写一篇审计这个线上教育平台最新版本的身份校验漏洞的文章。(本次代码审计均在本地搭建的环境进行)
上次那个版本已经是2017年的版本了,审计完之后一直心里有个疑问,不知道作者在2020年的版本中有没有修改他的校验方式,于是就有了今天这篇”就算有DES加密和session校验我也要进入你的心“。
在最新版本中,作者可能已经知道了cookie校验的危险,所以新版本他改成了session+cookie+des加密校验,但是正所谓“道高一尺,魔高一丈”,即使校验方式已经如此的繁杂,但终究还是没有逃过我的掌心。
正文
0x00 .NET反编译工具
这里我用的是.NET Reflector10,是一款功能强大的.NET反编译工具,使用.NET Reflector,可以反编译和调试.NET程序集和可执行文件,并将源代码反汇编为您选择的.NET语言,以便查看.NET程序集的内容。开发人员使用.NET Reflector来进行各种操作,如使用Visual Studio调试器调试程序集,即使没有源代码也是如此,动态反编译任何.NET代码,可进入第三方代码,设置断点并观察它运行,给他们一个强大的对象浏览器来浏览Visual Studio中的代码,支持恢复丢失或不可用的源代码以及查找性能问题并分析依赖性。
在审计编译之后的.net代码的时候,第一件事应该就是找对应web页面的inherits参数,这个参数告诉了我们该页面引入了那个dll文件,通过他就可以定位dll,然后将dll文件拖入.net reflector中就可以开始正常的审计了。
0x01 审计过程
这里我选择直捣黄龙,直接寻找管理员登录入口,然后从登录入口的身份校验开始审计。
如图,该系统的管理员登录入口和教师登录入口是同一个入口,我们就先从Teacher/index.aspx开始审计
打开Teacher/index.aspx。找到其对应的inherits为Teacher_index,然后我们就可以去.net reflector中去搜索对应的类,如下图步骤所示。
然后我们点击上图所示的expand methods 把方法展开,就可以看到里面具体方法的使用了。
展开之后可以分别看到三个关键的函数,分别是cookieJump()、LoginCode()、Page_Load()三个函数,从名字中就可以看出来CookieJump函数是通过cookie来进行页面跳转和身份判断的函数;LoginCode则是判断用户输入的用户名密码的函数;而Page_Load()函数则是进行页面加载的函数。我们先从cookieJump函数看起。
开发者使用Teacher对象和其中的Hpermiss,传入了SetTMCookies函数中,判断返回值再之后再判断teaCookieNname或者mngCookieNname进行不同身份的跳转。那我们跟进SetTMCookie函数,看看他是个啥
跟进函数之后发现,其作用是通过permiss的值判断用户是管理员还是教师,然后调用SetManagerCookies函数或者SetTeacherCookie函数来设置cookie。既然我们要突破的是管理员权限,那我这里自然就跟进SetManagerCookie。
这里首先创建了key为mngCookieNname的cookie,至于mngCookieNname是啥,我上个文章已经说过了,如下图所示:这个值是根据配置文件和用户身份计算出来的两个字符串拼接之后的结果。但是我们通过学生身份登陆进去之后,只要修改一下首字母,将S改为M就可以成为mngCookieNname。
从上上张图可以看到这个函数将传入的Teacher对象中的值放到了cookie中,但是他调用了一个非常奇怪的ToStr()函数,这个函数并不是内置的转换string的函数,而且他启用了session,看到这里,我内心一紧。感觉要凉了。
看到了设置session的值,吓得我赶紧去看了一眼Page_Load()函数,看看他到底有没有进行校验
这里可以看到,如果是管理员身份就跳转到Manager/index.aspx,至于他这个IsManagerLogin()函数我们根本不用管,因为我们没有通过输入密码的方式去登录,所以直接去找Manager/index.aspx这个页面所继承的类。
可以看到再Manager_index类中,Page_Load()函数调用了JudgeIsAdmin()函数,通过名称我们就可以猜测到,其是判断管理员身份的函数。我们继续跟进!
进去之后一看,卧槽,凉了。这里开启了session校验,但是这代码我越看感觉越不对劲,一开始我想不出来哪不对劲,但是就是感觉不对劲。突然之间,灵光一现,思绪如泉水般涌出大脑,卧槽,这尼玛代码不对啊,通过sessionid和cook对象(也就是处理过后的cookie对象)中的sessionid进行判断,但是sessionid只要我登录了就有一个不会变化的sessionid,那么也就是说我想要伪造管理员身份,只需要伪造一个名字为mngCookieNname的cookie,然后其中的参数sessionid等于我现在登录之后的sessionid,Hpermiss为true就可以了。
打个不恰当的比方,这相当于我拿着别人的credit card去bank取钱,bank不管我身份是谁,不管我有没有密码,不管creadit card的户主是谁,只问我知不知道card的卡号,知道card卡号,就可以取钱。
正当我得意之时,一个坏消息映入了我的眼帘。
在浏览器中观察这个cookie对应的值,这这这。。。。这怎么不对劲,为什么不是明文,为什么是一串毫无规则的,疯狂字符串?
突然之间,我想起来上面SetManagerCookie()函数中调用的那个诡异的ToStr()函数。点进去看看。
我叼,他在设置cookie的时候用了des加密。大哥至于的么。走都走到这一步了,执着的我又怎么会轻言放弃,那必须得继续跟进,有加密就有解密,既然是des,那密钥必定会有。
跟进DesCode类,发现了密钥和对应的加密解密方法。继续跟进。将加密、解密算法粘贴到本地修改,以便一会利用。
<----省略本地修改代码过程---->
将算法copy到本地修改之后,现在我们已经知道了绕过身份校验的条件。
- 必须要有key为mngCookieNname的cookie
- cookie中的Hpremiss应该为true
- sessionid和cookie中的session要一样
- 必须现有一个登录状态的sessionid(不等录的情况下sessionid是会改变的)
- 还要将修改之后的cookie进行DES加密
0x02 绕过
首先是一个坏消息,开发者没有给学生的cookie中设置sessionid,但是老师的cookie是有的,所以我们不能再通过学生的身份进行绕过了,但是可以退而求其次使用老师的sessionid。
这里可以轻松获取老师的sessionid,然后我们需要使用本地修改的des加密,进行cookie的伪造
Hpremiss和sessionid修改为对应的
再一次bingo
0x03 改进建议
1.将sessionid校验改为session值校验(此为突破权限的核心)
2.不使用cookie校验