风尘剑心 发布于2022年11月8日 分享 发布于2022年11月8日 0x00 前言 在上篇文章《VMware Workspace ONE Access漏洞调试环境搭建》 提到连接数据库的口令加密保存在文件/usr/local/horizon/conf/runtime-config。性能中,本文将要基于调试环境,分析加密流程,介绍详细的解密方法。 0x01 简介 本文将要介绍以下内容 加密流程 解密方法 数据库操作 0x02 加密流程 1.定位关键文件 经过一段时间的寻找,找到实现加密功能对应的文件为/opt/VMware/cert proxy/lib/horizon-config-encrypter-0.15。冲突 反编译获得加密的实现代码如下: 公共最终字符串加密(字节[]数据){ 如果(数据!=空数据,长度!=0) { 如果(!this.getKeyMgmt().randomKeyEnabled()!this.getKeyMgmt().customKeysAvailable()) { log.error('没有可用的自定义加密密钥,中止加密。'); 返回空 }否则{ 密码加密密码=这个。getencrypt密码(); 尝试{ if (encryptCipher!=null) { byte[]utf8=数组实用程序。addall(加密密码。getiv()、加密密码。做final(数据)); 字节缓冲区。分配(2); 密钥缓冲区。简而言之(这个。getkey管理().getCurrentKey()); utf8=数组实用程序。addall(密钥缓冲区。array()、utf8); utf8=ArrayUtils.insert(0,utf8,new byte[]{(byte)this。getkey管理().getcurrentciperversion()}); byte[]dec=base64。编码基数64(utf8); 返回新字符串(十二月,标准字符集.US _ ASCII); } } catch(IllegalBlockSizeException | IllegalStateException | BadPaddingException var 6){ log.error(var6.getMessage(),var 6); } 返回空 } }否则{ 返回空 } } 2.动态调试 为了提高分析效率,采取动态调试的方法,流程如下: (1)新建Java工程 下载访问VMware Workspace ONE服务器中/opt/vmware/certproxy/lib/下的所有冲突文件并保存,在Java 语言(一种计算机语言,尤用于创建网站)语言(一种计算机语言,尤用于创建网站)工程导入以上冲突文件 新建包:com。VMware。地平线。常见。utils。配置 新建文件ConfigEncrypterImpl.java,内容如下: 包com。VMware。地平线。常见。utils。配置; 导入com。谷歌。常见。注释。测试可见; 导入com。VMware。地平线。API。配置加密器; 导入com。VMware。地平线。随机的。securerandomutils 导入com。VMware。地平线。安全。安全提供者助手; 导入Java。nio。字节缓冲区; 导入Java。nio。字符集。字符集; 导入Java。nio。字符集。标准字符集; 导入Java。安全。invalidalgorithm参数异常; 导入Java。安全。invalidkeyexception 导入Java。安全。nosuchalgorithm异常; 导入Java。安全。securerandom 导入javax。注释。非空; 导入javax。注释。可空; 导入javax。密码。badpaddingexception 导入javax。密码。密码; 导入javax。密码。illegalblocksizeexception 导入javax。密码。nosuchpaddingexception 导入javax。密码。密钥; 导入javax。密码。规格。ivparameterspec 导入javax。密码。规格。secretkeyspec 导入org。阿帕奇。公地。编解码器。二进制。base64 导入org。阿帕奇。公地。郎3。数组实用程序; 导入org。阿帕奇。公地。郎3。字符串实用程序; 导入组织。充气城堡。密码。FIPS。fipsunapprovedoperationerror 导入org。slf4j。记录者; 导入org。SLF 4j。伐木工厂; 公共类ConfigEncrypterImpl实现ConfigEncrypter { 公共静态最终字符集编码字符集 私有静态最终记录器日志; 私有静态最终安全域斯兰德 私有静态configencrypterinmpl静态密钥实例; private static final configencrypteripl randomKeyInstance; 私有静态最终对象keyInstanceLock 私有ConfigEncrypterKeyMgmt密钥管理; 私有静态configencrypteripl createRandomKeyInstance(){ 安全提供者助手。initializesecurityprovider(); 返回新的configencrypterinpl(false); } 公共静态configencrypterinmpl getInstance(){ 同步(keyInstanceLock) { if (staticKeyInstance==null) { 静态密钥实例=new configencrypteripl(true); } 返回staticKeyInstance } } 公共静态configencrypteripl getRandomKeyInstance(){ 返回randomKeyInstance } private configencrypterinmpl(boolean useStaticKey){ if(使用静态键布尔值。分析布尔值(configpropertiesutil。获取属性().getProperty('组件。配置加密程序。kms。启用')){ log.info('未初始化静态配置密钥库。将KMS用于安全配置属性'); 这个。密钥管理=空; }否则{ 这个。key mgmt=new ConfigEncrypterKeyMgmt(useStaticKey); } } @VisibleForTesting configencrypteripl(ConfigEncrypterKeyMgmt密钥管理){ 这个。密钥管理=密钥管理; } @Nullable 公共最终字符串解密(字符串数据){ if (StringUtils.isBlank(data)) { 返回空 }否则{ byte[]加密=数据。getbytes(编码字符集); 布尔型b64 尝试{ b64=Base64.isBase64(加密); } catch(ArrayIndexOutOfBoundsException var 11){ b64=假; } 如果(b64) { encrypted=Base64.decodeBase64(加密); } if (ArrayUtils.isEmpty(加密)){ 返回空 }否则{ int密码版本=数学。ABS(加密[0]); 密码解密密码=空 if(密码版本=this。getkey管理().getMinCipherVersion()密码版本=this。getkey管理().getMaxCipherVersion()) { encrypted=arrayutils移除(加密,0); short keyIdx=ByteBuffer.wrap(加密,0,2)。get short(0); encrypted=数组实用程序。子数组(加密,2,加密。长度); 解密密码=这个。getdecrypt cipher(密码版本,this.getKeyMgmt().getKey(keyIdx),加密); } if (decryptCipher!=null) { encrypted=数组实用程序。subarray(加密,this.getKeyMgmt().getCipherNonceSize(密码版本,decryptCipher.getBlockSize()),加密。长度); 尝试{ byte[]utf8=解密密码。做最后的(加密); if (utf8.length 0) { 返回新字符串(utf8,编码字符集); } log.debug('零长度解密'); } catch(BadPaddingException var 7){ log.debug('无法解密给定值(填充)'); } catch(IllegalBlockSizeException var 8){ log.debug('无法解密给定值(块大小)'); } catch(ArrayIndexOutOfBoundsException var 9){ log.debug('无法解密给定值(mac验证)'); } catch(IllegalStateException var 10){ log.debug('无法解密给定值(非法状态)'); } } 返回空 } } } @Nullable 公共最终字符串加密(@非空字符串数据){ 返回StringUtils.isBlank(数据)?null:这个。加密(数据。getbytes(编码字符集)); } @Nullable 公共最终字符串加密(字节[]数据){ 如果(数据!=空数据,长度!=0) { 如果(!this.getKeyMgmt().randomKeyEnabled()!this.getKeyMgmt().customKeysAvailable()) { log.error('没有可用的自定义加密密钥,中止加密。'); 返回空 }否则{ 密码加密密码=这个。getencrypt密码(); 尝试{ if (encryptCipher!=null) { byte[]utf8=数组实用程序。addall(加密密码。getiv()、加密密码。做final(数据)); 字节缓冲区。分配(2); 密钥缓冲区。简而言之(这个。getkey管理().getCurrentKey()); utf8=数组实用程序。addall(密钥缓冲区。array()、utf8); utf8=ArrayUtils.insert(0,utf8,new byte[]{(byte)this。getkey管理().getcurrentciperversion()}); byte[]dec=base64。编码基数64(utf8); 返回新字符串(十二月,标准字符集.US _ ASCII); } } catch(IllegalBlockSizeException | IllegalStateException | BadPaddingException var 6){ log.error(var6.getMessage(),var 6); } 返回空 } }否则{ 返回空 } } @Nullable 私有密码获取解密密码(int Cipher版本,byte[] decryptionKey,byte[] iv) { 密码解密密码=空 如果(!ArrayUtils.isEmpty(iv)) { 尝试{ 解密密码=密码。getinstance(这个。getkey管理().getCipher(cipherVersion),securityproviderhelper。getjceprovider()); IvParameterSpec iv spec=new IvParameterSpec(数组实用程序。subarray(iv,0,this.getKeyMgmt().getCipherNonceSize(密码版本,解密密码。getblocksize())); secret key secret=new secret key spec(解密密钥,this.getKeyMgmt().getCipher(cipherVersion)). decryptCipher.init(2,secret,ivSpec,srand); } catch(invalidalgorithmhparameterexception | InvalidKeyException | nosuchalgorithm exception | nosuchpaddingeexception | IllegalArgumentException | FipsUnapprovedOperationError var 7){ log.error(var7.getMessage(),var 7); decryptCipher=null } } 返回解密密码 } @Nullable 私有密码getEncryptCipher() { 密码加密密码=空 尝试{ 加密密码=密码。getinstance(这个。getkey管理().getCipher()、安全提供者助手。getjceprovider()); 字节[] iv=新字节[this.getKeyMgmt().getCipherNonceSize(加密密码。getblocksize())]; srand。next bytes(iv); 秘密密钥秘密=新的秘密密钥规范(this。getkey管理().getKey(),this.getKeyMgmt().getCipher()); IvParameterSpec iv spec=new IvParameterSpec(iv); encryptCipher.init(1,secret,ivSpec,srand); } catch(invalidalgorithmhparameterexception | IllegalArgumentException | NoSuchPaddingException | nosuchalgorithm exception | InvalidKeyException | FipsUnapprovedOperationError var 5){ log.error(var5.getMessage(),var 5); } 返回加密密码 } @VisibleForTesting ConfigEncrypterKeyMgmt获取密钥管理(){ 返回这个。密钥管理。 } @VisibleForTesting public void setCustomEncryptionKeystorePath(@非空字符串路径){ this.getKeyMgmt().setCustomEncryptionKeystorePath(path); } public final boolean generateNewEncryptionKey(){ 返回this.getKeyMgmt().generateNewEncryptionKey(); } 公共静态void main(String[]值){ 字符串值=' 1234567890 '; configencrypteripl encrypter=getInstance(); 系统。出去。println(加密器。加密(值)); } 静态{ 编码字符集=标准字符集.ISO _ 8859 _ 1; log=记录器工厂。获取记录器(configencrypteripl。类); srand=securerandomutils。getsecurerandominstance(); randomkey实例=createrandomkey实例(); keyInstanceLock=new Object(); } } (2)动态调试 想法设置好远程调试参数,开启远程调试,分析结果如下: 在初始化过程中,需要读取文件\ usr \ local \ horizon \ conf \ runtime-config。属性,如下图 加密过程需要读取密钥文件1 \ usr \ local \ horizon \ conf \ config密钥库。通过,如下图 加密过程需要读取密钥文件2 \ usr \ local \ horizon \ conf \ config密钥库。bcfks,如下图 (3)实现加密功能 在访问VMware Workspace ONE服务器下载以下文件: \ usr \ local \ horizon \ conf \ runtime-config。性能 \ usr \ local \ horizon \ conf \ config密钥库。及格 \ usr \ local \ horizon \ conf \ config密钥库。bcfks 保存至C:\test 修改以下变量: DEFAULT _ PROPERTIES _ FILE=' c:\ \ test \ \ runtime-config。属性'; CUSTOM _ ENCRYPTION _ KEYSTORE _ PATH=' c:\ \ test \ '; 实现加密功能,如下图 0x03 解密方法 1.获取连接数据库的加密口令 加密数据对应文件/usr/local/horizon/conf/runtime-config。性能中的secure.datastore.jdbc.password 我的测试环境内容为baa cs 8 MW 1 xy me 7/8 ond 2 qwtg 3 MW 37 wf 1/1 pq 6d 09 xxqf 56 ncfrtcun 6y 8 a 1 xftjajhu 60v 1 qnyncoxk 3t 1m 0 dv 0 jva==,如下图 2.数据解密 代码如下: 线贬值=' baa cs 8 MW 1 xyme 7/8 ond 2 qwtg 3 MW 37 wf 1/1 pq 6d 09 xxqf 56 ncfrtcun 6y 8 a 1 xftjajhu 60v 1 qnyncoxk 3t 1m 0 dv 0 jva=='; 系统。出去。println(加密器。解密(贬值)); 解密出明文口令kuxmsscstqhxnqefbzawyml-das CX 0i,如下图 同/usr/local/地平线/conf/db.pwd中的内容一致,解密成功 0x04 数据库操作 (1)查看所有数据库 psql -h本地主机-U地平线-l 输入连接口令kuxmsscstqhxnqefbzawyml-das CX 0 I 查询结果如下图 存储数据的数据库为saas (2)导出用户表信息 psql -h localhost -U horizon -c '从用户的中选择结构名称';-d saas -W 输入连接口令kuxmsscstqhxnqefbzawyml-das CX 0 I 这里需要注意,对于一种数据库系统数据库,查询含有大写字母的字段必须加双引号,否则报错提示找不到表名 查询结果如下图 以上操作的戈朗语言实现代码已上传至github,地址如下: https://github。com/3g student/home-of-Go/blob/master/workspace one _ Query _ PostgreSQL。去 导出口令信息,结果如下图 0x05 小结 本文介绍了利用VMware Workspace ONE Access漏洞调试环境破解数据库加密口令的方法,记录技术细节。 留下回复 链接帖子 意见的链接 分享到其他网站 更多分享选项…
推荐的帖子