freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

渗透测试之前端JS加密浅析
2023-05-11 10:53:31
所属地 四川省

前言

本文主要记录常规JS加密方法的判断以及如何定位加密方法,并进行扣取执行的方法等,如果有错误的地方,还望指正,不喜勿喷;

在日常渗透测试中,当遇到登录接口时,通常会进行弱口令以及注入等方法进行安全测试,然而当目标站点对敏感参数进行加密后,会增加我们安全测试的难度,因此需要对前端JS进行分析,跟踪加密过程、判断加密方法、判断是否加盐,从而编写脚本对接口进行安全测试。

在Burp Suite中有一些HASH的算法以及其他大佬编写的加密插件,可以满足一部分测试需求,但对于JS中加密方法DES、AES、RSA以及一些自研加密方法还是需要自己动手调试找key等操作,因此我也去学了一下,以下内容算是学习记录。

快速判断加密/散列算法

1、通过密文判断

仅列出常用的,以下为密文123456的密文(未加盐的情况下):

//散列
MD5:e10adc3949ba59abbe56e057f20f883e
SHA1:7c4a8d09ca3762af61e59520943dc26494f8941b(40位)
SHA256:8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92(64位)
SHA512:
ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413(128位)

//编码
BASE64:MTIzNDU2
BASE32:GEZDGNBVGY======
Unicode:\u0031\u0032\u0033\u0034\u0035\u0036

//加密算法(DES/AES/RSA)一般密文无规律,常见在前端输出时会进行base64编码后在输出,对称和非对称都是16进制的形式,最大的字母只到了F那就说明可能是。

2、通过F12

访问站点F12,当提交数据时查看network加载资源,有时会看到加密方法,如下:

01

还有一些加密库jsencrypt、crypto-js等都可用做判断加密算法。

如何快速定位加密JS代码位置

1、搜索关键字

使用浏览器自带的search功能,定位的位置比较准确, 搜到的位置比较多, 要自己进行筛选, 容易搜不到;

在搜索一个对象时可以使用以下定义方法进行搜索,可以过滤掉一些不必要的结果:

var object
function object
object:
object :
object =
object=   //代码没格式化之前的样子

其他关键字:encrypt、passwd、password、MD5、AES、DES,登录加密的参数名是什么就先搜参数名,搜不到在搜其他关键字,框架的js文件(jquery等)可以不用看,重点看自写的JS文件,定位到大概位置后下断点跟值查看;

2、XHR断点

代码运行时间轴:加载html--加载js --运行js初始化 --用户触发了某个事件--调用了某段js--明文数据--调用加密函数 --加密数据--send请求(XHR--send)

执行比较靠后,距离加密函数相对比较近,可以根据栈快速定位,但是非XHR发送的数据包是断不住的。

example

http://www.example.com/adminlogin

将后面固定的路径 adminlogin,添加到XHR/fetch Breakpoints中,在提交请求,此时会被断住,就可以通过栈进行分析;

04

方法栈(从下往上运行),它遵从后进先出(LIFO——Last In First Out)原则,通过跟栈可以快速定位到加密点,找到密文和明文之间的代码,大概率为加密方法的位置。

3、dom事件断点

代码运行时间轴:用户输入明文 -》经过一些方法 -》加密函数 -》拼接封包 -》发包函数 -》浏览器的发包函数

定位的位置比较靠前,定位到的通常是用户输入的明文,需要跟值才能跟到;

05

在event Listeners中查看事件,找到登录事件(找不到时候可以通过删除事件,点击登录查看是否登录按钮有效进行排查找出事件),从后面指向的js文件跟进去,简单分析后在比较像加密的地方下断点,点击登录后跟值。

定位以及扣取案例

找了几个站发现都是基于加密库jsencrypt、crypto-js的案例不太好,这里只做练习,不在乎有没有意义,苦笑;

提取的时候通常会直接把整个js先提取到本地,然后再提取加密方法出来,然后本地运行缺什么在补什么,另外webpack 框架的提取方式和常规的还有一定区别。

需要注意的点:

  • 作用域的问题

var _hex_md5;    //将局部变量导出才能在全局使用
!(function(){
var j = {
hex_md5:function(){
console.log("1");
}
}
_hex_md5 = j;   //导出
})() //自执行
  • 提取代码完整

var class = {
name:"test"
md5:function(args) //不能光扣md5这部分需要把this一起提取出来才有用,var开始到最后才是一个整体
{
console.log(args)
}
}

RSA

RSA特征:

new JSEncrypt();
a.setPublicKey("key");
a.encrypt(passwd);

new rsa的加密对象
xxx.set设置publickey     //设置公钥
xxx.调用加密方法(“明文”)  //加密
以上三步是RSA加密必须的,跟值得时候也需要在这三个地方打上断点,扣代码运行也要这三点;

在登录时,查看network可以看到password参数是加密的

06

个人觉得XHR定位比较方便,但是这里可以看到type是document,因此无法使用XHR断点进行跟栈;

07

使用搜索进行定位,使用network左下的search搜索关键字encrypt,可以看到有五个结果,最后一个JS文件中的是我们想要拿到的;

08

点击169行跟到JS文件中查看,并在三个特征处下断点,再次点击登录跟值查看,可以看到在166行的时候还是明文,在173行就输出了密文,因此加密方法是处于166-173行,当然这里也能很清楚的看到e.encrypt(passwd)方法对明文进行加密,可以使用console调用这个方法尝试一下加密(只有在断住后才能使用console进行调用),可以看到加密成功。

09

那么这里已经很清晰了,e调用了encrypt进行加密,而e = ze{},我们这里把ze取出来就可以了,选中JSEncrypt,根据指向的文件进入js文件中;

10

进入jsencrypt.min.js后,查看,注意在var的前面还有空格,那就说明它是在一个大方法中,不出意外的话,我们把这个大方法抠出来,在按照上诉特征三个步骤去调用就可以了;

11

鼠标放到var上,然后一直往上滑,直到看到一个顶格的function,然后扣出来就可以了,另外正常的RSA代码在2000行左右;

12

大方法拿出来后在JS调试工具中运行,运行会提示navigator is not defined以及window is not defined,我们在首行增加以下代码即可:

navigator = {},window = this;

13

接下来构造调用函数,比较方便的是学着目标网站构造调用函数就行了,网站怎么写你就怎么写,不会错:

function rsaPass(passwd)
{
var e = new JSEncrypt();  //RSA三大步
e.setPublicKey("key");
return e.encrypt(passwd);
}

构造出来后我们发现此处还缺少key,我们在到网站的JS里去找一下看看对方是怎么传的,找到调用位置,可以看到170行,它的含义是将ID为"e"的HTML元素的值作为公钥,并将其设置为某个对象的公钥。

14

我们可以到前端HTML进行查找,搜索#e,定位到key

15

最后调用测试,RSA加密同一字符串时,每次生成的密文通常是不一样的,这是因为RSA加密算法中,每次使用的随机数都是不同的,而随机数会影响到加密过程中的一些计算,从而导致密文的差异。

16

DES

DES特征

(function () { // 定义一个立即执行函数
const message = "123456"; // 要加密的明文
const key = "ffffffffffff"; // 密钥

// 将密钥从字符串转换为字节数组
const keyBytes = CryptoJS.enc.Utf8.parse(key);

// 使用 DES 加密算法加密消息
const encrypted = CryptoJS.DES.encrypt(message, keyBytes, {
mode: CryptoJS.mode.ECB, // 使用 ECB 模式
padding: CryptoJS.pad.Pkcs7, // 使用 PKCS#7 填充方式
});

填充方式以及加密模式不一致也会导致密文不一致;

URL:http://xxx/adminlogin

请求类型是XHR

000

admin 123456的密文

1680158814017

这里使用XHR方法进行定位,在XHR/fetch Breakpoints添加adminlogin路径,再次提交请求,此时会被断住

001

根据栈往下看,先找到密文,在找到明文,在第三个栈(querySessionAttr)找到了密文,第二个栈(login)找到了明文以及密文,还有一串字符,那么加密代码的位置大概可能在这之间,但是这里比较清晰,我们直接在57、58行下断点,然后跟进去看;

002

003

跟进encryptByDES后可以看到DES的特征以及key,实际上到这里就可以将key拿到其他的DES算法环境中进行加密测试,看看密文是否相同,相同基本上就没有在跟下去的必要了。

004

这里我将key拿出来后,在自己的环境进行加密,密文相同。

005

AES

特征:

function Encrypt(xxx){  
var xxx  = xxx.enc.Utf8.parse('key');
var xx = xxx.enc.Utf8.parse(xxx);  
var xxx = xxx.AES.encrypt(xxx);  
}

其他操作也可des差不多。

测试脚本

代码功底太差,写了几个渗透测试用的简单小脚本,需要自己先把目标网站的key拿出来在使用脚本,不同的场景需要对脚本进行微调,主要实现功能如下:

  • DES、AES、RSA批量加密脚本,DES、AES解密

  • AES、DES 配合sqlmap的SQL注入脚本

项目地址:https://github.com/Small-ears/DES-AES_SQL_Scripts

后记

加密库的JS代码,提取出来放到VSvode里面用node运行时候会各种报错,比如ASN1 is not defined,我在目标网站找了半年都没有找到ASN,在https://github.com/travist/jsencrypt里找到了,但是在一些JS调试工具里面却能运行,不会报ASN1 is not defined,可能是环境问题,js代码拿出来调试时候需要注意。

使用加密库的网站只需要找到加密的key以及确认加密方式、填充方式是否有IV,就可以在自己的环境中运行,一般使用加密库也不太会改代码;

# 渗透测试 # 网络安全 # web安全 # 系统安全 # 网络安全技术
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
  • 0 文章数
  • 0 关注者
文章目录