【爬虫实战】逆向某公众平台登录接口

近期在练习一些网站的逆向,其实也无论难易程度,重点是总结经验。

一、目标整理

今天的目标是 https://mp.weixin.qq.com/ 中的登录接口,这个接口对post的数据中的密码部分进行了加密处理。其实这个接口并不是特别重要,所以破解起来很简单。

可以看到用户名是明文的,但是密码部分是加密后的,要实现的就是输出加密后的密文。

二、逻辑分析

1. 查找接口

接口很容易找,大概率是带有login这样关键字的接口,或者提交或者响应数据带有账号密码的接口。该网站的登录接口就是这个:/cgi-bin/bizlogin?action=startlogin

2. 函数定位

定位有很多种方式,看自己的爱好,一般可以直接搜索关键字,如果搜索结果数量较少就好办了,实在不行再选择其他方式。

搜索pwd这个特殊的关键字,可以对结果一一排除:

  • 首先排除掉css文件
  • loginpage.xxx.js 这个有点像,待会重点检查
  • listxxx.js 这个点进去可以看到是别的内容,排除掉
  • 最后一个是网页内容,排除掉

综上所述,就定位到了具体位置在第二个文件里。

但是这里明显没有pwd的具体加密的方式,这时候就可以在当前文件里搜索pwd这个关键字,在感觉可能的地方打断点。

3. 定位加密函数

这时候搜索到第二个位置的时候看到如下函数:

这是一个post方法,包含的数据里有pwd,且是由一个函数生成的。再次进行请求,可以在控制台里试一下。

符合预期,就是这里生成的密文。

u(n.pwd.substr(0, 16))
'25f9e794323b453885f5181f1b624d0b'
n.pwd.substr(0, 16)
'123456789'

所以u函数就是关键。

可以看到这个函数关键在于返回值的处理,这可以理解为嵌套的三元条件表达式。首先,根据 JavaScript 的运算符优先级,

JavaScript 的运算符优先级决定了表达式中各种运算符的执行顺序。以下是一些常见运算符按照优先级从高到低的顺序:

  1. ()(括号,最高优先级)
  2. .(点运算符)
  3. [](方括号运算符)
  4. ++--(前缀)
  5. !~+-(一元运算符)
  6. **(幂运算)
  7. */%(乘法、除法、取余)
  8. +-(加法、减法)
  9. <<>>>>>(移位运算符)
  10. <<=>>=instanceofin(关系运算符)
  11. ==!====!==(相等性运算符)
  12. &(按位与)
  13. ^(按位异或)
  14. |(按位或)
  15. &&(逻辑与)
  16. ||(逻辑或)
  17. ? :(条件运算符)
  18. =+=-=*=/=%=<<=>>=>>>=&=^=|=(赋值运算符)

我们可以给表达式加上括号,以更清晰地表示它的结构:

 t ? n ? i(t, e)  : o(i(t, e))  : n ? r(e)  : o(r(e))
(t ? (n ? i(t, e) : o(i(t, e))) : (n ? r(e) : o(r(e))))

这样,我们可以按照以下顺序解释表达式的执行:

  1. 如果 t 为真,则执行 (n ? i(t, e) : o(i(t, e)))
    • 如果 n 为真,则执行 i(t, e)
    • 如果 n 为假,则执行 o(i(t, e))
  2. 如果 t 为假,则执行 (n ? r(e) : o(r(e)))
    • 如果 n 为真,则执行 r(e)
    • 如果 n 为假,则执行 o(r(e))

最终,整个表达式的结果将取决于条件 tn 的值,以及相应分支函数 i(t, e)r(e)o() 的返回值。这种嵌套的条件结构可以根据实际情况来决定执行哪个分支。

虽然我们熟悉了怎么来执行这个三元条件表达式,但是由于存在很多函数的嵌套,导致并不能很快的在自己的代码中重写。因此我们可以使用更直接的方式,调用JS。

三、代码实现

判断函数作用域,完全复制,然后执行,如果报错就接着补。

