背景:

做授权渗透的时候要求要写明文传输漏洞,这就导致很多没有上 HTTPS 的网站为了修这个明文传输的问题,用尽了各种奇葩的做法,其中见得比较多的就是使用 RSA 或是 AES 对传输的数据进行加密后传输(还见到用 base64 进行编码之后就算修了的)。

但是要知道,加密都是在客户端进行的,而且 AES 是对称加密算法(就算是 RSA 非对称加密,也只是不能解密加密的内容,但有了公钥之后,拿去加密自己提交的 payload 还是可以的),所以只要拦截到数据包,理论上加密的信息都是可以解密的。面对这些掩耳盗铃的修复方式也是很无奈,但是也还是有稍微提高一些攻击成本的。

场景:

最近就碰到一个场景了。 修改用户密码的地方在收取手机验证码的时候注意到验证码只有4位,而且是纯数字,接口还没有对验证码的验证次数进行限制,这就意味着可以进行遍历对任意用户的密码进行重置。 但是还有一个问题就是它对提交的信息都进行了加密

任意密码重置的一个场景

这就意味着,如果需要继续进行下去,就需要绕过加密这道坎。然后我就进行了各种尝试。

第一次尝试:

思路一:对它的加密过程进行逆向,拿到 key 和 vi 值,然后再写个脚本在本地进行加密后再post到目标地址,但是逆了一个多个小时,愣是没搞掂(留下了没技术的眼泪),然后就放弃了这条路。

思路二:把网页的关键内容扒下了,然后在本地调用它预留的加密和处理的接口,再post过去。但是又遇到问题了,一开始以为它的 key 和 vi 值是固定的,就下断点调试从网页上拿到 key 和 vi 值之后就放到本地去做加密处理,但是后来发现它的 key 和 vi 值过几秒就会刷新一次,网页每次请求之前都会获取一次新的。但是本地的网页和目标网站不是同一个源,而且网站的CORS设置也没有问题,所以根据浏览器的同源策略,AJAX 获取 key 和 vi 是不行的,通过 AJAX 去 POST 数据也是不行的。

任意密码重置的一个场景

任意密码重置的一个场景

然后到这里,第一次尝试就已失败告终了(当时项目很急,而且任务量还很大,如果一直死磕这个问题,那后面的就不用做了,所以当时就只能放弃了)

第二次尝试:

过了几个星期,也就是这几天,那个项目要求再做一次测试,鉴于之前已经把问题挖得七七八八了,所以这次就有时间去继续研究下这个问题了。

分析了一下上次的失败,写代码是不可能的,这辈子都不可能,只有当脚本小子才能勉强维持现在的生活。那第二个思路关键点在于解决同源的问题。 想到这个关键点之后就好办了,最直接的方式就是在它的源上运行我的代码。那要怎么才能在它的源上运行我的代码呢?

首先想到的就是在浏览器上修改代码,但是浏览器并没有提供这个功能,那就要把服务器返回给浏览器的数据给修改了,欺骗浏览器去运行,这就要祭出我们强大的 burpsuite 了。

任意密码重置的一个场景

把这个页面的代码拦截下来修改(这个场景很欺骗,手机验证码在这个页面才验证,所以并不是到了这个页面就可以重置密码了):

任意密码重置的一个场景

拦截下来之后稍微加工一下:

任意密码重置的一个场景

这代码的意思是遍历1000到9999(因为验证码是4位),把对应的数值转换为文本后放到提交的数据的验证码字段,再交给它页面本身的加密算法加密后去提交(所以这里我根本不需要知道它加密算法的细节,只管去调用就行了)。

放行之后浏览器就收到这个修改之后的页面,里面已经包含我加入的代码了,剩下就交给浏览器去跑了,几分钟后跑了出来,自动跳转到登录页:

任意密码重置的一个场景

自此,成功修改13800138000用户的密码(之前还有一个任意号码注册的洞,所以当时注册了这个不存在的手机号)。

总结:

很多时候一些代码其实不需要自己手工去一步一步逆,可以借助环境帮你跑出来(一开始我也钻了牛角尖),很多CTF的 writeup 也看到借助环境跑出加密的代码或变量的。 通过拦截和修改服务器的返回包可以欺骗浏览器在指定源上跑自己的代码从而绕过同源策略的限制。

*本文作者:三只小潴