目标网站:aHR0cDovL3d3dy56bGRzai5jb20v
在一家公众号中看到,所以拿来学习下。
以下仅用文字记录自己的学习过程。。。。。。。。。。。。。。。截图太烦了。。。。。。。。。。。。。。
打开网页后,脑子一时有点空白,虽然已经知道它是rsa加密,但是突然就想不起第一步要干嘛。
于是试着在左侧栏搜索输入password,出现几个选项,一一排查,发现2点,
1.账号密码是由http://www.zldsj.com/txn999999.do提交的,并且密码被加密了,如下
password: UUN09T4poqDw0FjjCF0Y0EGin29A64IU3X2djsqO5iwF9PoVnJ4AY65SedsA56F0J3OPL+HOKrntlgF3bLJQRBGN1CJRBna3cGER0yRcR/KDs+mcgaRetJ6mvv3J3TL/e1z6u2+lOmaZQvNyxRyuIGDKD1B7geANQLTy8vtq2BI=
其实密码是111111
2.发现http://www.zldsj.com/module/di/js/usermanager/login.js?1.15.0 文件可疑。
于是试着在上述js的
var result = encryptedString(key, encodeURIComponent($("#password").val()) ,RSAAPP.NoPadding,RSAAPP.RawEncoding);
result = window.btoa(result);
打断点,再输入账号密码,对不对无所谓,验证码对就行了,登录。发现果然停住了。
记录下result的值然后全速运行,再回到http://www.zldsj.com/txn999999.do的headers中查看末尾的password,发现一模一样
那么可以得到
var result = encryptedString(key, encodeURIComponent($("#password").val()) ,RSAAPP.NoPadding,RSAAPP.RawEncoding);
是输出rsa加密的密码。
result = window.btoa(result); 将rsa加密的密码进行Base64编码后输出。
接下来在上处重新打上断点,继续分析key是在哪里产生的,发现encodeURIComponent($("#password").val())就是输入的密码111111,RSAAPP.NoPadding和RSAAPP.RawEncoding都是固定值。
最后就是扣代码了,我们要基于如下代码来扣代码
bodyRSA();
var result = encryptedString(key, encodeURIComponent($("#password").val()),RSAAPP.NoPadding,RSAAPP.RawEncoding);
result = window.btoa(result);
只有一个原则:缺啥补啥。
下面贴出我抠好的代码命名为wd.js:
var RSAAPP = {}; var biRadixBase = 2; var biRadixBits = 16; var bitsPerDigit = biRadixBits; var biRadix = 1 << 16; // = 2^16 = 65536 var biHalfRadix = biRadix >>> 1; var biRadixSquared = biRadix * biRadix; var maxDigitVal = biRadix - 1; var maxInteger = 9999999999999998; var highBitMasks = new Array(0x0000, 0x8000, 0xC000, 0xE000, 0xF000, 0xF800, 0xFC00, 0xFE00, 0xFF00, 0xFF80, 0xFFC0, 0xFFE0, 0xFFF0, 0xFFF8, 0xFFFC, 0xFFFE, 0xFFFF); var lowBitMasks = new Array(0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF); RSAAPP.NoPadding = "NoPadding"; RSAAPP.PKCS1Padding = "PKCS1Padding"; RSAAPP.RawEncoding = "RawEncoding"; RSAAPP.NumericEncoding = "NumericEncoding" var ZERO_ARRAY = new Array(131); for (var index = 0; index < 131; index++) { ZERO_ARRAY[index] = 0; } function biMultiplyByRadixPower(x, n) { var result = new BigInt(); arrayCopy(x.digits, 0, result.digits, n, result.digits.length - n); return result; } function biCompare(x, y) { if (x.isNeg != y.isNeg) { return 1 - 2 * Number(x.isNeg); } for (var i = x.digits.length - 1; i >= 0; --i) { if (x.digits[i] != y.digits[i]) { if (x.isNeg) { return 1 - 2 * Number(x.digits[i] > y.digits[i]); } else { return 1 - 2 * Number(x.digits[i] < y.digits[i]); } } } return 0; } function biSubtract(x, y) { var result; if (x.isNeg != y.isNeg) { y.isNeg = !y.isNeg; result = biAdd(x, y); y.isNeg = !y.isNeg; } else { result = new BigInt(); var n, c; c = 0; for (var i = 0; i < x.digits.length; ++i) { n = x.digits[i] - y.digits[i] + c; result.digits[i] = n & 0xffff; // Stupid non-conforming modulus operation. if (result.digits[i] < 0) result.digits[i] += biRadix; c = 0 - Number(n < 0); } // Fix up the negative sign, if any. if (c == -1) { c = 0; for (var i = 0; i < x.digits.length; ++i) { n = 0 - result.digits[i] + c; result.digits[i] = n & 0xffff; // Stupid non-conforming modulus operation. if (result.digits[i] < 0) result.digits[i] += biRadix; c = 0 - Number(n < 0); } // Result is opposite sign of arguments. result.isNeg = !x.isNeg; } else { // Result is same sign. result.isNeg = x.isNeg; } } return result; } function biMultiplyDigit(x, y) { var n, c, uv; result = new BigInt(); n = biHighIndex(x); c = 0; for (var j = 0; j <= n; ++j) { uv = result.digits[j] + x.digits[j] * y + c; result.digits[j] = uv & maxDigitVal; c = uv >>> biRadixBits; } result.digits[1 + n] = c; return result; } function biShiftRight(x, n) { var digitCount = Math.floor(n / bitsPerDigit); var result = new BigInt(); arrayCopy(x.digits, digitCount, result.digits, 0, x.digits.length - digitCount); var bits = n % bitsPerDigit; var leftBits = bitsPerDigit - bits; for (var i = 0, i1 = i + 1; i < result.digits.length - 1; ++i, ++i1) { result.digits[i] = (result.digits[i] >>> bits) | ((result.digits[i1] & lowBitMasks[bits]) << leftBits); } result.digits[result.digits.length - 1] >>>= bits; result.isNeg = x.isNeg; return result; } function biShiftLeft(x, n) { var digitCount = Math.floor(n / bitsPerDigit); var result = new BigInt(); arrayCopy(x.digits, 0, result.digits, digitCount, result.digits.length - digitCount); var bits = n % bitsPerDigit; var rightBits = bitsPerDigit - bits; for (var i = result.digits.length - 1, i1 = i - 1; i > 0; --i, --i1) { result.digits[i] = ((result.digits[i] << bits) & maxDigitVal) | ((result.digits[i1] & highBitMasks[bits]) >>> (rightBits)); } result.digits[0] = ((result.digits[i] << bits) & maxDigitVal); result.isNeg = x.isNeg; return result; } function arrayCopy(src, srcStart, dest, destStart, n) { var m = Math.min(srcStart + n, src.length); for (var i = srcStart, j = destStart; i < m; ++i, ++j) { dest[j] = src[i]; } } function BigInt(flag) { if (typeof flag == "boolean" && flag == true) { this.digits = null; } else { this.digits = ZERO_ARRAY.slice(0); } this.isNeg = false; } function charToHex(c) { var ZERO = 48; var NINE = ZERO + 9; var littleA = 97; var littleZ = littleA + 25; var bigA = 65; var bigZ = 65 + 25; var result; if (c >= ZERO && c <= NINE) { result = c - ZERO; } else if (c >= bigA && c <= bigZ) { result = 10 + c - bigA; } else if (c >= littleA && c <= littleZ) { result = 10 + c - littleA; } else { result = 0; } return result; } function biHighIndex(x) { var result = x.digits.length - 1; while (result > 0 && x.digits[result] == 0) --result; return result; } function hexToDigit(s) { var result = 0; var sl = Math.min(s.length, 4); for (var i = 0; i < sl; ++i) { result <<= 4; result |= charToHex(s.charCodeAt(i)) } return result; } function biFromHex(s) { var result = new BigInt(); var sl = s.length; for (var i = sl, j = 0; i > 0; i -= 4, ++j) { result.digits[j] = hexToDigit(s.substr(Math.max(i - 4, 0), Math.min(i, 4))); } return result; } function biCopy(bi) { var result = new BigInt(true); result.digits = bi.digits.slice(0); result.isNeg = bi.isNeg; return result; } function biDivide(x, y) { return biDivideModulo(x, y)[0]; } function biDivideModulo(x, y) { var nb = biNumBits(x); var tb = biNumBits(y); var origYIsNeg = y.isNeg; var q, r; if (nb < tb) { // |x| < |y| if (x.isNeg) { q = biCopy(bigOne); q.isNeg = !y.isNeg; x.isNeg = false; y.isNeg = false; r = biSubtract(y, x); // Restore signs, 'cause they're references. x.isNeg = true; y.isNeg = origYIsNeg; } else { q = new BigInt(); r = biCopy(x); } return new Array(q, r); } q = new BigInt(); r = x; // Normalize Y. var t = Math.ceil(tb / bitsPerDigit) - 1; var lambda = 0; while (y.digits[t] < biHalfRadix) { y = biShiftLeft(y, 1); ++lambda; ++tb; t = Math.ceil(tb / bitsPerDigit) - 1; } // Shift r over to keep the quotient constant. We'll shift the // remainder back at the end. r = biShiftLeft(r, lambda); nb += lambda; // Update the bit count for x. var n = Math.ceil(nb / bitsPerDigit) - 1; var b = biMultiplyByRadixPower(y, n - t); while (biCompare(r, b) != -1) { ++q.digits[n - t]; r = biSubtract(r, b); } for (var i = n; i > t; --i) { var ri = (i >= r.digits.length) ? 0 : r.digits[i]; var ri1 = (i - 1 >= r.digits.length) ? 0 : r.digits[i - 1]; var ri2 = (i - 2 >= r.digits.length) ? 0 : r.digits[i - 2]; var yt = (t >= y.digits.length) ? 0 : y.digits[t]; var yt1 = (t - 1 >= y.digits.length) ? 0 : y.digits[t - 1]; if (ri == yt) { q.digits[i - t - 1] = maxDigitVal; } else { q.digits[i - t - 1] = Math.floor((ri * biRadix + ri1) / yt); } var c1 = q.digits[i - t - 1] * ((yt * biRadix) + yt1); var c2 = (ri * biRadixSquared) + ((ri1 * biRadix) + ri2); while (c1 > c2) { --q.digits[i - t - 1]; c1 = q.digits[i - t - 1] * ((yt * biRadix) | yt1); c2 = (ri * biRadix * biRadix) + ((ri1 * biRadix) + ri2); } b = biMultiplyByRadixPower(y, i - t - 1); r = biSubtract(r, biMultiplyDigit(b, q.digits[i - t - 1])); if (r.isNeg) { r = biAdd(r, b); --q.digits[i - t - 1]; } } r = biShiftRight(r, lambda); // Fiddle with the signs and stuff to make sure that 0 <= r < y. q.isNeg = x.isNeg != origYIsNeg; if (x.isNeg) { if (origYIsNeg) { q = biAdd(q, bigOne); } else { q = biSubtract(q, bigOne); } y = biShiftRight(y, lambda); r = biSubtract(y, r); } // Check for the unbelievably stupid degenerate case of r == -0. if (r.digits[0] == 0 && biHighIndex(r) == 0) r.isNeg = false; return new Array(q, r); } function biMultiply(x, y) { var result = new BigInt(); var c; var n = biHighIndex(x); var t = biHighIndex(y); var u, uv, k; for (var i = 0; i <= t; ++i) { c = 0; k = i; for (j = 0; j <= n; ++j, ++k) { uv = result.digits[k] + x.digits[j] * y.digits[i] + c; result.digits[k] = uv & maxDigitVal; c = uv >>> biRadixBits; } result.digits[i + n + 1] = c; } // Someone give me a logical xor, please. result.isNeg = x.isNeg != y.isNeg; return result; } function biDivideByRadixPower(x, n) { var result = new BigInt(); arrayCopy(x.digits, n, result.digits, 0, result.digits.length - n); return result; } function biModuloByRadixPower(x, n) { var result = new BigInt(); arrayCopy(x.digits, 0, result.digits, 0, n); return result; } function biAdd(x, y) { var result; if (x.isNeg != y.isNeg) { y.isNeg = !y.isNeg; result = biSubtract(x, y); y.isNeg = !y.isNeg; } else { result = new BigInt(); var c = 0; var n; for (var i = 0; i < x.digits.length; ++i) { n = x.digits[i] + y.digits[i] + c; result.digits[i] = n & 0xffff; c = Number(n >= biRadix); } result.isNeg = x.isNeg; } return result; } function biToBytes(x) // Returns a string containing raw bytes. { var result = ""; for (var i = biHighIndex(x); i > -1; --i) { result += digitToBytes(x.digits[i]); } return result; } function digitToBytes(n) // Convert two-byte digit to string containing both bytes. { var c1 = String.fromCharCode(n & 0xff); n >>>= 8; var c2 = String.fromCharCode(n & 0xff); return c2 + c1; } function biNumBits(x) { var n = biHighIndex(x); var d = x.digits[n]; var m = (n + 1) * bitsPerDigit; var result; for (result = m; result > m - bitsPerDigit; --result) { if ((d & 0x8000) != 0) break; d <<= 1; } return result; } function BarrettMu(m) { this.modulus = biCopy(m); this.k = biHighIndex(this.modulus) + 1; var b2k = new BigInt(); b2k.digits[2 * this.k] = 1; // b2k = b^(2k) this.mu = biDivide(b2k, this.modulus); this.bkplus1 = new BigInt(); this.bkplus1.digits[this.k + 1] = 1; // bkplus1 = b^(k+1) this.modulo = BarrettMu_modulo; this.multiplyMod = BarrettMu_multiplyMod; this.powMod = BarrettMu_powMod; } function BarrettMu_multiplyMod(x, y) { var xy = biMultiply(x, y); return this.modulo(xy); } function BarrettMu_powMod(x, y) { var result = new BigInt(); result.digits[0] = 1; var a = x; var k = y; while (true) { if ((k.digits[0] & 1) != 0) result = this.multiplyMod(result, a); k = biShiftRight(k, 1); if (k.digits[0] == 0 && biHighIndex(k) == 0) break; a = this.multiplyMod(a, a); } return result; } function BarrettMu_modulo(x) { var q1 = biDivideByRadixPower(x, this.k - 1); var q2 = biMultiply(q1, this.mu); var q3 = biDivideByRadixPower(q2, this.k + 1); var r1 = biModuloByRadixPower(x, this.k + 1); var r2term = biMultiply(q3, this.modulus); var r2 = biModuloByRadixPower(r2term, this.k + 1); var r = biSubtract(r1, r2); if (r.isNeg) { r = biAdd(r, this.bkplus1); } var rgtem = biCompare(r, this.modulus) >= 0; while (rgtem) { r = biSubtract(r, this.modulus); rgtem = biCompare(r, this.modulus) >= 0; } return r; } function RSAKeyPair(encryptionExponent, decryptionExponent, modulus, keylen) { this.e = biFromHex(encryptionExponent); this.d = biFromHex(decryptionExponent); this.m = biFromHex(modulus); if (typeof (keylen) != 'number') { this.chunkSize = 2 * biHighIndex(this.m); } else { this.chunkSize = keylen / 8; } this.radix = 16; this.barrett = new BarrettMu(this.m); } function encryptedString(key, s, pad, encoding) { var a = new Array(); // The usual Alice and Bob stuff var sl = s.length; // Plaintext string length var i, j, k; // The usual Fortran index stuff var padtype; // Type of padding to do var encodingtype; // Type of output encoding var rpad; // Random pad var al; // Array length var result = ""; // Cypthertext result var block; // Big integer block to encrypt var crypt; // Big integer result var text; // Text result /* * Figure out the padding type. */ if (typeof (pad) == 'string') { if (pad == RSAAPP.NoPadding) { padtype = 1; } else if (pad == RSAAPP.PKCS1Padding) { padtype = 2; } else { padtype = 0; } } else { padtype = 0; } /* * Determine encoding type. */ if (typeof (encoding) == 'string' && encoding == RSAAPP.RawEncoding) { encodingtype = 1; } else { encodingtype = 0; } if (padtype == 1) { if (sl > key.chunkSize) { sl = key.chunkSize; } } else if (padtype == 2) { if (sl > (key.chunkSize - 11)) { sl = key.chunkSize - 11; } } i = 0; if (padtype == 2) { j = sl - 1; } else { j = key.chunkSize - 1; } while (i < sl) { if (padtype) { a[j] = s.charCodeAt(i); } else { a[i] = s.charCodeAt(i); } i++; j--; } if (padtype == 1) { i = 0; } j = key.chunkSize - (sl % key.chunkSize); while (j > 0) { if (padtype == 2) { rpad = Math.floor(Math.random() * 256); while (!rpad) { rpad = Math.floor(Math.random() * 256); } a[i] = rpad; } else { a[i] = 0; } i++; j--; } if (padtype == 2) { a[sl] = 0; a[key.chunkSize - 2] = 2; a[key.chunkSize - 1] = 0; } /* * Carve up the plaintext and encrypt each of the resultant blocks. */ al = a.length; for (i = 0; i < al; i += key.chunkSize) { /* * Get a block. */ block = new BigInt(); j = 0; for (k = i; k < (i + key.chunkSize); ++j) { block.digits[j] = a[k++]; block.digits[j] += a[k++] << 8; } /* * Encrypt it, convert it to text, and append it to the result. */ crypt = key.barrett.powMod(block, key.e); if (encodingtype == 1) { text = biToBytes(crypt); } else { text = (key.radix == 16) ? biToHex(crypt) : biToString(crypt, key.radix); } result += text; } return result; } function bodyRSA() { return key = new RSAKeyPair( "10001", "", "9fb11419c88cdc086c67e07a04f4dd33a8d9bfa2d66d0c08f458f73d73221a315d4612ec3939baf929b1f7128817354d50f3408eba93775daed932996665466c3f3534153b31512e0f8b8c08bee9e9ad95374621f0447e9a847216413c5951d5b5640941fd8a933868a84c74d3523356839c1006dca0a081e91e12617b671d09"); } function get_encrypted_password(password) { var key = bodyRSA(); var result = encryptedString(key, password ,RSAAPP.NoPadding, RSAAPP.RawEncoding); result = new Buffer.from(result, "binary").toString("base64"); return result }
btoa和atob是window对象的两个函数,其中btoa是binary to ASCII,用于将binary的数据用ASCII码表示,即Base64的编码过程, 而atob则是ASCII to binary,用于将ASCII码解析成binary数据,即Base64的解码过程 binary 是JS字符集的另外一个子集,它类似于 ASCII 字符集,但是字符的码点(charCode)不再限制到 127,它包含了255 以内的字符。 binary string设计的目的不是用于代表字符, 而是代表二进制数据。由 binary string 代表的二进制数据大小是原始数据的两倍, 然而这对于最终用户是不可见的, 因为JavaScript strings 的长度是以2字节为单位进行计算的。 比如, "Hello world" 这个字符串属于 ASCII 子集, 而 ÀÈÌÒÙ 不属于ASCII码,但属于binary。 所以btoa和atob其实还涉及了编码问题,我们只需要找出相同编码进行替换即可。 在node.js环境中,提供了一个 Buffer 类,用于操作二进制及Base64转码。 // atob var s = new Buffer.from("待解码的字符", "base64").toString("binary") // btoa var s = new Buffer.from("待编码的字符", "binary").toString("base64")
以下为python代码调用js文件生成密文
import execjs def encrypted(password): with open('wd.js','r',encoding='utf-8') as f: ctx = execjs.compile(f.read()) data = ctx.call('get_encrypted_password',password) return data
输入111111,发现返回的确与网页的密文一样。
完结。