密碼雜湊值在Oracle 12c資料庫中調整
密碼雜湊值在Oracle 12c資料庫中調整
Simeon
原文連結:
https://www.trustwave.com/Resources/SpiderLabs-Blog/Changes-in-Oracle-Database-12c-password-hashes/
Oracle在Oracle Database 12c中對使用者密碼雜湊進行了改進。通過使用基於PBKDF2的SHA512雜湊演算法,替代過去簡單的SHA1雜湊加密,使得密碼雜湊更安全。在這篇文章中,我將解釋一些變化及其安全影響。
1.Oracle密碼雜湊值
使用Oracle 11g資料庫時,sys.user$表中的spare4列儲存使用者密碼雜湊值。
這是sys.user$.spare4 使用者demo使用密碼“epsilon”(可插入資料庫)的輸入示例:
S:8F2D65FB5547B71C8DA3760F10960428CD307B1C6271691FC55C1F56554A;H:DC9894A01797D91D92ECA1DA66242209;T:23D1F8CAC9001F69630ED2DD8DF67DD3BE5C470B5EA97B622F757FE102D8BF14BEDC94A3CC046D10858D885DB656DC0CBF899A79CD8C76B788744844CADE54EEEB4FDEC478FB7C7CBFBBAC57BA3EF22C
詳細步驟:
SQL> create user demo identified by epsilon;
User created.
SQL> select spare4 from sys.user$ where name = 'DEMO';
S:8F2D65FB5547B71C8DA3760F10960428CD307B1C6271691FC55C1F56554A;H:DC9894A01797D91D92ECA1DA66242209;T:23D1F8CAC9001F69630ED2DD8DF67DD3BE5C470B5EA97B622F757FE102D8BF14BEDC94A3CC046D10858D885DB656DC0CBF899A79CD8C76B788744844CADE54EEEB4FDEC478FB7C7CBFBBAC57BA3EF22C
筆者注:查詢oracle使用者必須是大寫名稱
sys.user$.password跟demo使用者的密碼值一樣:
SQL> select password from sys.user$ where name = 'DEMO';
執行結果:
2B7983437FE9FEB6
筆者注:
執行查詢select password from sys.user$ where name = SYS';如圖1所示。
圖1獲取SYS使用者密碼值
這將省略password值的討論:它使用相同的演算法(大寫和連線使用者名稱和密碼,然後執行3DES雜湊)計算,跟以前的Oracle資料庫版本中使用一樣的演算法。
在spare4 列的值由分號分隔(“ S:”,“ H:”和“ T:”)的三個部分組成。
“S:”部分長度是60個字元或30個位元組:
8F2D65FB5547B71C8DA3760F10960428CD307B1C6271691FC55C1F56554A
“ H:”部分長度是32個字元或16個位元組:
DC9894A01797D91D92ECA1DA66242209
最後,“ T:”部分長度是160個字元或80個位元組:
23D1F8CAC9001F69630ED2DD8DF67DD3BE5C470B5EA97B622F757FE102D8BF14BEDC94A3CC046D10858D885DB656DC0CBF899A79CD8C76B788744844CADE54EEEB4FDEC478FB7C7CBFBBAC57BA3EF22C
那麼他們究竟有什麼含義呢?
2.S部分
在Oracle資料庫11g中有“ S:”部分,它的建立過程如下:
password hash (20 bytes) = sha1(password + salt (10 bytes))
(有關更多詳細資訊,請訪問http://marcel.vandewaters.nl/oracle/security/password-hashes。)
Oracle Database 12c也是如此:下面的簡單測試證明了這一點。
對於S上面的值(8F2D65FB5547B71C8DA3760F10960428CD307B1C6271691FC55C1F56554A):
雜湊是8F2D65FB5547B71C8DA3760F10960428CD307B1C,salt是6271691FC55C1F56554A
密碼是“epsilon”,所以讓我們來計算SHA1雜湊'epsilon' + 0x6271691FC55C1F56554A:
import hashlib
sha1 = hashlib.sha1()
sha1.update("epsilon")
sha1.update('\x62\x71\x69\x1f\xc5\x5c\x1f\x56\x55\x4a')
sha1.hexdigest().upper()
該計算產生:' 8F2D65FB5547B71C8DA3760F10960428CD307B1C',如圖2所示。
圖2計算epsilon的密碼值
這與11g演算法相同。
3.H部分
在$ORACLE_HOME/rdbms/admin下檢視一個SQL檔案時可以發現這一點:
create or replace view DBA_DIGEST_VERIFIERS
(USERNAME, HAS_DIGEST_VERIFIERS, DIGEST_TYPE) as
select u.name, 'YES', 'MD5' from user$ u where instr(spare4, 'H:')>0
union
select u.name, 'NO', NULL from user$ u where not(instr(spare4, 'H:')>0) or spare4 is null
/
所以它似乎是一個MD5雜湊加密。
請注意,下面的SQL程式碼$ORACLE_HOME/rdbms/admin 會修改spare4 列的值以刪除H: 降級。
這是spare4.H如何計算的:使用者名稱是大寫的,然後MD5雜湊加密計算其值,' XDB'和密碼用冒號分隔(也即md5('DEMO:XDB:epsilon'),32位加密):
import hashlib
m = hashlib.md5()
m.update('DEMO:XDB:epsilon')
m.hexdigest().upper()
'DC9894A01797D91D92ECA1DA66242209'
這使得可以使用預先計算密碼字典的雜湊值來對內建的使用者密碼進行***,例如使用字首SYSTEM:XDB:的系統使用者密碼。
該H值似乎用於XDB中的摘要式身份驗證。
4.T部分
這僅適用於12.1.0.2。對於12c之前的版本,T部分不可用。
我們通過更新sqlnet.ora 檔案(假設客戶端來自12.1.0.2發行版)來啟用12c密碼雜湊:
# sqlnet.ora
SQLNET.ALLOWED_LOGON_VERSION_SERVER = 12a
然後重新建立演示使用者(首先重新連線客戶端):
drop user demo;
create user demo identified by epsilon;
select spare4 from sys.user$ where name = 'DEMO';
H:DC9894A01797D91D92ECA1DA66242209;T:E3243B98974159CC24FD2C9A8B30BA62E0E83B6CA2FC7C55177C3A7F82602E3BDD17CEB9B9091CF9DAD672B8BE961A9EAC4D344BDBA878EDC5DCB5899F689EBD8DD1BE3F67BFF9813A464382381AB36B
注意到該spare4值不再包含“S:”部分,只有“H:”部分和“T:”部分在那裡。
在Oracle Database 12c文件中,我們可以找到這個:
5.關於12C驗證器
基於一個包含PBKDF2和SHA512的優化演算法,所以密碼應該通過PBKDF2,隨後SHA512來生成T(部分)。在認證期間,伺服器傳送所謂的AUTH_VFR_DATA (匹配值spare4.T的最後16個位元組)到客戶端:
-- Server to client packet snippet
39 39 39 00 00 00 00 0D-00 00 00 0D 41 55 54 48 999.........AUTH
5F 56 46 52 5F 44 41 54-41 20 00 00 00 20 38 44 _VFR_DATA.....8D
44 31 42 45 33 46 36 37-42 46 46 39 38 31 33 41 D1BE3F67BFF9813A
34 36 34 33 38 32 33 38-31 41 42 33 36 42 15 48 464382381AB36B.H
所以我們可以把這個T 值分成兩部分(前64個位元組和AUTH_VFR_DATA):
E3243B98974159CC24FD2C9A8B30BA62E0E83B6CA2FC7C55177C3A7F82602E3BDD17CEB9B9091CF9DAD672B8BE961A9EAC4D344BDBA878EDC5DCB5899F689EBD (前128個字元或64個位元組)8DD1BE3F67BFF9813A464382381AB36B (最後32個字元或16個位元組AUTH_VFR_DATA)
假設AUTH_VFR_DATA 密碼設定/重置時隨機生成。因此Python程式碼生成的第一個64位元組T 是(需要PBKDF2 Python模組):
import pbkdf2, hashlib
AUTH_VFR_DATA = b'\x8d\xd1\xbe\x3f\x67\xbf\xf9\x81\x3a\x46\x43\x82\x38\x1a\xb3\x6b' # This is received from the server once the latest protocol is negotiated
salt = AUTH_VFR_DATA + b'AUTH_PBKDF2_SPEEDY_KEY'
key = pbkdf2.PBKDF2("epsilon", salt, 4096, hashlib.sha512) # Password
key_64bytes = key.read(64) # This 64-byte derived key is encrypted by the client and sent to the server as AUTH_PBKDF2_SPEEDY_KEY
t = hashlib.sha512() # This happens on the server after they key is decrypted from the AUTH_PBKDF2_SPEEDY_KEY value
t.update(key_64bytes)
t.update(AUTH_VFR_DATA)
t.hexdigest().upper() # First 64 bytes of spare4.T: value if password is correct
執行結果:
E3243B98974159CC24FD2C9A8B30BA62E0E83B6CA2FC7C55177C3A7F82602E3BDD17CEB9B9091CF9DAD672B8BE961A9EAC4D344BDBA878EDC5DCB5899F689EBD
總結
Oracle在12c中添加了MD5雜湊和基於PBKDF2的SHA512雜湊加密。在Oracle文件中有一個引用:
用於生成12C 驗證的雜湊密碼函式是基於包含PBKDF2和SHA-512的非優化演算法。PBKDF2演算法通常被介紹為當擁有12C的驗證者找回原密碼時,面對***者所面臨的挑戰時的非對稱計算演算法。
筆者注:由於Oracle 12C驗證器存在,通過抓包,可以通過暴力破解來獲取Oracle的密碼,後續內容為筆者補充。
6.PBKDF2簡介及其演算法
(1)PBKDF2簡介
PBKDF2簡單而言就是將salted hash進行多次重複計算,這個次數是可選擇的。如果計算一次所需要的時間是1微秒,那麼計算1百萬次就需要1秒鐘。假如***一個密碼所需的rainbow table有1千萬條,建立所對應的rainbow table所需要的時間就是115天。這個代價足以讓大部分的***者忘而生畏。
(2)PBKDF2演算法
DK = PBKDF2(P,S,c,dkLen)
可選項: RPF 基本偽隨機函式(hLen表示偽隨機函式輸出的位元組長度)
輸入:
P 口令,一位元組串
S 鹽值,位元組串
c 迭代次數,正整數
dkLen 匯出金鑰的指定位元組長度,正整數,最大約(2^32-1)*hLen
輸出: DK 匯出金鑰,長度dkLen位元組
步驟:
1. 如果dkLen>(2^32-1)*hLen,輸出“derived key too long”並停止。
2. 假設l是匯出金鑰的hLen個位元組塊的個數,r表示最後一個塊的位元組數。
l = CEIL (dkLen / hLen) ,
r = dkLen - (l - 1) * hLen .
這裡,CEIL(x)是“ceiling”函式,即,大於或等於x的最小整數。
4. 對於匯出金鑰的每一塊,運用函式F於口令P、鹽S、迭代次數c和塊索引以計算塊:
T_1 = F (P, S, c, 1) ,
T_2 = F (P, S, c, 2) ,
...
T_l = F (P, S, c, l) ,
這裡函式F定義為基本偽隨機函式PRF應用於口令P和鹽S的串聯和塊索引i的前c次迴圈的異或和。
F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c
其中
U_1 = PRF (P, S || INT (i)) ,
U_2 = PRF (P, U_1) ,
...
U_c = PRF (P, U_{c-1}) .
這裡,INT(i)是整數i的四位元組編碼,高位元組在先。
3. 串聯各塊,抽取前dkLen位元組以產生匯出金鑰DK:
DK = T_1 || T_2 || ... || T_l<0..r-1>
4. 輸出匯出金鑰DK。
注意:函式F的構造遵循“belt-and-suspenders”方法。U_i次迴圈被遞迴計算以消除敵手的並行度;它們被異或到一起以減少有關遞迴退化到一個小的值集的擔憂。
密碼解密:
select username, password from dba_users;
hashcat -m 10200 -a 0 oracle.hash -o oracle.txt --remove oracle.hash wordlist.txt
hashcat -m 1800 -a 3 oracle.hash ?d?d?d?d?d?d?d?d?d?d?d