Pete Finnigan has a set of scripts not only to hack and find exploits but also to find things like users with privileges they should not have.
* [[http://www.petefinnigan.com/tools.htm|PeteFinnigan.com Tools]]
==== script to show schema / user profile and the profile setup ====
set lines 200 pages 1000
col username for a23 head "Username"
col dba for a5 head "DBA|privs"
col status for a8 head "Status"
col lock_date for a21 head "Lock|date"
col expiry_date for a21 head "Expiry|date"
col default_tablespace for a20 head "Default|tablespace"
col profile for a18 head "Profile"
col pwd_verify for a20 head "Pwd|function"
col plt for a4 head "Pwd|life"
col fla for a8 head "Failed|logins"
col rum for a5 head "Pwd|reuse"
col pgt for a5 head "Pwd|grace"
col pwd_lok for a7 head "Lock|days"
with profile_detail as
(
select dbp.profile
, dbp.resource_name
, decode(dbp.limit,'DEFAULT',def.limit,'NULL','','UNLIMITED','',dbp.limit) limit
from dba_profiles dbp
, (select def.resource_name
, decode(def.limit,'NULL','','UNLIMITED','',def.limit) limit
from dba_profiles def
where profile = 'DEFAULT'
) def
where 1=1
and dbp.resource_name = def.resource_name
order by 2,1
)
select dbu.username
, decode(dba.grantee,null,'NO','YES') dba
, replace( replace( replace( replace(dbu.account_status,'LOCKED','LOCK'), 'EXPIRED','EXP'), '(GRACE)','(GR)'), ' & ','&') status
, dbu.lock_date
, dbu.expiry_date
, dbu.default_tablespace
, dbu.profile
, pwd.limit pwd_verify
, plt.limit plt
, fla.limit fla
, rum.limit rum
, pgt.limit pgt
, plk.limit pwd_lok
from dba_users dbu
, (select grantee
from dba_role_privs
where granted_role = 'DBA'
) dba
, profile_detail pwd
, profile_detail plt
, profile_detail fla
, profile_detail rum
, profile_detail pgt
, profile_detail plk
where 1=1
and pwd.profile = dbu.profile
and pwd.resource_name = 'PASSWORD_VERIFY_FUNCTION'
and plt.profile = dbu.profile
and plt.resource_name = 'PASSWORD_LIFE_TIME'
and fla.profile = dbu.profile
and fla.resource_name = 'FAILED_LOGIN_ATTEMPTS'
and rum.profile = dbu.profile
and rum.resource_name = 'PASSWORD_REUSE_MAX'
and pgt.profile = dbu.profile
and pgt.resource_name = 'PASSWORD_GRACE_TIME'
and plk.profile = dbu.profile
and plk.resource_name = 'PASSWORD_LOCK_TIME'
and dbu.username = dba.grantee(+)
order by expiry_date
/
==== Password verification function for user profile ====
FUNCTION verify_function_11g
(username varchar2,
password varchar2,
old_password varchar2)
RETURN boolean IS
n boolean;
m integer;
differ integer;
isdigit boolean;
ischar boolean;
ispunct boolean;
db_name varchar2(40);
digitarray varchar2(20);
punctarray varchar2(25);
chararray varchar2(52);
i_char varchar2(10);
simple_password varchar2(10);
reverse_user varchar2(32);
BEGIN
digitarray:= '0123456789';
chararray:= 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
punctarray:='!"#$%&()``*+,-/:;<=>?_';
-- Check for the minimum length of the password
IF length(password) < 8 THEN
raise_application_error(-20001, 'Password length less than 8');
END IF;
-- Check if the password is same as the username or username(1-100)
IF NLS_LOWER(password) = NLS_LOWER(username) THEN
raise_application_error(-20002, 'Password same as or similar to user');
END IF;
FOR i IN 1..100 LOOP
i_char := to_char(i);
if NLS_LOWER(username)|| i_char = NLS_LOWER(password) THEN
raise_application_error(-20005, 'Password same as or similar to user name ');
END IF;
END LOOP;
-- Check if the password is same as the username reversed
FOR i in REVERSE 1..length(username) LOOP
reverse_user := reverse_user || substr(username, i, 1);
END LOOP;
IF NLS_LOWER(password) = NLS_LOWER(reverse_user) THEN
raise_application_error(-20003, 'Password same as username reversed');
END IF;
-- Check if the password is the same as server name and or servername(1-100)
select name into db_name from sys.v$database;
if NLS_LOWER(db_name) = NLS_LOWER(password) THEN
raise_application_error(-20004, 'Password same as or similar to server name');
END IF;
FOR i IN 1..100 LOOP
i_char := to_char(i);
if NLS_LOWER(db_name)|| i_char = NLS_LOWER(password) THEN
raise_application_error(-20005, 'Password same as or similar to server name ');
END IF;
END LOOP;
-- Check if the password is too simple. A dictionary of words may be
-- maintained and a check may be made so as not to allow the words
-- that are too simple for the password.
IF NLS_LOWER(password) IN ('welcome1', 'database1', 'account1', 'user1234',
'password1', 'oracle123', 'computer1', 'abcdefg1', 'change_on_install') THEN
raise_application_error(-20006, 'Password too simple');
END IF;
-- Check if the password is the same as oracle (1-100)
simple_password := 'oracle';
FOR i IN 1..100 LOOP
i_char := to_char(i);
if simple_password || i_char = NLS_LOWER(password) THEN
raise_application_error(-20007, 'Password too simple ');
END IF;
END LOOP;
-- Check if the password contains at least one letter, one digit
-- 1. Check for the digit
isdigit:=FALSE;
m := length(password);
FOR i IN 1..10 LOOP
FOR j IN 1..m LOOP
IF substr(password,j,1) = substr(digitarray,i,1) THEN
isdigit:=TRUE;
GOTO findchar;
END IF;
END LOOP;
END LOOP;
IF isdigit = FALSE THEN
raise_application_error(-20008, 'Password must contain at least one digit');
END IF;
-- 2. Check for the character
<>
ischar:=FALSE;
FOR i IN 1..length(chararray) LOOP
FOR j IN 1..m LOOP
IF substr(password,j,1) = substr(chararray,i,1) THEN
ischar:=TRUE;
GOTO findpunct;
END IF;
END LOOP;
END LOOP;
IF ischar = FALSE THEN
raise_application_error(-20009, 'Password must contain at least one alphabetic character');
END IF;
-- 3. Check for the punctuation
<>
ispunct:=FALSE;
FOR i IN 1..length(punctarray) LOOP
FOR j IN 1..m LOOP
IF substr(password,j,1) = substr(punctarray,i,1) THEN
ispunct:=TRUE;
GOTO endsearch;
END IF;
END LOOP;
END LOOP;
IF ispunct = FALSE THEN
raise_application_error(-20010, 'Password should contain at least one punctuation');
END IF;
<>
-- Check if the password differs from the previous password by at least
-- 3 letters
IF old_password IS NOT NULL THEN
differ := length(old_password) - length(password);
differ := abs(differ);
IF differ < 3 THEN
IF length(password) < length(old_password) THEN
m := length(password);
ELSE
m := length(old_password);
END IF;
FOR i IN 1..m LOOP
IF substr(password,i,1) != substr(old_password,i,1) THEN
differ := differ + 1;
END IF;
END LOOP;
IF differ < 1 THEN
raise_application_error(-20011, 'Password should differ from the \\
old password by at least 1 characters');
END IF;
END IF;
END IF;
-- Everything is fine; return TRUE ;
RETURN(TRUE);
END;