發現問題 在一次偶然中,在爬取某個網站時,老方法,打開調試工具查看請求方式,請求攔截,是否是非同步載入,不亦樂乎,當我以為這個網站非常簡單的時候,發現二級網頁的地址和源碼不對應 Ajax非同步載入?源碼也是這樣的 而且這些鏈接直... ...
發現問題
在一次偶然中,在爬取某個網站時,老方法,打開調試工具查看請求方式,請求攔截,是否是非同步載入,不亦樂乎,當我以為這個網站非常簡單的時候,發現二級網頁的地址和源碼不對應
Ajax非同步載入?源碼也是這樣的
而且這些鏈接直接訪問根本無法訪問
用火狐瀏覽器的event顯示:
找到加密方式
源碼:
function() { var hh = $(this).attr("href"); if (typeof(hh) == 'undefined' || hh == '#') { return } var aa = hh.split("/"); var aaa = aa.length; var bbb = aa[aaa - 1].split('.'); var ccc = bbb[0]; var cccc = bbb[1]; var r = /^\+?[1-9][0-9]*$/; if (r.test(ccc) && cccc.indexOf('jhtml') != -1) { var srcs = CryptoJS.enc.Utf8.parse(ccc); var k = CryptoJS.enc.Utf8.parse(s); var en = CryptoJS.AES.encrypt(srcs, k, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 }); var ddd = en.toString(); ddd = ddd.replace(/\//g, "^"); ddd = ddd.substring(0, ddd.length - 2); var bbbb = ddd + '.' + bbb[1]; aa[aaa - 1] = bbbb; var uuu = ''; for (i = 0; i < aaa; i++) { uuu += aa[i] + '/' } uuu = uuu.substring(0, uuu.length - 1); window.open(uuu) } else { var ee = $(this).attr('target'); if (ee.typeof('undefined')) { window.location = hh } else { window.open(hh) } } return false }
根據我的發現,實現的效果就是讓源碼的鏈接:
http://xxxx.xxxx.xx:80/jssfdg/3254639.jhtml
變為如下鏈接:
http://xxxx.xxxx.xx:80/jssfdg/JzRnGhk7J9D1ZNMlh47fMw.jhtml
以上代碼縮減了下:
就這幾行代碼:
var srcs = CryptoJS.enc.Utf8.parse(ccc); var k = CryptoJS.enc.Utf8.parse(s); var en = CryptoJS.AES.encrypt(srcs, k, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 }); var ddd = en.toString(); ddd = ddd.replace(/\//g, "^"); ddd = ddd.substring(0, ddd.length - 2); return ddd
將以上代碼封裝為一個函數併在瀏覽器的控制台測試:
大概的意思就是先將那串數字用utf8加密成數組:
再對密鑰操作:
再將上面的兩個數組用aes加密
將用aes加密過的en轉為字元串:
我渣一看這種字元串像是base64加密
再將帶有/符號的轉為^,因為在url編碼中,/符號有特殊意義
再將數據後面的[==]分割掉
最後的字元串就是需要的數據了
把這段操作封裝成一個函數,然後測試:
經過測試,沒毛病,返回的這個字元與真實的一致。
卧槽,瞬間激動啦,這還沒完,我是直接在當前網頁的控制台操作的,換到其他網頁的控制台:
需要兩個重要的東西:CryptoJS對象 和 s變數
CryptoJS對象都還好,那特麽一定是引入的,s變數就難了,從源碼找,包含s的太多了,而且還是小寫,關鍵詞太多了
而且S變數是已經定義好的,因為我打開控制台直接訪問s就能有結果:
所以,那絕對是已定義的,但是我無法確定是寫死的還是隨機生成的,如果按寫死的來,那就難了,所以我必須找到它,它也至關重要,因為就是aes加密需要的密鑰,不然無法加密出來希望的格式
我找了一上午,還請教了我的前端大佬同事,也是一時不知道怎麼找
最後,我把當天的任務忙完之後,專門騰出兩小時時間來再分析,我一個一個js文件慢慢看:
找到key值
結果,他麽的,放在jquery源碼裡面:
而且,還真的是寫死的
卧槽!!!!!!!!!!!!!!!!!!!!,太nm騷了,放源碼了,按正常人的慣用思維,像什麼jquery,vue等的源碼,一定是不敢去亂改的,要寫js的話,也不敢去亂搞,都是新建一個js文件寫入,它這個把密鑰寫在jquery源碼里,簡直反其道而行,我不知道說這個網站的前端開發者是高明還是奇葩了
好的,兩樣東西都齊了,準備用代碼實現了,在這之前,先瞭解下什麼是CryptoJS
源碼:
!function(t, n) { "object" == typeof exports ? module.exports = exports = n() : "function" == typeof define && define.amd ? define([], n) : t.CryptoJS = n() } (this, function() { var t = t || function(t, n) { var i = Object.create || function() { function t() {} return function(n) { var i; return t.prototype = n, i = new t, t.prototype = null, i } } (), e = {}, r = e.lib = {}, o = r.Base = function() { return { extend: function(t) { var n = i(this); return t && n.mixIn(t), n.hasOwnProperty("init") && this.init !== n.init || (n.init = function() { n.$super.init.apply(this, arguments) }), n.init.prototype = n, n.$super = this, n }, create: function() { var t = this.extend(); return t.init.apply(t, arguments), t }, init: function() {}, mixIn: function(t) { for (var n in t) t.hasOwnProperty(n) && (this[n] = t[n]); t.hasOwnProperty("toString") && (this.toString = t.toString) }, clone: function() { return this.init.prototype.extend(this) } } } (), s = r.WordArray = o.extend({ init: function(t, i) { t = this.words = t || [], i != n ? this.sigBytes = i: this.sigBytes = 4 * t.length }, toString: function(t) { return (t || c).stringify(this) }, concat: function(t) { var n = this.words, i = t.words, e = this.sigBytes, r = t.sigBytes; if (this.clamp(), e % 4) for (var o = 0; o < r; o++) { var s = i[o >>> 2] >>> 24 - o % 4 * 8 & 255; n[e + o >>> 2] |= s << 24 - (e + o) % 4 * 8 } else for (var o = 0; o < r; o += 4) n[e + o >>> 2] = i[o >>> 2]; return this.sigBytes += r, this }, clamp: function() { var n = this.words, i = this.sigBytes; n[i >>> 2] &= 4294967295 << 32 - i % 4 * 8, n.length = t.ceil(i / 4) }, clone: function() { var t = o.clone.call(this); return t.words = this.words.slice(0), t }, random: function(n) { for (var i, e = [], r = function(n) { var n = n, i = 987654321, e = 4294967295; return function() { i = 36969 * (65535 & i) + (i >> 16) & e, n = 18e3 * (65535 & n) + (n >> 16) & e; var r = (i << 16) + n & e; return r /= 4294967296, r += .5, r * (t.random() > .5 ? 1 : -1) } }, o = 0; o < n; o += 4) { var a = r(4294967296 * (i || t.random())); i = 987654071 * a(), e.push(4294967296 * a() | 0) } return new s.init(e, n) } }), a = e.enc = {}, c = a.Hex = { stringify: function(t) { for (var n = t.words, i = t.sigBytes, e = [], r = 0; r < i; r++) { var o = n[r >>> 2] >>> 24 - r % 4 * 8 & 255; e.push((o >>> 4).toString(16)), e.push((15 & o).toString(16)) } return e.join("") }, parse: function(t) { for (var n = t.length, i = [], e = 0; e < n; e += 2) i[e >>> 3] |= parseInt(t.substr(e, 2), 16) << 24 - e % 8 * 4; return new s.init(i, n / 2) } }, u = a.Latin1 = { stringify: function(t) { for (var n = t.words, i = t.sigBytes, e = [], r = 0; r < i; r++) { var o = n[r >>> 2] >>> 24 - r % 4 * 8 & 255; e.push(String.fromCharCode(o)) } return e.join("") }, parse: function(t) { for (var n = t.length, i = [], e = 0; e < n; e++) i[e >>> 2] |= (255 & t.charCodeAt(e)) << 24 - e % 4 * 8; return new s.init(i, n) } }, f = a.Utf8 = { stringify: function(t) { try { return decodeURIComponent(escape(u.stringify(t))) } catch(t) { throw new Error("Malformed UTF-8 data") } }, parse: function(t) { return u.parse(unescape(encodeURIComponent(t))) } }, h = r.BufferedBlockAlgorithm = o.extend({ reset: function() { this._data = new s.init, this._nDataBytes = 0 }, _append: function(t) { "string" == typeof t && (t = f.parse(t)), this._data.concat(t), this._nDataBytes += t.sigBytes }, _process: function(n) { var i = this._data, e = i.words, r = i.sigBytes, o = this.blockSize, a = 4 * o, c = r / a; c = n ? t.ceil(c) : t.max((0 | c) - this._minBufferSize, 0); var u = c * o, f = t.min(4 * u, r); if (u) { for (var h = 0; h < u; h += o) this._doProcessBlock(e, h); var p = e.splice(0, u); i.sigBytes -= f } return new s.init(p, f) }, clone: function() { var t = o.clone.call(this); return t._data = this._data.clone(), t }, _minBufferSize: 0 }), p = (r.Hasher = h.extend({ cfg: o.extend(), init: function(t) { this.cfg = this.cfg.extend(t), this.reset() }, reset: function() { h.reset.call(this), this._doReset() }, update: function(t) { return this._append(t), this._process(), this }, finalize: function(t) { t && this._append(t); var n = this._doFinalize(); return n }, blockSize: 16, _createHelper: function(t) { return function(n, i) { return new t.init(i).finalize(n) } }, _createHmacHelper: function(t) { return function(n, i) { return new p.HMAC.init(t, i).finalize(n) } } }), e.algo = {}); return e } (Math); return t }); //# sourceMappingURL=core.min.js.map ! function(e, t, i) { "object" == typeof exports ? module.exports = exports = t(require("./core.min"), require("./sha1.min"), require("./hmac.min")) : "function" == typeof define && define.amd ? define(["./core.min", "./sha1.min", "./hmac.min"], t) : t(e.CryptoJS) } (this, function(e) { return function() { var t = e, i = t.lib, r = i.Base, n = i.WordArray, o = t.algo, a = o.MD5, c = o.EvpKDF = r.extend({ cfg: r.extend({ keySize: 4, hasher: a, iterations: 1 }), init: function(e) { this.cfg = this.cfg.extend(e) }, compute: function(e, t) { for (var i = this.cfg, r = i.hasher.create(), o = n.create(), a = o.words, c = i.keySize, f = i.iterations; a.length < c;) { s && r.update(s); var s = r.update(e).finalize(t); r.reset(); for (var u = 1; u < f; u++) s = r.finalize(s), r.reset(); o.concat(s) } return o.sigBytes = 4 * c, o } }); t.EvpKDF = function(e, t, i) { return c.create(i).compute(e, t) } } (), e.EvpKDF }); //# sourceMappingURL=evpkdf.min.js.map ! function(r, e) { "object" == typeof exports ? module.exports = exports = e(require("./core.min")) : "function" == typeof define && define.amd ? define(["./core.min"], e) : e(r.CryptoJS) } (this, function(r) { return function() { function e(r, e, t) { for (var n = [], i = 0, o = 0; o < e; o++) if (o % 4) { var f = t[r.charCodeAt(o - 1)] << o % 4 * 2, c = t[r.charCodeAt(o)] >>> 6 - o % 4 * 2; n[i >>> 2] |= (f | c) << 24 - i % 4 * 8, i++ } return a.create(n, i) } var t = r, n = t.lib, a = n.WordArray, i = t.enc; i.Base64 = { stringify: function(r) { var e = r.words, t = r.sigBytes, n = this._map; r.clamp(); for (var a = [], i = 0; i < t; i += 3) for (var o = e[i >>> 2] >>> 24 - i % 4 * 8 & 255, f = e[i + 1 >>> 2] >>> 24 - (i + 1) % 4 * 8 & 255, c = e[i + 2 >>> 2] >>> 24 - (i + 2) % 4 * 8 & 255, s = o << 16 | f << 8 | c, h = 0; h < 4 && i + .75 * h < t; h++) a.push(n.charAt(s >>> 6 * (3 - h) & 63)); var p = n.charAt(64); if (p) for (; a.length % 4;) a.push(p); return a.join("") }, parse: function(r) { var t = r.length, n = this._map, a = this._reverseMap; if (!a) { a = this._reverseMap = []; for (var i = 0; i < n.length; i++) a[n.charCodeAt(i)] = i } var o = n.charAt(64); if (o) { var f = r.indexOf(o); f !== -1 && (t = f) } return e(r, t, a) }, _map: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" } } (), r.enc.Base64 }); //# sourceMappingURL=enc-base64.min.js.map ! function(e, t, r) { "object" == typeof exports ? module.exports = exports = t(require("./core.min"), require("./evpkdf.min")) : "function" == typeof define && define.amd ? define(["./core.min", "./evpkdf.min"], t) : t(e.CryptoJS) } (this, function(e) { e.lib.Cipher || function(t) { var r = e, i = r.lib, n = i.Base, c = i.WordArray, o = i.BufferedBlockAlgorithm, s = r.enc, a = (s.Utf8, s.Base64), f = r.algo, p = f.EvpKDF, d = i.Cipher = o.extend({ cfg: n.extend(), createEncryptor: function(e, t) { return this.create(this._ENC_XFORM_MODE, e, t) }, createDecryptor: function(e, t) { return this.create(this._DEC_XFORM_MODE, e, t) }, init: function(e, t, r) { this.cfg = this.cfg.extend(r), this._xformMode = e, this._key = t, this.reset() }, reset: function() { o.reset.call(this), this._doReset() }, process: function(e) { return this._append(e), this._process() }, finalize: function(e) { e && this._append(e); var t = this._doFinalize(); return t }, keySize: 4, ivSize: 4, _ENC_XFORM_MODE: 1, _DEC_XFORM_MODE: 2, _createHelper: function() { function e(e) { return "string" == typeof e ? B: x } return function(t) { return { encrypt: function(r, i, n) { return e(i).encrypt(t, r, i, n) }, decrypt: function(r, i, n) { return e(i).decrypt(t, r, i, n) } } } } () }), h = (i.StreamCipher = d.extend({ _doFinalize: function() { var e = this._process(!0); return e }, blockSize: 1 }), r.mode = {}), u = i.BlockCipherMode = n.extend({ createEncryptor: function(e, t) { return this.Encryptor.create(e, t) }, createDecryptor: function(e, t) { return this.Decryptor.create(e, t) }, init: function(e, t) { this._cipher = e, this._iv = t } }), l = h.CBC = function() { function e(e, r, i) { var n = this._iv; if (n) { var c = n; this._iv = t } else var c = this._prevBlock; for (var o = 0; o < i; o++) e[r + o] ^= c[o] } var r = u.extend(); return r.Encryptor = r.extend({ processBlock: function(t, r) { var i = this._cipher, n = i.blockSize; e.call(this, t, r, n), i.encryptBlock(t, r), this._prevBlock = t.slice(r, r + n) } }), r.Decryptor = r.extend({ processBlock: function(t, r) { var i = this._cipher, n = i.blockSize, c = t.slice(r, r + n); i.decryptBlock(t, r), e.call(this, t, r, n), this._prevBlock = c } }), r } (), _ = r.pad = {}, v = _.Pkcs7 = { pad: function(e, t) { for (var r = 4 * t, i = r - e.sigBytes % r, n = i << 24 | i << 16 | i << 8 | i, o = [], s = 0; s < i; s += 4) o.push(n); var a = c.create(o, i); e.concat(a) }, unpad: function(e) { var t = 255 & e.words[e.sigBytes - 1 >>> 2]; e.sigBytes -= t } }, y = (i.BlockCipher = d.extend({ cfg: d.cfg.extend({ mode: l, padding: v }), reset: function() { d.reset.call(this); var e = this.cfg, t = e.iv, r = e.mode; if (this._xformMode == this._ENC_XFORM_MODE) var i = r.createEncryptor; else { var i = r.createDecryptor; this._minBufferSize = 1 } this._mode && this._mode.__creator == i ? this._mode.init(this, t && t.words) : (this._mode = i.call(r, this, t && t.words), this._mode.__creator = i) }, _doProcessBlock: function(e, t) { this._mode.processBlock(e, t) }, _doFinalize: function() { var e = this.cfg.padding; if (this._xformMode == this._ENC_XFORM_MODE) { e.pad(this._data, this.blockSize); var t = this._process(!0) } else { var t = this._process(!0); e.unpad(t) } return t }, blockSize: 4 }), i.CipherParams = n.extend({ init: function(e) { this.mixIn(e) }, toString: function(e) { return (e || this.formatter).stringify(this) } })), m = r.format = {}, k = m.OpenSSL = { stringify: function(e) { var t = e.ciphertext, r = e.salt; if (r) var i = c.create([1398893684, 1701076831]).concat(r).concat(t); else var i = t; return i.toString(a) }, parse: function(e) { var t = a.parse(e), r = t.words; if (1398893684 == r[0] && 1701076831 == r[1]) { var i = c.create(r.slice(2, 4)); r.splice(0, 4), t.sigBytes -= 16 } return y.create({ ciphertext: t, salt: i }) } }, x = i.SerializableCipher = n.extend({ cfg: n.extend({ format: k }), encrypt: function(e, t, r, i) { i = this.cfg.extend(i); var n = e.createEncryptor(r, i), c = n.finalize(t), o = n.cfg; return y.create({ ciphertext: c, key: r, iv: o.iv, algorithm: e, mode: o.mode, padding: o.padding, blockSize: e.blockSize, formatter: i.format }) }, decrypt: function(e, t, r, i) { i = this.cfg.extend(i), t = this._parse(t, i.format); var n = e.createDecryptor(r, i).finalize(t.ciphertext); return n }, _parse: function