function l(e, t) {
    
    
    var n = (65535 & e) + (65535 & t);
    return (e >> 16) + (t >> 16) + (n >> 16) << 16 | 65535 & n
}

function a(e, t, n, o, r, i) {
    
    
    return l((t = l(l(t, e), l(o, i))) << r | t >>> 32 - r, n)
}

function d(e, t, n, o, r, i, s) {
    
    
    return a(t & n | ~t & o, e, t, r, i, s)
}

function f(e, t, n, o, r, i, s) {
    
    
    return a(t & o | n & ~o, e, t, r, i, s)
}

function m(e, t, n, o, r, i, s) {
    
    
    return a(t ^ n ^ o, e, t, r, i, s)
}

function g(e, t, n, o, r, i, s) {
    
    
    return a(n ^ (t | ~o), e, t, r, i, s)
}

function s(e, t) {
    
    
    e[t >> 5] |= 128 << t % 32, e[14 + (t + 64 >>> 9 << 4)] = t;
    for (var n, o, r, i, s = 1732584193, a = -271733879, c = -1732584194, u = 271733878, p = 0; p < e.length; p += 16) s = d(n = s, o = a, r = c, i = u, e[p], 7, -680876936), u = d(u, s, a, c, e[p + 1], 12, -389564586), c = d(c, u, s, a, e[p + 2], 17, 606105819), a = d(a, c, u, s, e[p + 3], 22, -1044525330), s = d(s, a, c, u, e[p + 4], 7, -176418897), u = d(u, s, a, c, e[p + 5], 12, 1200080426), c = d(c, u, s, a, e[p + 6], 17, -1473231341), a = d(a, c, u, s, e[p + 7], 22, -45705983), s = d(s, a, c, u, e[p + 8], 7, 1770035416), u = d(u, s, a, c, e[p + 9], 12, -1958414417), c = d(c, u, s, a, e[p + 10], 17, -42063), a = d(a, c, u, s, e[p + 11], 22, -1990404162), s = d(s, a, c, u, e[p + 12], 7, 1804603682), u = d(u, s, a, c, e[p + 13], 12, -40341101), c = d(c, u, s, a, e[p + 14], 17, -1502002290), s = f(s, a = d(a, c, u, s, e[p + 15], 22, 1236535329), c, u, e[p + 1], 5, -165796510), u = f(u, s, a, c, e[p + 6], 9, -1069501632), c = f(c, u, s, a, e[p + 11], 14, 643717713), a = f(a, c, u, s, e[p], 20, -373897302), s = f(s, a, c, u, e[p + 5], 5, -701558691), u = f(u, s, a, c, e[p + 10], 9, 38016083), c = f(c, u, s, a, e[p + 15], 14, -660478335), a = f(a, c, u, s, e[p + 4], 20, -405537848), s = f(s, a, c, u, e[p + 9], 5, 568446438), u = f(u, s, a, c, e[p + 14], 9, -1019803690), c = f(c, u, s, a, e[p + 3], 14, -187363961), a = f(a, c, u, s, e[p + 8], 20, 1163531501), s = f(s, a, c, u, e[p + 13], 5, -1444681467), u = f(u, s, a, c, e[p + 2], 9, -51403784), c = f(c, u, s, a, e[p + 7], 14, 1735328473), s = m(s, a = f(a, c, u, s, e[p + 12], 20, -1926607734), c, u, e[p + 5], 4, -378558), u = m(u, s, a, c, e[p + 8], 11, -2022574463), c = m(c, u, s, a, e[p + 11], 16, 1839030562), a = m(a, c, u, s, e[p + 14], 23, -35309556), s = m(s, a, c, u, e[p + 1], 4, -1530992060), u = m(u, s, a, c, e[p + 4], 11, 1272893353), c = m(c, u, s, a, e[p + 7], 16, -155497632), a = m(a, c, u, s, e[p + 10], 23, -1094730640), s = m(s, a, c, u, e[p + 13], 4, 681279174), u = m(u, s, a, c, e[p], 11, -358537222), c = m(c, u, s, a, e[p + 3], 16, -722521979), a = m(a, c, u, s, e[p + 6], 23, 76029189), s = m(s, a, c, u, e[p + 9], 4, -640364487), u = m(u, s, a, c, e[p + 12], 11, -421815835), c = m(c, u, s, a, e[p + 15], 16, 530742520), s = g(s, a = m(a, c, u, s, e[p + 2], 23, -995338651), c, u, e[p], 6, -198630844), u = g(u, s, a, c, e[p + 7], 10, 1126891415), c = g(c, u, s, a, e[p + 14], 15, -1416354905), a = g(a, c, u, s, e[p + 5], 21, -57434055), s = g(s, a, c, u, e[p + 12], 6, 1700485571), u = g(u, s, a, c, e[p + 3], 10, -1894986606), c = g(c, u, s, a, e[p + 10], 15, -1051523), a = g(a, c, u, s, e[p + 1], 21, -2054922799), s = g(s, a, c, u, e[p + 8], 6, 1873313359), u = g(u, s, a, c, e[p + 15], 10, -30611744), c = g(c, u, s, a, e[p + 6], 15, -1560198380), a = g(a, c, u, s, e[p + 13], 21, 1309151649), s = g(s, a, c, u, e[p + 4], 6, -145523070), u = g(u, s, a, c, e[p + 11], 10, -1120210379), c = g(c, u, s, a, e[p + 2], 15, 718787259), a = g(a, c, u, s, e[p + 9], 21, -343485551), s = l(s, n), a = l(a, o), c = l(c, r), u = l(u, i);
    return [s, a, c, u]
}

