在某次测试,遇到一OA页面存在验证码复用,本想可以直接水个洞交差了,但密码字段是加密,没法直接水洞,故做个笔记。
0x01 INFO
如图,js加密函数调用为:desEncrypt(document.forms[0].newPassWord.value)
而且调用加密函数时,会发起一个ajax请求,同时服务端返回一串js代码。
分析发现加密函数:desEncrypt()定义在:[security.js]文件中:
把[security.js]保存,格式化一下。
Look look发现,该js文件中定义了 aes/des加密调用过程:
进行加密前,先向 [https://demo.xxx.com/resource/js/session.jsp] 发起请求,服务端返回包含当前SessionId的js,并将SessionId作为安全秘钥进行aes/des加密运算。
继续look发现,修改密码页面返回的数字有识别度:1为验证错误,2为原密码错误
0x02 刨析
服务器后端会先校验验证码是否正确,然后再校验原密码正确性,正确后再进行下一步-修改密码,由于验证可复用(只要前端页面不刷新,验证码就不会失效),因此可以重复发起请求去验证原密码:当返数字非1、非2时则可能是原密码校验成功。
关于密码字段加密,可通过调用desEncrypt()进行加密。
0x03 准备
1、phantomJS;
2、jsEncrypter - jsEncrypter_des.js;
3、保存标站点的【 security.js、base64.js、aes.js】;
4、拦截登录请求包,Ctrl+R,放掉当前拦截的数据包,重复发送,复制返回内容。
5、新建getSessionId()方法,写入返回的 SessionId值(每次变更后都需要修改):
注释引入文件以及ajax请求部分代码,新增内容:
1 2
| str = getSessionId() return str
|
Code:
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
var SECURITYKEY = { toHexString: function(str) { var temp = ""; for (i = 0; i < str.length; i++) { temp += str.charCodeAt(i).toString(16) } return temp }, _2: function() {
str = getSessionId() return str }, supportEncodings: function() { return ["aes", "des"] }, get: function(encodeType) { var str = SECURITYKEY._2(); if (encodeType == null || encodeType == 'aes') { if (str.length < 32) { str += "abcdefghijklmnopqrstuvwxyz1234567890" } str = str.toUpperCase(); var key = {}; key.key = str.substring(0, 16); key.iv = str.substring(16, 32); key.security = "\u4435\u5320\u4d35" } else { if (str.length < 16) { str += "abcdefghijklmnopqrstuvwxyz" } str = str.toUpperCase(); var key = {}; key.key = SECURITYKEY.toHexString(str.substring(0, 8)); key.iv = SECURITYKEY.toHexString(str.substring(8, 16)); key.security = "\u4445\u5320\u4d45" } return key }, getCookie: function(c_name) { if (document.cookie.length > 0) { var cookies = document.cookie.split(";"); for (i = 0; i < cookies.length; i++) { var xc = cookies[i]; var cn = xc.substring(0, xc.indexOf("=")).toUpperCase(); cn = cn.replace(/^\s*/, "").replace(/\s*$/, ""); if (cn == c_name) { return unescape(xc.substring(xc.indexOf("=") + 1, xc.length)) } } } return "" } };
function base64Convert() { return "\u4241\u5345\u3634{" + Base64.encode(arguments[0]) + "}" }
function _0(xForm) { if (xForm == null) { xForm = document.forms[0] } if (xForm != null) { if (xForm.encoding == "multipart/form-data") { return true } } return false }
function _1(str, xForm, isX) { if (_0(xForm)) { return str } else { var val = str; if (str != null && str.length > 0) str = base64Convert(str); if (val != str) { if (isX == true) { val = "\u4645\u5810\u4d40" + str } else { val = "\u4649\u5820\u4d45" + str } } return val } }
function desEncrypt(value, xForm, type) { if (_0(xForm)) { return value } else { var keyObj = {}; if (type == null || "aes" == type.toLowerCase()) { keyObj = SECURITYKEY.get(); value = CryptoJS.AES.encrypt(value, CryptoJS.enc.Utf8.parse(keyObj.key), { iv: CryptoJS.enc.Utf8.parse(keyObj.iv) }).toString() } else { keyObj = SECURITYKEY.get('des'); value = CryptoJS.DES.encrypt(value, CryptoJS.enc.Hex.parse(keyObj.key), { iv: CryptoJS.enc.Hex.parse(keyObj.iv) }) } return keyObj.security + value } }
function base64Encode(str, xForm) { return _1(str, xForm) }
function base64Encodex(str, xForm) { return _1(str, xForm, true) }
function getSessionId(){ return "53AD650E8542F6E2723515913D104FC2" }
|
6、burpsuite 加载 jsEncrypter 插件,编辑脚本 jsEncrypter_des.js:
运行phantomJS 测试可用性(使用gitbash,避免乱码显示不完整)
1
| phantomJS jsEncrypter_des.js
|
加密后的密码有特殊字符,无法全部直接填充使用,把git bash中输入内容保存为txt,去除【特殊字符】和【==】再导入即可。
0x04 验证
it’s great!