1. Introduction
In the anti-climbing measures used by various websites nowadays, it is very common to use JavaScript encryption. Usually, JavaScript is used to encrypt a parameter, such as token or sign. In this example, this measure was taken to anti-climb, using JavaScript to encrypt a parameter antitoken, and this blog is about how to deal with and solve it.
Second, site analysis
The site link for this crawl is: https://www.ly.com/hotel/beijing53/?spm0=10002.2001.1.0.1.4.17 .
After the page loads, open the developer tools, switch to the XHR option, and find the following request:
Notice that there is an antitoken in the parameter, which is an encrypted string, how do you get this encrypted parameter antitoken?
3. Cracking steps
1. Search encryption method
Globally search for antitoken in the developer tools, find the JS file named list-newest.js, switch to the Sources page, find the JS file and open it, click "{}" in the lower left corner to format it for us to consult, as follows Figure:
Search for antitoken in this JS file, you can find a way to get antitoken by searching, the specific code is as follows:
e.getantitoken = function() {
var t = $.cookie("wangba");
t && void 0 !== t || (t = (new Date).getTime().toString(),
$.cookie("wangba", t, {
path: "/",
domain: "ly.com"
}));
return (0,
r["default"])(t)
}
;
You can see that you want to get a value from the cookie named wangba field, wangba? Internet cafe? Who knows. If wangba is empty, then recreate one, and what is created is actually a 13-digit timestamp.
var t = $.cookie("wangba");
t && void 0 !== t || (t = (new Date).getTime().toString(),
Put a breakpoint on the return line, and then refresh the page for debugging, jump to the return method, as shown below:
In order to know how the antitoken is generated, we need to know the meaning of each parameter n, i, o, r in this function, so we have to continue to break the point for debugging.
The first is n. Know n = a (30) through the code. After breaking the point, find the code corresponding to the n parameter as follows:
n = { rotl: function(t, e) { return t << e | t >>> 32 - e }, rotr: function(t, e) { return t << 32 - e | t >>> e }, endian: function(t) { if (t.constructor == Number) return 16711935 & n.rotl(t, 8) | 4278255360 & n.rotl(t, 24); for (var e = 0; e < t.length; e++) t[e] = n.endian(t[e]); return t }, randomBytes: function(t) { for (var e = []; t > 0; t--) e.push(Math.floor(256 * Math.random())); return e }, bytesToWords: function(t) { for (var e = [], a = 0, n = 0; a < t.length; a++, n += 8) e[n >>> 5] |= t[a] << 24 - n % 32; return e }, wordsToBytes: function(t) { for (var e = [], a = 0; a < 32 * t.length; a += 8) e.push(t[a >>> 5] >>> 24 - a % 32 & 255); return e }, bytesToHex: function(t) { for (var e = [], a = 0; a < t.length; a++) e.push((t[a] >>> 4).toString(16)), e.push((15 & t[a]).toString(16)); return e.join("") }, hexToBytes: function(t) { for (var e = [], a = 0; a < t.length; a += 2) e.push(parseInt(t.substr(a, 2), 16)); return e }, bytesToBase64: function(t) { for (var e = [], n = 0; n < t.length; n += 3) for (var i = t[n] << 16 | t[n + 1] << 8 | t[n + 2], r = 0; r < 4; r++) 8 * n + 6 * r <= 8 * t.length ? e.push(a.charAt(i >>> 6 * (3 - r) & 63)) : e.push("="); return e.join("") }, base64ToBytes: function(t) { t = t.replace(/[^A-Z0-9+\/]/gi, ""); for (var e = [], n = 0, i = 0; n < t.length; i = ++n % 4) 0 != i && e.push((a.indexOf(t.charAt(n - 1)) & Math.pow(2, -2 * i + 8) - 1) << 2 * i | a.indexOf(t.charAt(n)) >>> 6 - 2 * i); return e } },
Then i, know i = a (12) .utf-8 through the code. After breaking the point, find the code corresponding to the i parameter as follows:
{ stringToBytes: function(t) { return a.bin.stringToBytes(unescape(encodeURIComponent(t))) }, bytesToString: function(t) { return decodeURIComponent(escape(a.bin.bytesToString(t))) } }
Then there is o, know o = a (12) .bin through the code, after breaking the point, find the code corresponding to the o parameter as follows:
{ stringToBytes: function (t) { for (var e = [], a = 0; a < t.length; a++) e.push(255 & t.charCodeAt(a)); return e } , bytesToString: function (t) { for (var e = [], a = 0; a < t.length; a++) e.push(String.fromCharCode(t[a])); return e.join("") } }
Here you can define an a12, and then remove the corresponding method from it.
var a12 = { utf8: { stringToBytes: function (e) { return a12.bin.stringToBytes(unescape(encodeURIComponent(e))) }, bytesToString: function (e) { return decodeURIComponent(escape(a.bin.bytesToString(e))) } }, bin: { stringToBytes: function (e) { for (var t = [], a = 0; a < e.length; a++) t.push(255 & e.charCodeAt(a)); return t }, bytesToString: function (e) { for (var t = [], a = 0; a < e.length; a++) t.push(String.fromCharCode(e[a])); return t.join("") } } };
Finally, there is an o parameter, and the following code can be located through breakpoint debugging:
It can be seen that this parameter o is set to null. So far, we have obtained the parameters of the encryption method. The next thing to talk about is how to achieve encryption to obtain antitoken.
2. Implement the encryption method
To realize the encryption method, you also need to know that two parameters are passed in during encryption, one is a 13-bit timestamp and the other is a null value. Through debugging, the screenshot is as follows:
Sort out the previous parameters and methods to get the following JavaScript code:
1 //定义antitoken 2 function antitoken(e) { 3 var a12 = { 4 utf8: { 5 stringToBytes: function (e) { 6 return a12.bin.stringToBytes(unescape(encodeURIComponent(e))) 7 }, 8 bytesToString: function (e) { 9 return decodeURIComponent(escape(a.bin.bytesToString(e))) 10 } 11 }, 12 bin: { 13 stringToBytes: function (e) { 14 for (var t = [], a = 0; a < e.length; a++) 15 t.push(255 & e.charCodeAt(a)); 16 return t 17 }, 18 bytesToString: function (e) { 19 for (var t = [], a = 0; a < e.length; a++) 20 t.push(String.fromCharCode(e[a])); 21 return t.join("") 22 } 23 } 24 }; 25 var t = null; 26 var n, i, o, s, r; 27 n = { 28 rotl: function (e, t) { 29 return e << t | e >>> 32 - t 30 }, 31 rotr: function (e, t) { 32 return e << 32 - t | e >>> t 33 }, 34 endian: function (e) { 35 if (e.constructor == Number) 36 return 16711935 & n.rotl(e, 8) | 4278255360 & n.rotl(e, 24); 37 for (var t = 0; t < e.length; t++) 38 e[t] = n.endian(e[t]); 39 return e 40 }, 41 randomBytes: function (e) { 42 for (var t = []; e > 0; e--) 43 t.push(Math.floor(256 * Math.random())); 44 return t 45 }, 46 bytesToWords: function (e) { 47 for (var t = [], a = 0, n = 0; a < e.length; a++, 48 n += 8) 49 t[n >>> 5] |= e[a] << 24 - n % 32; 50 return t 51 }, 52 wordsToBytes: function (e) { 53 for (var t = [], a = 0; a < 32 * e.length; a += 8) 54 t.push(e[a >>> 5] >>> 24 - a % 32 & 255); 55 return t 56 }, 57 bytesToHex: function (e) { 58 for (var t = [], a = 0; a < e.length; a++) 59 t.push((e[a] >>> 4).toString(16)), 60 t.push((15 & e[a]).toString(16)); 61 return t.join("") 62 }, 63 hexToBytes: function (e) { 64 for (var t = [], a = 0; a < e.length; a += 2) 65 t.push(parseInt(e.substr(a, 2), 16)); 66 return t 67 }, 68 bytesToBase64: function (e) { 69 for (var t = [], n = 0; n < e.length; n += 3) 70 for (var i = e[n] << 16 | e[n + 1] << 8 | e[n + 2], o = 0; o < 4; o++) 71 8 * n + 6 * o <= 8 * e.length ? t.push(a.charAt(i >>> 6 * (3 - o) & 63)) : t.push("="); 72 return t.join("") 73 }, 74 base64ToBytes: function (e) { 75 e = e.replace(/[^A-Z0-9+\/]/gi, ""); 76 for (var t = [], n = 0, i = 0; n < e.length; i = ++n % 4) 77 0 != i && t.push((a.indexOf(e.charAt(n - 1)) & Math.pow(2, -2 * i + 8) - 1) << 2 * i | a.indexOf(e.charAt(n)) >>> 6 - 2 * i); 78 return t 79 } 80 }, 81 i = a12.utf8, 82 o = null, 83 s = a12.bin, 84 (r = function (e, t) { 85 e.constructor == String ? e = t && "binary" === t.encoding ? s.stringToBytes(e) : i.stringToBytes(e) : o(e) ? e = Array.prototype.slice.call(e, 0) : Array.isArray(e) || (e = e.toString()); 86 for (var a = n.bytesToWords(e), l = 8 * e.length, c = 1732584193, d = -271733879, p = -1732584194, u = 271733878, m = 0; m < a.length; m++) 87 a[m] = 16711935 & (a[m] << 8 | a[m] >>> 24) | 4278255360 & (a[m] << 24 | a[m] >>> 8); 88 a[l >>> 5] |= 128 << l % 32; 89 a[14 + (l + 64 >>> 9 << 4)] = l; 90 var f = r._ff 91 , h = r._gg 92 , v = r._hh 93 , g = r._ii; 94 for (m = 0; m < a.length; m += 16) { 95 var y = c 96 , _ = d 97 , b = p 98 , $ = u; 99 d = g(d = g(d = g(d = g(d = v(d = v(d = v(d = v(d = h(d = h(d = h(d = h(d = f(d = f(d = f(d = f(d, p = f(p, u = f(u, c = f(c, d, p, u, a[m + 0], 7, -680876936), d, p, a[m + 1], 12, -389564586), c, d, a[m + 2], 17, 606105819), u, c, a[m + 3], 22, -1044525330), p = f(p, u = f(u, c = f(c, d, p, u, a[m + 4], 7, -176418897), d, p, a[m + 5], 12, 1200080426), c, d, a[m + 6], 17, -1473231341), u, c, a[m + 7], 22, -45705983), p = f(p, u = f(u, c = f(c, d, p, u, a[m + 8], 7, 1770035416), d, p, a[m + 9], 12, -1958414417), c, d, a[m + 10], 17, -42063), u, c, a[m + 11], 22, -1990404162), p = f(p, u = f(u, c = f(c, d, p, u, a[m + 12], 7, 1804603682), d, p, a[m + 13], 12, -40341101), c, d, a[m + 14], 17, -1502002290), u, c, a[m + 15], 22, 1236535329), p = h(p, u = h(u, c = h(c, d, p, u, a[m + 1], 5, -165796510), d, p, a[m + 6], 9, -1069501632), c, d, a[m + 11], 14, 643717713), u, c, a[m + 0], 20, -373897302), p = h(p, u = h(u, c = h(c, d, p, u, a[m + 5], 5, -701558691), d, p, a[m + 10], 9, 38016083), c, d, a[m + 15], 14, -660478335), u, c, a[m + 4], 20, -405537848), p = h(p, u = h(u, c = h(c, d, p, u, a[m + 9], 5, 568446438), d, p, a[m + 14], 9, -1019803690), c, d, a[m + 3], 14, -187363961), u, c, a[m + 8], 20, 1163531501), p = h(p, u = h(u, c = h(c, d, p, u, a[m + 13], 5, -1444681467), d, p, a[m + 2], 9, -51403784), c, d, a[m + 7], 14, 1735328473), u, c, a[m + 12], 20, -1926607734), p = v(p, u = v(u, c = v(c, d, p, u, a[m + 5], 4, -378558), d, p, a[m + 8], 11, -2022574463), c, d, a[m + 11], 16, 1839030562), u, c, a[m + 14], 23, -35309556), p = v(p, u = v(u, c = v(c, d, p, u, a[m + 1], 4, -1530992060), d, p, a[m + 4], 11, 1272893353), c, d, a[m + 7], 16, -155497632), u, c, a[m + 10], 23, -1094730640), p = v(p, u = v(u, c = v(c, d, p, u, a[m + 13], 4, 681279174), d, p, a[m + 0], 11, -358537222), c, d, a[m + 3], 16, -722521979), u, c, a[m + 6], 23, 76029189), p = v(p, u = v(u, c = v(c, d, p, u, a[m + 9], 4, -640364487), d, p, a[m + 12], 11, -421815835), c, d, a[m + 15], 16, 530742520), u, c, a[m + 2], 23, -995338651), p = g(p, u = g(u, c = g(c, d, p, u, a[m + 0], 6, -198630844), d, p, a[m + 7], 10, 1126891415), c, d, a[m + 14], 15, -1416354905), u, c, a[m + 5], 21, -57434055), p = g(p, u = g(u, c = g(c, d, p, u, a[m + 12], 6, 1700485571), d, p, a[m + 3], 10, -1894986606), c, d, a[m + 10], 15, -1051523), u, c, a[m + 1], 21, -2054922799), p = g(p, u = g(u, c = g(c, d, p, u, a[m + 8], 6, 1873313359), d, p, a[m + 15], 10, -30611744), c, d, a[m + 6], 15, -1560198380), u, c, a[m + 13], 21, 1309151649), p = g(p, u = g(u, c = g(c, d, p, u, a[m + 4], 6, -145523070), d, p, a[m + 11], 10, -1120210379), c, d, a[m + 2], 15, 718787259), u, c, a[m + 9], 21, -343485551), 100 c = c + y >>> 0; 101 d = d + _ >>> 0; 102 p = p + b >>> 0; 103 u = u + $ >>> 0; 104 } 105 return n.endian([c, d, p, u]) 106 } 107 )._ff = function (e, t, a, n, i, o, s) { 108 var r = e + (t & a | ~t & n) + (i >>> 0) + s; 109 return (r << o | r >>> 32 - o) + t 110 }; 111 112 r._gg = function (e, t, a, n, i, o, s) { 113 var r = e + (t & n | a & ~n) + (i >>> 0) + s; 114 return (r << o | r >>> 32 - o) + t 115 }; 116 117 r._hh = function (e, t, a, n, i, o, s) { 118 var r = e + (t ^ a ^ n) + (i >>> 0) + s; 119 return (r << o | r >>> 32 - o) + t 120 }; 121 122 r._ii = function (e, t, a, n, i, o, s) { 123 var r = e + (a ^ (t | ~n)) + (i >>> 0) + s; 124 return (r << o | r >>> 32 - o) + t 125 }; 126 127 r._blocksize = 16; 128 r._digestsize = 16; 129 130 var a = n.wordsToBytes(r(e, t)); 131 return t && t.asBytes ? a : t && t.asString ? s.bytesToString(a) : n.bytesToHex(a); 132 }
This is the encryption method implemented using JavaScript. The incoming parameter e is a thirteen-digit timestamp. It can be used regardless of whether it is called using JS or Python. Here you can verify it.
The first is a screenshot in the developer tools:
Then is the result of running the code: