一次完整的代码审计

一次完整的代码审计

编程入门访客2021-10-07 0:17:004840A+A-

发个去年的存稿

前言:因为本人一直活跃于教育 SRC, 所以本次针对的系统也是各大高校所使用的 系统。系统名称:某一卡通门户系统

正文: 0x01: NET 平台下的源码挖掘

个人非常喜欢针对于.NET 和 JAVA 平台所开发的程序做测试,相反,对 于 php 就是一窍不通了。。。。 在针对 NET 平台,因为大部分使用的都是 IIS 中间件,对大小写不敏感,所以在生成字典的时候也会方便很多。 由于 NET 平台的特性,大部分程序的源代码都会打包成程序集,存储在根 目录下的 bin 目录。这导致了部分运维喜欢备份 bin 目录,且将备份过后的 文件存储于网站根目录下,若攻击者使用事先准备好的字典,就可以轻而易举 的获取到源代码。

示例:使用御剑批量扫描资产

得到的数据还是挺可观的,下载过后的文件可以直接使用 dnSpy 进行逆向,查看 源代码
0x02:.NET 代码审计之 - 文件上传

在某个站点下获取到一卡通的 bin 目录。使用 dnSpy 进行了逆向。

初步分析了两个文件,WebController 为主页的控制器。

ManagerController 为管理页的控制器 两个页面的路由规则如下: WebController: 控制器名 / 方法名 ManagerController: Manager / 控制器名 / 方法名

一般的 Manager 控制器下面的都会有登录过滤,可以后面再看。 这里先看 WebController 下面的功能

有很多控制器,看命名方式,还是能确定不少功能的。
其实,在开始审计前,我都喜欢看一下 Filter 过滤器,里面的功能。 在过滤器中,有一个 SqlFitler

大概功能就是捕捉 get 和 post 请求里面的敏感参数。比如 单引号’

就会直接拦截。。。。,那么就没有必要去挖 SQL 了。虽然这里也可以绕过,但 是 SQL 注入太麻烦了。一般都喜欢放到最后再挖。

期 间 在 NoBaseController 控 制 器 下 面 发 现 了 一 处 文 件 上 传 操,upshallfile 方法中,定义了一处文件上传功能。具体展现在第 59 行,进行 了文件存储操作,期间并未进行任何文件类型效验操作。


流程分析:
方法中,第 5,6,7 行代码声明了三个字符类型的变量。该变量的值从 http 请求头的属性获取

text 变量获取请求头中的 path 属性,默认值为 “~/”。
text2 变量 获取请求头中的 sign 属性。
text3 变量获取请求头中的 time 属性。 第 10 行 - 17 行,判断 text2 是否为空。如果为空。返回签名失败

第 18 行 --27 行。进行了一个效验操作

时间类型变量 d 的值为 text3 变量转换成时间的内容。
时间类型变量 d2 的值为 当前时间转换成 yyyyMMddHHmmssff 格式的内容 那么这里可以得知: text3 的内容是由请求头中的 time 属性决定。
time 属性 传递内容必须为时间且为 yyyyMMddHHmmssff 格式。
第 20 行:如果 当前时间 减去 传递进来的时间 大于 10 则返回签名超时
这里只需要大于 10 就可以。那么可以直接定义传入时间为 2099 年。这样就一直 可以使用。
第 28-38 行,则是对文件效验码的操作。

29 行中的 声明了一个 strMd 变量 其 值为 进行 md5 加密后的内容。

要加密的内容如下:

file.FileName (文件名称) :service.asmx

text : 由 http 请求头中的 path 属性决定

text3: 由 http 请求头中的 time 属性决定

Synjones 为进行 md5 加密所附带的 salt。
将以上内容加密后。与 text2 变量进行对比。如果不相等。那么返回签名校验失败。
如果相等则进入 59 行的文件存储操作。
已知 text2 变量的内容由 http 请求头中的 sign 属性决定
那么只需要将定义好的内容进行加密然后赋值给 sign。就可以绕过了。
这里可以直接把 InterFaceMd5Helper.GetStrMd5 这个方法拖出来到本地调用进行加密操作。
其中
第 59 行调用 text 变量。

也就是说 text 为文件存储路径。

那么构造加解密方法:


得到 Sign 的值。

构造 POC:

POST /NoBase/upshallfile HTTP/1.1
Content-Type: multipart/form-data; boundary="6e9cb0ae-23eb-49bf-92d6-16dcbb95bd8a"
time: 2099070800284040
sign: B041E90676E936521F2B967770314C56
path: ~/

0x03: 任意账户登录
在 LoginController 控制器 下面的 QrCodeLogin 方法中,其功能为扫码登录。该功能最终效验不是传统的账号密码验证,而是账号加密过后的内容。当攻击者掌握加密规则后,可构造参数结构,导致任意账户登录。

流程分析:

QrCodeLogin 方法下面的操作。要分为两个结构。

第一段结构:

第 1 行 - 44 行:账户效验。

第 45 行 - 84 行:将账户带入,请求终端查询。

这里要注意: 45 行以后的操作就不再由程序接管了。具体可以看 GetTsmCommon 方法.

所以这里只分析 45 行之前的操作。

第 7 行实例化了一个对象。这个对象是空的。无任何内容。后面是用来存储用户信息的。

第 10 行接收 POST 请求传递进来的参数 account 并将内容赋值给 text 变量

整个方法。只接收这一个参数。所以,只需要追踪哪里调用了 account 就可以了。

第 11 行 - 17 行中进行了判空操作,如果 account 内容为空。则返回账号为空。

第 19 行 - 25 行进行了解密操作。如果解密失败则返回账户解密失败。

可以看到 第 18 行

string text2 = DesEncryptHelper.Decrypt(text);

进行了解密操作。追踪这个方法。

DesEncryptHelper 类中,包含了解密和加密的方法。所以后续可以直接拉出来调用。

第 60 行中可以看到。

调用了 Decrypt 解密方法 并传递了一个 Key 为 SYNJONES 。

那么等会加密的时候。也需要带入这个 Key。

回到 QrCodeLogin 方法

第 26 行 - 33 行。

分别对解密后的内容进行了切片操作。

第 26 行:以 “_” 为分隔符进行拆分。取第一个内容的值 赋值给 text3

第 30 行:以 “_” 为分隔符进行拆分。取第二个内容的值 赋值给 value

第 34 行:声明时间变量 d , 值为 转换成时间格式的变量 value 。

那么这里已知 value 是时间
第 35 行:声明时间变量 d2 值为当前时间
第 36 行: d2-d 当前时间减去传入时间。如果大于 120, 则返回超时。

若符合。则执行下面的操作。

第 45 行。将参数带入了 Jsonrequest 变量中。第 53 行进行了一次外部请求。这里我不需要过多深入。因为下面的操作已经无法人为控制。这里只需要知道,text3 的内容是账号。
且传入进去的账号必须存在。

那么最终加密的格式为

账号_时间 时间为:"yyyy-MM-dd HH:mm:ss" 格式

将加解方法单独拖取出来调用。

构造加解密方法:

构造 POC:

POST /Login/QrCodeLogin HTTP/1.1
Host: *******

account=B7D7D43C8166BCB4540FF2464842485E3383D6CA04041C7F


成功登录

点击这里复制本文地址 以上内容由黑资讯整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

支持Ctrl+Enter提交

黑资讯 © All Rights Reserved.  
Copyright Copyright 2015-2020 黑资讯
滇ICP备19002590号-1
Powered by 黑客资讯 Themes by 如有不合适之处联系我们
网站地图| 发展历程| 留言建议| 网站管理