Call now: 252-767-6166  
Oracle Training Oracle Support Development Oracle Apps

Free Oracle Tips

HTML Text

 Home
 E-mail Us
 Oracle Articles


 Oracle Training
 Oracle Tips

 Oracle Forum
 Class Catalog


 Remote DBA
 Oracle Tuning
 Emergency 911
 RAC Support
 Apps Support
 Analysis
 Design
 Implementation
 Oracle Support


 SQL Tuning
 Security

 Oracle UNIX
 Oracle Linux
 Monitoring
 Remote s
upport
 Remote plans
 Remote
services
 Application Server

 Applications
 Oracle Forms
 Oracle Portal
 App Upgrades
 SQL Server
 Oracle Concepts
 Software Support

 Remote S
upport  
 Development  

 Implementation


 Consulting Staff
 Consulting Prices
 Help Wanted!

 


 Oracle Posters
 Oracle Books

 Oracle Scripts
 Ion
 Excel-DB   


 

 

 


 

 

 

 

 


Using Views as a Form of Access Control

Oracle Forensics tips by Paul Wright

VIEWs are also sometimes used as a form of access control by Oracle, in the Author’s opinion they should not be, but they are. For instance in the case of an undocumented VIEW called KU$_USER_VIEW. This VIEW contains the passwords of the users in an Oracle database, but the VIEW source code restricts the users who can view it. The privileges on the VIEW are to public ROLE but the actual source code in the VIEW checks who is reading the VIEW and grants access based on that.

This view relies solely on the source code of the view to stop PUBLIC users selecting from it as PUBLIC is granted SELECT on this VIEW by default. The KU$_USER_VIEW or KU$_ROLE_VIEW is a prime target for a rootkit and PUBLIC select should be revoked from this undocumented VIEW.

SQL> desc KU$_USER_VIEW;

 Name                                      Null?    Type
 ----------------------------------------- -------- ---------------------------
 VERS_MAJOR                                         CHAR(1)
 VERS_MINOR                                         CHAR(1)
 USER_ID                                            NUMBER
 NAME                                               VARCHAR2(30)
 TYPE_NUM                                           NUMBER
 PASSWORD                                           VARCHAR2(30)
 DATATS                                             VARCHAR2(30)
 TEMPTS                                             VARCHAR2(30)
 CTIME                                              DATE
 PTIME                                              DATE
 EXPTIME                                            DATE
 LTIME                                              DATE
 PROFNUM                                            NUMBER
 PROFNAME                                           VARCHAR2(30)
 USER_AUDIT                                         VARCHAR2(38)
 DEFROLE                                            NUMBER
 DEFGRP_NUM                                         NUMBER
 DEFGRP_SEQ_NUM                                     NUMBER
 ASTATUS                                            NUMBER

SQL> select grantee from dba_tab_privs where table_name='KU$_USER_VIEW';

GRANTEE
------------------------------
PUBLIC

This is a mislead privilege grant. Imagine granting PUBLIC execute to a table with passwords in it.

conn sys as sysdba
SQL> select name, password from KU$_USER_VIEW;

NAME                           PASSWORD
------------------------------ ------------------------------
SCOTT                          F894844C34402B67
MGMT_VIEW                      4F538DF5F344F348
MDDATA                         DF02A496267DEE66

NAME                           PASSWORD
------------------------------ ------------------------------
SYSMAN                         447B729161192C24
MDSYS                          72979A94BAD2AF80
XDB                            88D8364765FCE6AF
CTXSYS                         71E687F036AD56E5
EXFSYS                         66F4EF5650C20355
WMSYS                          7C9BA362F8314299

NAME                           PASSWORD
------------------------------ ------------------------------
DBSNMP                         E066D214D5421CCC
TSMSYS                         3DF26A8B17D0F29F
DMSYS                          BFBA5A553FD9E28A
DIP                            CE4A36B8E06CA59C
OUTLN                          0F763FE382235763
SYSTEM                         D4DF7931AB130E37
SYS                            8F496E0A85640576

SQL> conn scott/tiger

Connected.

SQL> desc KU$_USER_VIEW;

ERROR:

ORA-04043: object KU$_USER_VIEW does not exist

Question: How does this VIEW protect the viewing of passwords since it is has SELECT granted to PUBLIC?

Answer: It is in the source code, which is not good from a defense perspective as we shall see.

SQL>  set long 100000

SELECT owner, text
FROM all_views
WHERE owner = SYS
view_name = ‘
KU$_USER_VIEW’;

OWNER                          TEXT
------------------------------ -------------------------------------------------------------------
SYS                            select '1','0',
                                         u.user#,
                                         u.name,
                                         u.type#,
…….. 

OWNER                          TEXT
------------------------------ -------------------------------------------------------------------
                                                and cgm.status = 'ACTIVE'
                                                and cgm.value = u.name), u.defschclass),
                                         u.ext_username,
                                         u.spare1,
                                         u.spare2,
                                         u.spare3,
                                         u.spare4,
                                         u.spare5,
                                         u.spare6
                                 from sys.user$ u,
                                      sys.ts$ ts1, sys.ts$ ts2, sys.profname$ p
 

