https://www.jianshu.com/p/d0a741c9439a

背景:最近公司生产环境通过堡垒机对数据库进行接管。通过堡垒机配置PL/SQL工具,启动后会自动进行用户名密码填充。这样数据库密码就不需要暴露给运维人员,而且可以通过堡垒机进行日志审计。·
为了验证堡垒机是通过认证模式进行连接还是通过填充密码的模式进行连接,先将PL/SQL的密码保存打开,然后通过堡垒机进行连接。连接成功后关闭PL/SQL并退出堡垒机。下次直接通过选择记住的用户进行登录,发现可以直接登录成功。说明,我司使用的堡垒机只是对用户密码,进行填充,并非采用认证转发的模式。

如何设置PL/SQL密码保存?

打开PL/SQL,依次进入目录:工具->首选项->登录历史;

 
保存密码设置界面

勾选存储历史及带密码存储,点击已确认,退出PL/SQL重新登录。

 
登录界面

成功登录后会自动保存密码,下次登录时可以点击用户名右边...按钮,通过下拉的用户列表进行选择,选择后PL/SQL会自动登录,不需要再输入密码。PL/SQL默认存储登录信息,不存储密码。

如何解密PL/SQL保存的密码?

数据

要想解密PL/SQL保存的密码,首先,我们需要知道密码存储位置。PL/SQL将登录信息及密码存储在user.prefs下。该文件一般存储在如下位置。其中<username>是你的用户名。

C:\Users<username>\AppData\Roaming\PLSQL Developer\Preferences<username>\
C:\Program Files\PLSQL Developer\Preferences<username>\
C:\Program Files (x86)\PLSQL Developer\Preferences<username>\

本人使用绿色版的PLSQL,存储位置为:C:\Users\Administrator\AppData\Roaming\PLSQL Developer\Preferences\Administrator 打开user.prefs文件,其中标题[LogonHistory]下面存在多行数字字符串,每一行即为一个登录信息,这些信息是加密的,其明文格式如下:

<username>/<password>@<server>

算法

加密算法非常简单,主要由位移和xor组成 。生成的密文看起来像这样:

273645624572423045763066456443024120413041724566408044424900419043284194407643904160

第一组四位数(2736)是密钥值-他是有系统运行时随机生成的四位数(大于2000,小于3000),后面每一位字符根据下面算法进行运算得到4位数字,直至加密完毕。

下面是JAVA实现的加密代码:

public static void cryptPassword() {
        int key = 2736;
        String plaintext = "user/password@server";
        String result = Integer.toString(key);
        for (int i = 0; i < plaintext.length(); i++) {
            int mask = Integer.valueOf(plaintext.charAt(i)) << 4;
            int n = (mask ^ (key + (i + 1) * 10)) + 1000;
            result += Integer.toString(n);
        }
        System.out.println(result);
    }

user/password@server加密结果为:

273645624572423045763066456443024120413041724566408044424900419043284194407643904160

下面是JAVA实现的解密代码:

public static void decryptPassword(){
        String cryptText = "273645624572423045763066456443024120413041724566408044424900419043284194407643904160";
        String plainText = "";
        ArrayList<Integer> values = new ArrayList<Integer>();
        for (int i = 0; i < cryptText.length(); i+= 4){
            values.add(Integer.parseInt((cryptText.substring(i, i + 4))));
        }
        int key = values.get(0);
        values.remove(0);
        for (int i = 0; i < values.size(); i++) {
            int val = values.get(i) - 1000;
            int mask = key + (10 * (i + 1));
            int res = (val ^ mask) >> 4;
            plainText += Character.toString((char)(res));
        }
        System.out.println("plainText:"+plainText);
    }

注意:生产环境切记不要开启保存密码的选项,否则本地环境一旦被人获取,生产密码将直接暴露,窃取者甚至不需要进行解密,直接将密文拷贝至PLSQL对应位置即可直接登录。
通过上面的破解过程,说明这种模式的数据库接管没有实际意义,并不能规避密码在内部泄露的问题。

参考资料:https://adamcaudill.com/2016/02/02/plsql-developer-nonexistent-encryption/



作者:tc_song
链接:https://www.jianshu.com/p/d0a741c9439a
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。