电脑疯子技术论坛|电脑极客社区

微信扫一扫 分享朋友圈

已有 1988 人浏览分享

关于一次测试中的加密算法解读

[复制链接]
1988 0
本帖最后由 zhaorong 于 2021-7-9 17:26 编辑

前言

在一次渗透测试过程中 偶然发现了返回包里面出现了加密算法 在查询诸多资料之后 费劲千辛万苦
又使用编码后的密码进行反推,最终有了这篇文章 。

一、追踪加密函数

打开测试网站,仔细观察返回包中发现username和password两个参数调用了getBase64Data函数。

QQ截图20210709170918.png

在返回包下面使用搜索getBase64Data函数 发现对应的加密算法。

QQ截图20210709170951.png

二、for循环之前的函数解读

代码为:
  1. function getBase64Data(data){
  2.         var base = new Base64();
  3.         var newDataArr = [];
  4.         //form data is json object
  5.         var formDataArr = base.encode(JSON.stringify(data)).split("");
  6.         var forLength = formDataArr.length * 2;
  7.         for (var i = 0; i < forLength; i++) {
  8.             if (formDataArr.length == 0) {
  9.                 break;
  10.             } else {
  11.                 if (!(i % 2)) {
  12.                     newDataArr.push(Math.random().toString(36).slice(-1));
  13.                 } else {
  14.                     newDataArr.push(formDataArr[formDataArr.length - 1]);
  15.                     formDataArr.pop();
  16.                 }
  17.             }
  18.         }
  19.         var h = Math.random().toString(36).substr(2, 4);
  20.         var f = Math.random().toString(36).substr(2, 8);
  21.         return h + newDataArr.join("") + f;
  22. }
复制代码