OWNER                          TEXT
------------------------------ -------------------------------------------------------------------
                                 where   u.datats# = ts1.ts# AND
                                         u.tempts# = ts2.ts# AND
                                         u.type# = 1 AND
                                         u.resource$ = p.profile#

                                         AND (SYS_CONTEXT('USERENV','CURRENT_USERID') = 0
                                               OR EXISTS ( SELECT * FROM session_roles
                                                      WHERE role='SELECT_CATALOG_ROLE' ))

As DBA we can change the source of the VIEW to  

                         AND (SYS_CONTEXT('USERENV','CURRENT_USERID') = 0
                               OR EXISTS ( SELECT username from dba_users ))
 

Now the attacker can VIEW the passwords whenever they want with a low privileged account and there has been no change to privileges or base tables. The only change is to the source code of the VIEW. As we already know it is trivial to change the hash to clear text  (OHH).

What is needed is an integrity check for the actual code that makes up the VIEW.

Here is a basic text output version. Note that the source to VIEWS in sys.view$ is a LONG not varchar2 text.

SET SERVEROUTPUT ON SIZE 1000000;
DECLARE
long_var LONG;
BEGIN
SELECT text INTO long_var
FROM dba_views
WHERE view_name='KU$_USER_VIEW';
DBMS_OUTPUT.PUT_LINE('The checksum dba_users is
'||dbms_utility.get_hash_value(long_var,1000000000,power(2,30)));
END;
/

SQL> SET SERVEROUTPUT ON SIZE 1000000;
SQL> DECLARE
  2  long_var LONG;
  3  BEGIN
  4  SELECT text INTO long_var
  5  FROM dba_views
  6  WHERE view_name='KU$_USER_VIEW';
  7  DBMS_OUTPUT.PUT_LINE('The checksum dba_users is
  8  '||dbms_utility.get_hash_value(long_var,1000000000,power(2,30)));
  9  END;
 10  /

The checksum dba_users is

1646689215

PL/SQL procedure successfully completed.

--use this to generate the number then run a check to see if it is the same

SET SERVEROUTPUT ON SIZE 1000000;
DECLARE
long_var LONG;
BEGIN
SELECT text INTO long_var
FROM dba_views
WHERE view_name='KU$_USER_VIEW';
if dbms_utility.get_hash_value(long_var,1000000000,power(2,30)) = 1646689215
then DBMS_OUTPUT.PUT_LINE('The checksum for dba_users is correct');
else
DBMS_OUTPUT.PUT_LINE('The checksum for dba_users is not correct');
end if;
end;
/

Need to do this query without using the name of the view from DBA_VIEWS.

SYS.VIEW$ is the base table.

SQL> desc sys.view$;

 Name      Null?    Type
 OBJ#               NOT NULL NUMBER
 AUDIT$             NOT NULL VARCHAR2(
 COLS               NOT NULL NUMBER
 INTCOLS            NOT NULL NUMBER
 PROPERTY  NOT NULL NUMBER
 FLAGS            NOT NULL NUMBER
 TEXTLENGTH       NUMBER

 TEXT             LONG

Better to use the base tables that contain the VIEW source code instead of DBA_VIEWS in order to check the integrity of the VIEW source code.

set long 4000 to be able to see all the code. Source Text in this case is just one big LONG datatype i.e. like a number.

Viewscheckums.sql ~ basic checksum query  for a view 

DECLARE
long_var LONG;
BEGIN
select sys.view$.text into long_var from sys.view$ left outer join
sys.obj$ on sys.view$.obj# = sys.obj$.obj# where sys.obj$.name='DBA_USERS';
if dbms_utility.get_hash_value(long_var,1000000000,power(2,30)) = 1958803667
then DBMS_OUTPUT.PUT_LINE('The checksum for dba_users is correct');
else
DBMS_OUTPUT.PUT_LINE('The checksum for dba_users is not correct');
end if;
end;
/
 

These VIEW integrity checks should be done before using the VIEWS to identify the integrity of OBJECTS as illustrated in previous chapters.

Automating the collection of VIEW source code metadata such as checksums, timestamps and file size is more complex due to the source text being in a number format called LONG. The next query deals with that and will allow for automatic collection of checksums on VIEW source of a given schema. These checksums should then be stored in the Depository for future comparison and correlation with known good and known bad examples.

Automatedforensicviewstatecheck.sql

create table VIEWSTATESPROBASE(OWNERIN VARCHAR2(30),USER$NAME VARCHAR2(30),OBJ$OWNER VARCHAR2(30),
NAMEIN VARCHAR2(30),
SOURCE$OBJID NUMBER,
OBJ$TYPE VARCHAR2(30),
COUNTOUT NUMBER,
CTIMEOUT TIMESTAMP,
STIMEOUT TIMESTAMP,
LASTDDLOUT TIMESTAMP,
HASH NUMBER);

CREATE OR REPLACE PROCEDURE VIEWSTATEPROBASE(OWNERIN VARCHAR2) AS TYPE C_TYPE IS REF CURSOR;
CV6 C_TYPE;
USER$NAME VARCHAR2(30); --
OBJ$OWNER VARCHAR2(30);
NAMEIN VARCHAR2(30);
SOURCE$OBJID NUMBER;
OBJ$TYPE VARCHAR2(30);
COUNTOUT NUMBER;
CTIMEOUT TIMESTAMP;
STIMEOUT TIMESTAMP;
LASTDDLOUT TIMESTAMP;
long_var LONG;
HASH NUMBER;
BEGIN
 OPEN CV6 FOR 'SELECT  sys.user$.NAME , sys.obj$.owner#, sys.obj$.NAME, sys.view$.obj#, sys.OBJ$.TYPE#, sys.view$.textlength,
ctime, stime, mtime from (sys.view$  join sys.obj$
ON sys.view$.obj#=sys.obj$.obj#)
inner join sys.user$ ON sys.obj$.owner# = sys.user$.user#
where sys.obj$.TYPE#=4  and sys.view$.textlength < 4000
And  sys.user$.NAME = :x GROUP BY  sys.user$.NAME, sys.obj$.owner#, sys.obj$.NAME, sys.view$.obj#, sys.OBJ$.TYPE#,
sys.view$.textlength, ctime, stime, mtime' using OWNERIN;
 LOOP
  FETCH CV6 INTO USER$NAME, OBJ$OWNER, NAMEIN, SOURCE$OBJID, OBJ$TYPE, COUNTOUT, CTIMEOUT, STIMEOUT,
LASTDDLOUT;
  DBMS_OUTPUT.ENABLE(200000);
  SELECT SYS.VIEW$.TEXT INTO long_var FROM SYS.VIEW$ WHERE sys.view$.obj#=SOURCE$OBJID;
  SELECT SUM(dbms_utility.get_hash_value(long_var,1000000000,power(2,30))) INTO HASH from sys.view$ where

sys.view$.obj#=SOURCE$OBJID;  DBMS_OUTPUT.PUT_LINE(OWNERIN||','||USER$NAME||','||OBJ$OWNER||','||NAMEIN||','||
SOURCE$OBJID||','||OBJ$TYPE||','||COUNTOUT||','||CTIMEOUT||','||STIMEOUT||','||
LASTDDLOUT||','||HASH);
insert into VIEWSTATESPROBASE values(OWNERIN,USER$NAME,OBJ$OWNER,NAMEIN,SOURCE$OBJID,OBJ$TYPE,COUNTOUT,
CTIMEOUT, STIMEOUT,LASTDDLOUT,HASH);
COMMIT;
long_var:=0;
HASH := 0;
  EXIT WHEN CV6%NOTFOUND;
 END LOOP;
 CLOSE CV6;
END;
/
show errors
--EXEC VIEWSTATEPROBASE('SYS');
--SELECT * FROM VIEWSTATESPROBASE;
--TRUNCATE TABLE VIEWSTATESPROBASE;

Once again the dblink syntax can be used on the table references in order to run this query from the Depository against the target DB remotely as in section 11.8. Please note the above code works on VIEWS with source code less than LONG 4000 which is the majority.

Other types of malware apart from modified VIEWS could include backdoored Oracle patches or a Windows Oracle client that has been changed to sniff the database traffic. Free database development tools could also be backdoored. Therefore it is worth integrity checking patches and software and using free software that comes with the source code which has been subject to source code review. Known good hashes for all Oracle software should be made and kept in the Depository. Examples of known bad checksums could be the Voyager worm PoC and the procedure at OxDEADBEEF used to run SQL as another user mentioned previously.


This is an excerpt from the book "Oracle Forensics: Oracle Security Best Practices", by Paul M. Wright, the father of Oracle Forensics.

 


 

 
  
 

 
 
 
 
Oracle performance tuning software
 
 

 

 
 
 
Oracle performance Tuning 10g reference poster
 
 
 
Oracle training in Linux commands
 
Oracle training Excel
 
Oracle training & performance tuning books
 

 

Burleson is the American Team

Note: This Oracle documentation was created as a support and Oracle training reference for use by our DBA performance tuning consulting professionals.  Feel free to ask questions on our Oracle forum.

Verify experience! Anyone considering using the services of an Oracle support expert should independently investigate their credentials and experience, and not rely on advertisements and self-proclaimed expertise. All legitimate Oracle experts publish their Oracle qualifications.

Errata?  Oracle technology is changing and we strive to update our BC Oracle support information.  If you find an error or have a suggestion for improving our content, we would appreciate your feedback.  Just  e-mail:  and include the URL for the page.


                    









Burleson Consulting

The Oracle of Database Support

Oracle Performance Tuning

Remote DBA Services


 

Copyright © 1996 -  2011 by Burleson Enterprises

All rights reserved.

Oracle © is the registered trademark of Oracle Corporation.