function c(e) {
    
    
    for (var t = "", n = 0; n < 32 * e.length; n += 8) t += String.fromCharCode(e[n >> 5] >>> n % 32 & 255);
    return t
}

function u(e) {
    
    
    var t, n = [];
    for (n[(e.length >> 2) - 1] = void 0, t = 0; t < n.length; t += 1) n[t] = 0;
    for (t = 0; t < 8 * e.length; t += 8) n[t >> 5] |= (255 & e.charCodeAt(t / 8)) << t % 32;
    return n
}

function o(e) {
    
    
    for (var t, n = "0123456789abcdef", o = "", r = 0; r < e.length; r += 1) t = e.charCodeAt(r), o += n.charAt(t >>> 4 & 15) + n.charAt(15 & t);
    return o
}

function p(e) {
    
    
    return unescape(encodeURIComponent(e))
}

function r(e) {
    
    
    return c(s(u(e = p(e)), 8 * e.length))
}

function i(e, t) {
    
    
    var n, e = p(e), t = p(t), o = u(e), r = [], i = [];
    for (r[15] = i[15] = void 0, 16 < o.length && (o = s(o, 8 * e.length)), n = 0; n < 16; n += 1) r[n] = 909522486 ^ o[n], i[n] = 1549556828 ^ o[n];
    return e = s(r.concat(u(t)), 512 + 8 * t.length), c(s(i.concat(e), 640))
}

而对于关键函数可以单独摘出来,进行调用。

function getPwd(e, t, n) {
    
    
    return t ? n ? i(t, e) : o(i(t, e)) : n ? r(e) : o(r(e))
}

最后执行该JS文件:

import execjs


def encrypt(pwd):
    encrypt_str = execjs.compile(open("mp.weixin.com_login.js", encoding="utf-8").read()).call("getPwd", pwd)
    return encrypt_str


if __name__ == '__main__':
    new_str = encrypt('12345678')
    print(new_str)
    
# 输出
25d55ad283aa400af464c76d713c07ad

至此,实现了密文的复现。

四、总结回顾

该网站的密码的加密逆向很简单,加密的函数也比较少。其实很多时候对于逆向来说,最终能实现功能才是最重要的,实现的方法和过程并不重要。可以说用Python代码用个半小时完全重写一遍,当然也可以几分钟直接调用JS得到结果,两者之间并没有高低之分。

在解决逆向问题的时候一定要先定位到准确的位置,否则就是南辕北辙。
请添加图片描述

猜你喜欢

转载自blog.csdn.net/u013046615/article/details/134418718
今日推荐