首先我们来解读一下这段代码 其中创建了两个数组对象 分别为newDataArr和formDataArr 我们看看结尾return
返回了newDataArr 说明newDataArr才是我们要注意的变量 fromDataArr是中间过渡需要用的变量。
其中var formDataArr = base.encode(JSON.stringify(data)).split("") 这段代码首先对传过来的参数使用了J
SON.stringify()方法该方法用于将 JavaScript 值转换为 JSON 字符串 这个只是对传过来的值做了引号引起来
然后使用base()来做base64编码 最后使用了split(separator,limit方法将base64编码后的字符串拆分成一个
数组如果把空字符串 ("") 用作 separator 那么 stringObject 中的每个字符之间都会被分割。

也就是说我们从前端输入一个账号user10 先是对user10做了双引号引起来成了 user10 然后在做base64编码成了
InVzZXIxMCI= 这个等号在加密后没看出来 在加密算法也没看出去除等号 查了base64编码资料发现=可忽略。
参照资料:
Base64编码要求把3个8位字节 3*8=24 转化为4个6位的字节 4*6=24之后在6位的前面补两个0
形成8位一个字节的形式。 如果剩下的字符不足3个字节 则用0填充 输出字符使用'='因此编码后
输出的文本末尾可能会出现1或2个'='。

三、for循环的解读

继续往下看代码 var forLength = formDataArr.length * 2这段代码定义了数组的长度 用于后
面的for循环 乘以2也是让循环能够执行完 因为for循环里面有个break跳出终止 如果formDat
  1. aArr.length == 0的话 循环会终止。
  2. for (var i = 0; i < forLength; i++) {
  3.             if (formDataArr.length == 0) {
  4.                 break;
  5.             } else {
  6.                 if (!(i % 2)) {
  7.                     newDataArr.push(Math.random().toString(36).slice(-1));
  8.                 } else {
  9.                     newDataArr.push(formDataArr[formDataArr.length - 1]);
  10.                     formDataArr.pop();
  11.                 }
  12.             }
  13.         }
复制代码

接下来再查看for循环执行了什么内容 for循环使用forLength为循环最大值 而且formDataArr.length == 0时会跳出
如果不跳出的情况下执行一个条件语句 这个条件语句为:如果i是奇数的话生成一个随机数插入到newDataArr数组里面其中
slice(-1)意思是截取最后一个字符 push()方法是向数组的末尾添加一个或多个元素 意思是说i是奇数的话会往newDataArr里
面输入一个随机字符而i是偶数的情况下 会将formDataArr[formDataArr.length - 1]也就是formDataArr的最
后一位字符输入newDataArr 由于使用了pop()方法 这个方法是删除最后一个字符 也就是说下一次循环就会得到form
DataArr里面的倒数第二个字符了 以此类推 将formDataArr数组里面的字符全
部写进去newDataArr里面。

考虑到栈入栈出的问题 push()方法会在栈顶 数组的尾部 添加指定的元素 也就是说即使是从后往前添加formDataArr的
字符串 formDataArr也就是前端传进来的做了base64编码的字符串使用split()方法形成的数组 push()方法也是先加到
newDataArr的尾部从后往前添加,加密后的顺序没有改变的。

四、for循环之后的函数解读
  1. var h = Math.random().toString(36).substr(2, 4);
  2. var f = Math.random().toString(36).substr(2, 8);
  3. return h + newDataArr.join("") + f;
复制代码

最后我们看这段代码Math.random().toString(36).substr 2, 4 这个参考了文章 里面没提到toString36
什么意思 这个是输出36进制的意思 然后使用了substr()方法从第2位截取4个长度的字符赋值给h,截取8个长度的
字符赋值给f,这个Math.random()是一个随机数 其实这些都不用太过考虑,参考文章中这个Math.random
().toString 36
说明它可以输出16或者17个随机字符串也就是说不管是4个还是8个字符串都是够截取的看最
后一串代码是return h + newDataArr.join("") + f 也就是说加密后的密码只要去掉前面的4位和后面的8
位就可以得到newDataArr.join("")join(separator用于把数组中的所有元素转换一个字符串 其中
separator指定要使用的分隔符。如果省略该参数 则使用逗号作为分隔符。

接下来我使用了burpsuite对目标抓取前端输入了用户名user10之后
得到了以下3组加密后的字符串:
  1. 7kv5bIvndVczhZcXhIfxsMuCwI121wwl12
  2. fuh7jIinkVpztZ6XxI5x9MtC6In0zobdxj
  3. awjwhI4n8VwzdZeXqIvxkM3CeI9pvs94cc
复制代码

获得多组字符串是为了验证这个结果是否正确 去掉前面4位和后面的8位随机数之后得到:
  1. bIvndVczhZcXhIfxsMuCwI
  2. jIinkVpztZ6XxI5x9MtC6I
  3. hI4n8VwzdZeXqIvxkM3CeI
复制代码

根据循环得出奇数只是随机数 偶数才是编码后的字符串 去掉奇数位之后得到了lnVzZXlxMCl 再使用base64解码
之后即可得到 user10 因为这个是使用了JSON.stringify()方法 该方法用于将 JavaScript 值转换为 JSON 字符串
所以去掉双引号之后即可得到user10了。

后续

其实javascript很多方法我也不是很懂 文章是从前面分析 解密的思路却是我一步步逆推回去的 首先是看到
Math.random().toString36 这个函数 因为这个函数影响了最后的return输出的值 然后查了文章才发现是
一个随机数而已 加密后的字符串在前面和后面的加上了同等数量的字符串,那么减去就可以了然后再去思
考for循环的内容了 这里还是可以看出for循环想要执行的内容的 奇数为随机数偶数才要用到formDataArr
所以最终加密的去掉奇数位的数字就可以了 可是最终得到的结果是lnVzZXlxMCl 然后我去查了这个JSON
.stringify()
才知道是对输入的内容加了双引号 当时还因为循环的执行思考了半天,因为这个push()方法的
栈入栈出问题 从formDataArr里面由后往前取字符 然后往newDataArr里面也是由后往前放 所以加密后的
字符串顺序没有变化。

您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

关注

0

粉丝

9021

主题
精彩推荐
热门资讯
网友晒图
图文推荐

Powered by Pcgho! X3.4

© 2008-2022 Pcgho Inc.