Jump to content

0x00 前言在上篇文章《VMware Workspace ONE Access漏洞调试环境搭建》 提到連接數據庫的口令加密保存在文件/usr/local/horizon/conf/runtime-config.properties中,本文將要基於調試環境,分析加密流程,介紹詳細的解密方法。

0x01 簡介本文將要介紹以下內容

加密流程

解密方法

數據庫操作

0x02 加密流程1.定位關鍵文件經過一段時間的尋找,找到實現加密功能對應的文件為/opt/vmware/certproxy/lib/horizon-config-encrypter-0.15.jar

反編譯獲得加密的實現代碼如下:

publicfinalStringencrypt(byte[]data){

if(data!=nulldata.length!=0){

if(!this.getKeyMgmt().randomKeyEnabled()!this.getKeyMgmt().customKeysAvailable()){

log.error('Nocustomencryptionkeysavailable,abortingencrypt.');

returnnull;

}else{

CipherencryptCipher=this.getEncryptCipher();

try{

if(encryptCipher!=null){

byte[]utf8=ArrayUtils.addAll(encryptCipher.getIV(),encryptCipher.doFinal(data));

ByteBufferkeyBuffer=ByteBuffer.allocate(2);

keyBuffer.putShort(this.getKeyMgmt().getCurrentKey());

utf8=ArrayUtils.addAll(keyBuffer.array(),utf8);

utf8=ArrayUtils.insert(0,utf8,newbyte[]{(byte)this.getKeyMgmt().getCurrentCipherVersion()});

byte[]dec=Base64.encodeBase64(utf8);

returnnewString(dec,StandardCharsets.US_ASCII);

}

}catch(IllegalBlockSizeException|IllegalStateException|BadPaddingExceptionvar6){

log.error(var6.getMessage(),var6);

}

returnnull;

}

}else{

returnnull;

}

}2.動態調試

為了提高分析效率,採取動態調試的方法,流程如下:

(1)新建Java工程

下載VMware Workspace ONE Accessd服務器中/opt/vmware/certproxy/lib/下的所有jar文件並保存,在Java工程導入以上jar文件

新建package:com.vmware.horizon.common.utils.config

新建文件ConfigEncrypterImpl.java,內容如下:

packagecom.vmware.horizon.common.utils.config;

importcom.google.common.annotations.VisibleForTesting;

importcom.vmware.horizon.api.ConfigEncrypter;

importcom.vmware.horizon.random.SecureRandomUtils;

importcom.vmware.horizon.security.SecurityProviderHelper;

importjava.nio.ByteBuffer;

importjava.nio.charset.Charset;

importjava.nio.charset.StandardCharsets;

importjava.security.InvalidAlgorithmParameterException;

importjava.security.InvalidKeyException;

importjava.security.NoSuchAlgorithmException;

importjava.security.SecureRandom;

importjavax.annotation.Nonnull;

importjavax.annotation.Nullable;

importjavax.crypto.BadPaddingException;

importjavax.crypto.Cipher;

importjavax.crypto.IllegalBlockSizeException;

importjavax.crypto.NoSuchPaddingException;

importjavax.crypto.SecretKey;

importjavax.crypto.spec.IvParameterSpec;

importjavax.crypto.spec.SecretKeySpec;

importorg.apache.commons.codec.binary.Base64;

importorg.apache.commons.lang3.ArrayUtils;

importorg.apache.commons.lang3.StringUtils;

importorg.bouncycastle.crypto.fips.FipsUnapprovedOperationError;

importorg.slf4j.Logger;

importorg.slf4j.LoggerFactory;

publicclassConfigEncrypterImplimplementsConfigEncrypter{

publicstaticfinalCharsetencodingCharset;

privatestaticfinalLoggerlog;

privatestaticfinalSecureRandomsrand;

privatestaticConfigEncrypterImplstaticKeyInstance;

privatestaticfinalConfigEncrypterImplrandomKeyInstance;

privatestaticfinalObjectkeyInstanceLock;

privateConfigEncrypterKeyMgmtkeyMgmt;

privatestaticConfigEncrypterImplcreateRandomKeyInstance(){

SecurityProviderHelper.initializeSecurityProvider();

returnnewConfigEncrypterImpl(false);

}

publicstaticConfigEncrypterImplgetInstance(){

synchronized(keyInstanceLock){

if(staticKeyInstance==null){

staticKeyInstance=newConfigEncrypterImpl(true);

}

returnstaticKeyInstance;

}

}

publicstaticConfigEncrypterImplgetRandomKeyInstance(){

returnrandomKeyInstance;

}

privateConfigEncrypterImpl(booleanuseStaticKey){

if(useStaticKeyBoolean.parseBoolean(ConfigPropertiesUtil.getProperties().getProperty('components.configEncrypter.kms.enable'))){

log.info('Notinitializingstaticconfigkeystore.UsingKMSforsecureconfigproperties');

this.keyMgmt=null;

}else{

this.keyMgmt=newConfigEncrypterKeyMgmt(useStaticKey);

}

}

@VisibleForTesting

ConfigEncrypterImpl(ConfigEncrypterKeyMgmtkeyMgmt){

this.keyMgmt=keyMgmt;

}

@Nullable

publicfinalStringdecrypt(Stringdata){

if(StringUtils.isBlank(data)){

returnnull;

}else{

byte[]encrypted=data.getBytes(encodingCharset);

booleanb64;

try{

b64=Base64.isBase64(encrypted);

}catch(ArrayIndexOutOfBoundsExceptionvar11){

b64=false;

}

if(b64){

encrypted=Base64.decodeBase64(encrypted);

}

if(ArrayUtils.isEmpty(encrypted)){

returnnull;

}else{

intcipherVersion=Math.abs(encrypted[0]);

CipherdecryptCipher=null;

if(cipherVersion=this.getKeyMgmt().getMinCipherVersion()cipherVersion0){

returnnewString(utf8,encodingCharset);

}

log.debug('zerolengthdecryption');

}catch(BadPaddingExceptionvar7){

log.debug('Failedtodecryptthegivenvalue(padding)');

}catch(IllegalBlockSizeExceptionvar8){

log.debug('Failedtodecryptthegivenvalue(blocksize)');

}catch(ArrayIndexOutOfBoundsExceptionvar9){

log.debug('Failedtodecryptthegivenvalue(macverification)');

}catch(IllegalStateExceptionvar10){

log.debug('Failedtodecryptthegivenvalue(illegalstate)');

}

}

returnnull;

}

}

}

@Nullable

publicfinalStringencrypt(@NonnullStringdata){

returnStringUtils.isBlank(data)?null:this.encrypt(data.getBytes(encodingCharset));

}

@Nullable

publicfinalStringencrypt(byte[]data){

if(data!=nulldata.length!=0){

if(!this.getKeyMgmt().randomKeyEnabled()!this.getKeyMgmt().customKeysAvailable()){

log.error('Nocustomencryptionkeysavailable,abortingencrypt.');

returnnull;

}else{

CipherencryptCipher=this.getEncryptCipher();

try{

if(encryptCipher!=null){

byte[]utf8=ArrayUtils.addAll(encryptCipher.getIV(),encryptCipher.doFinal(data));

ByteBufferkeyBuffer=ByteBuffer.allocate(2);

keyBuffer.putShort(this.getKeyMgmt().getCurrentKey());

utf8=ArrayUtils.addAll(keyBuffer.array(),utf8);

utf8=ArrayUtils.insert(0,utf8,newbyte[]{(byte)this.getKeyMgmt().getCurrentCipherVersion()});

byte[]dec=Base64.encodeBase64(utf8);

returnnewString(dec,StandardCharsets.US_ASCII);

}

}catch(IllegalBlockSizeException|IllegalStateException|BadPaddingExceptionvar6){

log.error(var6.getMessage(),var6);

}

returnnull;

}

}else{

returnnull;

}

}

@Nullable

privateCiphergetDecryptCipher(intcipherVersion,byte[]decryptionKey,byte[]iv){

CipherdecryptCipher=null;

if(!ArrayUtils.isEmpty(iv)){

try{

decryptCipher=Cipher.getInstance(this.getKeyMgmt().getCipher(cipherVersion),SecurityProviderHelper.getJceProvider());

IvParameterSpecivSpec=newIvParameterSpec(ArrayUtils.subarray(iv,0,this.getKeyMgmt().getCipherNonceSize(cipherVersion,decryptCipher.getBlockSize())));

SecretKeysecret=newSecretKeySpec(decryptionKey,this.getKeyMgmt().getCipher(cipherVersion));

decryptCipher.init(2,secret,ivSpec,srand);

}catch(InvalidAlgorithmParameterException|InvalidKeyException|NoSuchAlgorithmException|NoSuchPaddingException|IllegalArgumentException|FipsUnapprovedOperationErrorvar7){

log.error(var7.getMessage(),var7);

decryptCipher=null;

}

}

returndecryptCipher;

}

@Nullable

privateCiphergetEncryptCipher(){

CipherencryptCipher=null;

try{

encryptCipher=Cipher.getInstance(this.getKeyMgmt().getCipher(),SecurityProviderHelper.getJceProvider());

byte[]iv=newbyte[this.getKeyMgmt().getCipherNonceSize(encryptCipher.getBlockSize())];

srand.nextBytes(iv);

SecretKeysecret=newSecretKeySpec(this.getKeyMgmt().getKey(),this.getKeyMgmt().getCipher());

IvParameterSpecivSpec=newIvParameterSpec(iv);

encryptCipher.init(1,secret,ivSpec,srand);

}catch(InvalidAlgorithmParameterException|IllegalArgumentException|NoSuchPaddingException|NoSuchAlgorithmException|InvalidKeyException|FipsUnapprovedOperationErrorvar5){

log.error(var5.getMessage(),var5);

}

returnencryptCipher;

}

@VisibleForTesting

ConfigEncrypterKeyMgmtgetKeyMgmt(){

returnthis.keyMgmt;

}

@VisibleForTesting

publicvoidsetCustomEncryptionKeyst

0 Comments

Recommended Comments

There are no comments to display.

Guest
Add a comment...