Call: +44 (0)7759 277220 Call
Blog

Pete Finnigan's Oracle Security Weblog

This is the weblog for Pete Finnigan. Pete works in the area of Oracle security and he specialises in auditing Oracle databases for security issues. This weblog is aimed squarely at those interested in the security of their Oracle databases.

Oracles Free TNS Firewall - VALIDNODE_CHECKING

I said in a post a couple of days ago that my overall plan to secure an Oracle database; actually my plan is to secure the data in an Oracle database not blindly just secure Oracle. We must focus on securing data first and last and everywhere in-between.

As I said a few days ago the first step is to stop people connecting to the database who should not be allowed to connect. We must limit the actual people who are allowed to directly connect to the database to just and only just those users who need to. no more. Once these users / people are identified then we can further limit how they can connect (i.e. what tools are allowed) and then further strengthen them with strong passwords and least rights; i.e. only have exactly the right privileges to do their job and no more. This is easy to say but in practice hard to do for many many reasons.

Finally after we control the users and their rights we can then think about data security controls including permissions on tables/views etc and even context based security such as VPD, OLS, DV Realms or hand coded solutions with views and triggers all based on factors such as user id, time, where, when, what etc.

Valid node checking is Oracles free simple TNS firewall that exists in the listener. I have been advising clients and others at talks and presentations and training to use this technology for years. Its free and simple but a little brute force - I.e. it works at the IP level and port (because it works on TNS its tied to the current listener port). It would be better if there was a little more flexibility maybe down to the tool level/ user/ ?? . We can do that level with a login trigger though so all is not lost.

OK, lets test valid node checking. First go to the Linux box and go to the $ORACLE_HOME/network/admin and open the sqlnet.ora file and turn on valid node checking by setting TCP.VALIDNODE_CHECKING=yes and then create an invited nodes list - a white list of IP addresses or Hostnames. This can be done with the TCP.INVITED_NODES parameter. See my box as follows to see that I have added the IP Address of the database server only at this point:

[oracle@oel1124 admin]$ cat sqlnet.ora
# sqlnet.ora Network Configuration File: /u01/app/oracle/product/11.2.0/db_1/network/admin/sqlnet.ora
# Generated by Oracle configuration tools.

NAMES.DIRECTORY_PATH= (TNSNAMES, EZCONNECT)

ADR_BASE = /u01/app/oracle

TCP.VALIDNODE_CHECKING=yes
TCP.INVITED_NODES=(192.168.56.85)
[oracle@oel1124 admin]$

Now try and connect remotely from a client PC using SQL*Plus:

C:\_aa\PB\bin>sqlplus /nolog

SQL*Plus: Release 11.2.0.4.0 Production on Tue Mar 31 09:38:01 2020

Copyright (c) 1982, 2013, Oracle. All rights reserved.

SQL> connect system/oracle1@//192.168.56.85:1521/bfora.localdomain
Connected.
SQL>

This clearly doesn't work. Let us find out my IP Address first:

C:\_aa\PB\bin>ipconfig

Windows IP Configuration


Ethernet adapter Ethernet 3:

Connection-specific DNS Suffix . :
Link-local IPv6 Address . . . . . : fe80::a11c:3e6e:4d67:b94a%8
IPv4 Address. . . . . . . . . . . : 192.168.56.1
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . :

Ethernet adapter Ethernet 4:

Connection-specific DNS Suffix . :
Link-local IPv6 Address . . . . . : fe80::45f6:ee3f:46b4:bd8f%14
Autoconfiguration IPv4 Address. . : 169.254.189.143
Subnet Mask . . . . . . . . . . . : 255.255.0.0
Default Gateway . . . . . . . . . :

Wireless LAN adapter Local Area Connection* 1:

Media State . . . . . . . . . . . : Media disconnected
Connection-specific DNS Suffix . :

Wireless LAN adapter Local Area Connection* 2:

Media State . . . . . . . . . . . : Media disconnected
Connection-specific DNS Suffix . :

Wireless LAN adapter Wi-Fi:

Connection-specific DNS Suffix . :
Link-local IPv6 Address . . . . . : fe80::8554:bf8f:3b91:e321%13
IPv4 Address. . . . . . . . . . . : 192.168.1.96
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . : 192.168.1.1

C:\_aa\PB\bin>

We have 192.168.56.1 - this is the gateway for Virtual box. so we should not be able to connect as that IP Address is not in the valid node checking invited nodes list. Restart the listener and re-register it:

LSNRCTL> stop
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC1521)))
The command completed successfully
LSNRCTL> start
Starting /u01/app/oracle/product/11.2.0/db_1/bin/tnslsnr: please wait...

TNSLSNR for Linux: Version 11.2.0.4.0 - Production
System parameter file is /u01/app/oracle/product/11.2.0/db_1/network/admin/listener.ora
Log messages written to /u01/app/oracle/diag/tnslsnr/oel1124/listener/alert/log.xml
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=oel1124.localdomain)(PORT=1521)))

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC1521)))
STATUS of the LISTENER
------------------------
Alias LISTENER
Version TNSLSNR for Linux: Version 11.2.0.4.0 - Production
Start Date 31-MAR-2020 09:37:13
Uptime 0 days 0 hr. 0 min. 0 sec
Trace Level off
Security ON: Local OS Authentication
SNMP OFF
Listener Parameter File /u01/app/oracle/product/11.2.0/db_1/network/admin/listener.ora
Listener Log File /u01/app/oracle/diag/tnslsnr/oel1124/listener/alert/log.xml
Listening Endpoints Summary...
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=oel1124.localdomain)(PORT=1521)))
The listener supports no services
The command completed successfully
LSNRCTL> exit
[oracle@oel1124 admin]$ sqlplus / as sysdba

SQL*Plus: Release 11.2.0.4.0 Production on Tue Mar 31 09:37:18 2020

Copyright (c) 1982, 2013, Oracle. All rights reserved.


Connected to:
Oracle Database 11g Release 11.2.0.4.0 - 64bit Production

SQL> alter system register;

System altered.

SQL> exit
Disconnected from Oracle Database 11g Release 11.2.0.4.0 - 64bit Production
[oracle@oel1124 admin]$ lsnrctl

LSNRCTL for Linux: Version 11.2.0.4.0 - Production on 31-MAR-2020 09:37:28

Copyright (c) 1991, 2013, Oracle. All rights reserved.

Welcome to LSNRCTL, type "help" for information.

LSNRCTL> status
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC1521)))
STATUS of the LISTENER
------------------------
Alias LISTENER
Version TNSLSNR for Linux: Version 11.2.0.4.0 - Production
Start Date 31-MAR-2020 09:37:13
Uptime 0 days 0 hr. 0 min. 16 sec
Trace Level off
Security ON: Local OS Authentication
SNMP OFF
Listener Parameter File /u01/app/oracle/product/11.2.0/db_1/network/admin/listener.ora
Listener Log File /u01/app/oracle/diag/tnslsnr/oel1124/listener/alert/log.xml
Listening Endpoints Summary...
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=oel1124.localdomain)(PORT=1521)))
Services Summary...
Service "bfora.localdomain" has 1 instance(s).
Instance "bfora", status READY, has 1 handler(s) for this service...
Service "bforaXDB.localdomain" has 1 instance(s).
Instance "bfora", status READY, has 1 handler(s) for this service...
The command completed successfully
LSNRCTL>

Now try and connect remotely again from 192.168.56.1 and see what happens:

C:\_aa\PB\bin>sqlplus /nolog

SQL*Plus: Release 11.2.0.4.0 Production on Tue Mar 31 09:41:13 2020

Copyright (c) 1982, 2013, Oracle. All rights reserved.

SQL> connect system/oracle1@//192.168.56.85:1521/bfora.localdomain
ERROR:
ORA-12547: TNS:lost contact


SQL>

Now the connection is prevented so we have proved that it works. Go in now and change the sqlnet.ora again to include my IP Address so that I can connect to the database from my SQL*Plus client but no one else can:

[oracle@oel1124 admin]$ vi sqlnet.ora
[oracle@oel1124 admin]$ cat sqlnet.ora
# sqlnet.ora Network Configuration File: /u01/app/oracle/product/11.2.0/db_1/network/admin/sqlnet.ora
# Generated by Oracle configuration tools.

NAMES.DIRECTORY_PATH= (TNSNAMES, EZCONNECT)

ADR_BASE = /u01/app/oracle

TCP.VALIDNODE_CHECKING=yes
TCP.INVITED_NODES=(192.168.56.85,192.168.56.1)
[oracle@oel1124 admin]$

Now restart the listener again:

[oracle@oel1124 admin]$ lsnrctl

LSNRCTL for Linux: Version 11.2.0.4.0 - Production on 31-MAR-2020 09:39:39

Copyright (c) 1991, 2013, Oracle. All rights reserved.

Welcome to LSNRCTL, type "help" for information.

LSNRCTL> stop
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC1521)))
The command completed successfully
LSNRCTL> start
Starting /u01/app/oracle/product/11.2.0/db_1/bin/tnslsnr: please wait...

TNSLSNR for Linux: Version 11.2.0.4.0 - Production
System parameter file is /u01/app/oracle/product/11.2.0/db_1/network/admin/listener.ora
Log messages written to /u01/app/oracle/diag/tnslsnr/oel1124/listener/alert/log.xml
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=oel1124.localdomain)(PORT=1521)))

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC1521)))
STATUS of the LISTENER
------------------------
Alias LISTENER
Version TNSLSNR for Linux: Version 11.2.0.4.0 - Production
Start Date 31-MAR-2020 09:39:46
Uptime 0 days 0 hr. 0 min. 0 sec
Trace Level off
Security ON: Local OS Authentication
SNMP OFF
Listener Parameter File /u01/app/oracle/product/11.2.0/db_1/network/admin/listener.ora
Listener Log File /u01/app/oracle/diag/tnslsnr/oel1124/listener/alert/log.xml
Listening Endpoints Summary...
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=oel1124.localdomain)(PORT=1521)))
The listener supports no services
The command completed successfully
LSNRCTL> exit
[oracle@oel1124 admin]$ sqlplus / as sysdba

SQL*Plus: Release 11.2.0.4.0 Production on Tue Mar 31 09:39:54 2020

Copyright (c) 1982, 2013, Oracle. All rights reserved.


Connected to:
Oracle Database 11g Release 11.2.0.4.0 - 64bit Production

SQL> alter system register;

System altered.

SQL> exit
Disconnected from Oracle Database 11g Release 11.2.0.4.0 - 64bit Production
[oracle@oel1124 admin]$ lsnrctl status

LSNRCTL for Linux: Version 11.2.0.4.0 - Production on 31-MAR-2020 09:40:04

Copyright (c) 1991, 2013, Oracle. All rights reserved.

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC1521)))
STATUS of the LISTENER
------------------------
Alias LISTENER
Version TNSLSNR for Linux: Version 11.2.0.4.0 - Production
Start Date 31-MAR-2020 09:39:46
Uptime 0 days 0 hr. 0 min. 18 sec
Trace Level off
Security ON: Local OS Authentication
SNMP OFF
Listener Parameter File /u01/app/oracle/product/11.2.0/db_1/network/admin/listener.ora
Listener Log File /u01/app/oracle/diag/tnslsnr/oel1124/listener/alert/log.xml
Listening Endpoints Summary...
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=oel1124.localdomain)(PORT=1521)))
Services Summary...
Service "bfora.localdomain" has 1 instance(s).
Instance "bfora", status READY, has 1 handler(s) for this service...
Service "bforaXDB.localdomain" has 1 instance(s).
Instance "bfora", status READY, has 1 handler(s) for this service...
The command completed successfully
[oracle@oel1124 admin]$

Now try the remote connection using SQL*plus from my client PC:

SQL> connect system/oracle1@//192.168.56.85:1521/bfora.localdomain
Connected.
SQL>

Of course it works now. There are two points here. Yesterday in the post "Add A SQL*Net Security Banner And Audit Notice" I showed that for the banner parameters SEC_USER_AUDIT_ACTION_BANNER and SEC_USER_UNAUTHORIZED_ACCESS_BANNER in the sqlnet.ora we had to re-start the database for them to take effect. But, for valid node checking we only need to restart the listener. Inconsistency is not good. The second point is that this is virtual box and my true IP Address is in the 192.168.1.* range but I access the database on virtualbox networking via the gateway 192.168.56.1. This is not ideal if clients are going to access a database on a box in a virtual box network as the gateway needed to be added. Ensure that when you use valid node checking that you do not need to allow all access via a gateway as this will defeat the object of it.

OK, hope this helps, bye from WFH

Add A SQL*Net Security Banner And Audit Notice

I would have to say whilst I see security banners on customers Unix boxes when I am allowed to log in as part of a security audit I canot ever remember seeing a security banner when I log into a customer database using SQL*Plus or our database security scanner PFCLScan or indeed any other tool. It is possible to add one and to therefore make sure that anyone who accesses your systems using SQL*Net is told that they can only access if they have permission and also to be told that they are being audited.

Oracle supports adding an Unauthorized access banner and an audit action banner. Lets see how this works. First connect to my 11.2.0.4 database as normal and check if we have a banner and show the version:

C:\_aa\PB\bin>sqlplus system/oracle1@//192.168.56.85:1521/bfora.localdomain

SQL*Plus: Release 11.2.0.4.0 Production on Mon Mar 30 12:36:21 2020

Copyright (c) 1982, 2013, Oracle. All rights reserved.


Connected to:
Oracle Database 11g Release 11.2.0.4.0 - 64bit Production

SQL> select * from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Release 11.2.0.4.0 - 64bit Production
PL/SQL Release 11.2.0.4.0 - Production
CORE 11.2.0.4.0 Production
TNS for Linux: Version 11.2.0.4.0 - Production
NLSRTL Version 11.2.0.4.0 - Production

SQL>

OK, no banners, I didn't set them up yet. First lets connect to the Unix/Linux box and create the banner text files:

[root@oel1124 ~]# su - oracle
[oracle@oel1124 ~]$ cd $ORACLE_HOME/network/admin
[oracle@oel1124 admin]$ pwd
/u01/app/oracle/product/11.2.0/db_1/network/admin
[oracle@oel1124 admin]$ vi unauth.txt
[oracle@oel1124 admin]$ vi audit.txt
[oracle@oel1124 admin]$ cat unauth.txt
No unauthorised access is allowed to this system. You must have permission and a valid account and password provided by facilities and authorised by the Managing Director.

This system is Copyright PeteFinnigan.com Limited (c) 2020. All rights reserved.
[oracle@oel1124 admin]$ cat audit.txt
This system is protected by PeteFinnigan.com Limited.

All actions in this system by YOU are audited and those audit trails may be used to enforce security restrictions.
[oracle@oel1124 admin]$

Now lets update the sqlnet.ora file to reference the text files for the banners. I created my two text files in the $ORACLE_HOME/network/admin directory in the same location as my sqlnet.ora file BUT you can put the files anywhere that the Oracle software owner has access to read the files. So next let's update the sqlnet.ora:

[oracle@oel1124 admin]$ cat sqlnet.ora
# sqlnet.ora Network Configuration File: /u01/app/oracle/product/11.2.0/db_1/network/admin/sqlnet.ora
# Generated by Oracle configuration tools.

NAMES.DIRECTORY_PATH= (TNSNAMES, EZCONNECT)

ADR_BASE = /u01/app/oracle

SEC_USER_AUDIT_ACTION_BANNER=/u01/app/oracle/product/11.2.0/db_1/network/admin/audit.txt
SEC_USER_UNAUTHORIZED_ACCESS_BANNER=/u01/app/oracle/product/11.2.0/db_1/network/admin/unauth.txt
[oracle@oel1124 admin]$

The banner text for each parameter can be at most 512 bytes. So the banner message needs to be fairly succinct but as there are two of them we can have 1024 bytes of message and that should be enough for most people.

So, how to make it work? We can restart the listener:

[oracle@oel1124 admin]$ lsnrctl stop

LSNRCTL for Linux: Version 11.2.0.4.0 - Production on 30-MAR-2020 13:04:23

Copyright (c) 1991, 2013, Oracle. All rights reserved.

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC1521)))
The command completed successfully
[oracle@oel1124 admin]$ lsnrctl start

LSNRCTL for Linux: Version 11.2.0.4.0 - Production on 30-MAR-2020 13:04:29

Copyright (c) 1991, 2013, Oracle. All rights reserved.

Starting /u01/app/oracle/product/11.2.0/db_1/bin/tnslsnr: please wait...

TNSLSNR for Linux: Version 11.2.0.4.0 - Production
System parameter file is /u01/app/oracle/product/11.2.0/db_1/network/admin/listener.ora
Log messages written to /u01/app/oracle/diag/tnslsnr/oel1124/listener/alert/log.xml
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=oel1124.localdomain)(PORT=1521)))

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC1521)))
STATUS of the LISTENER
------------------------
Alias LISTENER
Version TNSLSNR for Linux: Version 11.2.0.4.0 - Production
Start Date 30-MAR-2020 13:04:29
Uptime 0 days 0 hr. 0 min. 0 sec
Trace Level off
Security ON: Local OS Authentication
SNMP OFF
Listener Parameter File /u01/app/oracle/product/11.2.0/db_1/network/admin/listener.ora
Listener Log File /u01/app/oracle/diag/tnslsnr/oel1124/listener/alert/log.xml
Listening Endpoints Summary...
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=oel1124.localdomain)(PORT=1521)))
The listener supports no services
The command completed successfully
[oracle@oel1124 admin]$
[oracle@oel1124 admin]$ lsnrctl status

LSNRCTL for Linux: Version 11.2.0.4.0 - Production on 30-MAR-2020 13:05:04

Copyright (c) 1991, 2013, Oracle. All rights reserved.

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC1521)))
STATUS of the LISTENER
------------------------
Alias LISTENER
Version TNSLSNR for Linux: Version 11.2.0.4.0 - Production
Start Date 30-MAR-2020 13:04:29
Uptime 0 days 0 hr. 0 min. 35 sec
Trace Level off
Security ON: Local OS Authentication
SNMP OFF
Listener Parameter File /u01/app/oracle/product/11.2.0/db_1/network/admin/listener.ora
Listener Log File /u01/app/oracle/diag/tnslsnr/oel1124/listener/alert/log.xml
Listening Endpoints Summary...
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=oel1124.localdomain)(PORT=1521)))
Services Summary...
Service "bfora.localdomain" has 1 instance(s).
Instance "bfora", status READY, has 1 handler(s) for this service...
Service "bforaXDB.localdomain" has 1 instance(s).
Instance "bfora", status READY, has 1 handler(s) for this service...
The command completed successfully
[oracle@oel1124 admin]$

So, when we connect to the database with SQL*Plus do we get the banners:

C:\_aa\PB\bin>sqlplus system/oracle1@//192.168.56.85:1521/bfora.localdomain

SQL*Plus: Release 11.2.0.4.0 Production on Mon Mar 30 13:09:19 2020

Copyright (c) 1982, 2013, Oracle. All rights reserved.


Connected to:
Oracle Database 11g Release 11.2.0.4.0 - 64bit Production

SQL>

The short answer is no. We must restart the database for these parameters to take affect. This is odd in my opinion as these are network settings so it would have made more sense for these to take effect when the listener is restarted but never mind. Lets restart the database:

[oracle@oel1124 admin]$ sqlplus / as sysdba

SQL*Plus: Release 11.2.0.4.0 Production on Mon Mar 30 13:12:47 2020

Copyright (c) 1982, 2013, Oracle. All rights reserved.


Connected to:
Oracle Database 11g Release 11.2.0.4.0 - 64bit Production

SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup
No unauthorised access is allowed to this system. You must have permission and a valid account and password provided by facilities and authorised by the Managing Director.

This system is Copyright PeteFinnigan.com Limited (c) 2020. All rights reserved.

This system is protected by PeteFinnigan.com Limited.

All actions in this system by YOU are audited and those audit trails may be used to enforce security restrictions.

ORACLE instance started.

Total System Global Area 1653518336 bytes
Fixed Size 2253784 bytes
Variable Size 1006636072 bytes
Database Buffers 637534208 bytes
Redo Buffers 7094272 bytes
Database mounted.
No unauthorised access is allowed to this system. You must have permission and a valid account and password provided by facilities and authorised by the Managing Director.

This system is Copyright PeteFinnigan.com Limited (c) 2020. All rights reserved.

This system is protected by PeteFinnigan.com Limited.

All actions in this system by YOU are audited and those audit trails may be used to enforce security restrictions.

Database opened.
SQL>

This is interesting. Both banner texts are displayed in the order, Unauthorised banner and then audit banner text. The texts are displayed twice on startup. I was connected already AS SYSDBA and shutdown the database. I didn't reconnect but the banners displayed before the instance was started and then again after the instance started. Not sure why twice and also why display when no connection was made. Now lets connect with SQL*Plus from a client and see what happens:

C:\_aa\PB\bin>sqlplus system/oracle1@//192.168.56.85:1521/bfora.localdomain

SQL*Plus: Release 11.2.0.4.0 Production on Mon Mar 30 13:19:38 2020

Copyright (c) 1982, 2013, Oracle. All rights reserved.

No unauthorised access is allowed to this system. You must have permission and a valid account and password provided by facilities and authorised by the Managing Director.

This system is Copyright PeteFinnigan.com Limited (c) 2020. All rights reserved.

This system is protected by PeteFinnigan.com Limited.

All actions in this system by YOU are audited and those audit trails may be used to enforce security restrictions.


Connected to:
Oracle Database 11g Release 11.2.0.4.0 - 64bit Production

SQL>

Now we get both banners. What happens if I use SQL*Plus in silent mode:

C:\_aa\PB\bin>sqlplus -S system/oracle1@//192.168.56.85:1521/bfora.localdomain


^C
C:\_aa\PB\bin>

Nothing; it hangs and never times out. the -S works when there is no banner files but not when there is? is this is a bug? If we use SQL*Plus with -V then it does work and only shows the version:

C:\_aa\PB\bin>sqlplus -V system/oracle1@//192.168.56.85:1521/bfora.localdomain

SQL*Plus: Release 11.2.0.4.0 Production


C:\_aa\PB\bin>

If we do a connect from within SQL*Plus rather than a connect on the command line:

SQL> connect system/oracle1@//192.168.56.85:1521/bfora.localdomain
No unauthorised access is allowed to this system. You must have permission and a valid account and password provided by facilities and authorised by the Managing Director.

This system is Copyright PeteFinnigan.com Limited (c) 2020. All rights reserved.

This system is protected by PeteFinnigan.com Limited.

All actions in this system by YOU are audited and those audit trails may be used to enforce security restrictions.

Connected.
SQL>

This works the same as a connection on the command line.

What about other tools. We can create a project in PFCLScan our database vulnerability scanner that uses OCI to connect to the database and we can check the engine logs to see if the banner works:

...
[2020 Mar 30 12:28:42] Oscan: [-] Test database connection
[2020 Mar 30 12:28:42] Oscan: Attached to [//192.168.56.85:1521/bfora.localdomain]
[2020 Mar 30 12:28:42] Oscan: Connected to [//192.168.56.85:1521/bfora.localdomain] as [system ]
...

The above is a section from the plugin log where the database connection is tested. What about actually connecting during the scan:


[2020 Mar 30 12:30:49] Oscan: Connect to the database....
[2020 Mar 30 12:30:49] Oscan: Server Attached to [//192.168.56.85:1521/bfora.localdomain]
[2020 Mar 30 12:30:49] Oscan: Connected to [//192.168.56.85:1521/bfora.localdomain] as [system]
...

No, again it doesn't show any banner in the OCI connection. So we would need to make a modification to our OCI code to display the banners. We would need to use OCI_AttrGet(…) and use the OCI_ATTR_ACCESS_BANNER and OCI_ATTR_AUDIT_BANNER attributes to get the banners if they exist and display them in our OCI code.

So in summary we can set banners for unauthorised access and also audit trail notification but there is no mechanism to answer a question to accept the banner and then log in and it is too easy to ignore then banner in SQL*Plus with a -V or cause a hang with -S. Also unless your write code into your tools then OCI does not display these banners by default.

OK, by for now from WHF!!


ORA-28050 - Can I drop the SYSTEM User?

Two things most annoy me with the Oracle database in terms of securing it and this is the abundance of default users in most Oracle databases that I perform security audits on and also the massive amount of PUBLIC grants that are there by default for all users.

The primary goal in securing Oracle is to stop people connecting to the database. If you can do that and only allow in the exact number of users necessary to do their job to connect. This can be achieved by network controls, Oracle network controls such as validnode checking and even database controls such as login triggers or Database Vault CONNECT command rules... If you then ensure that each account has only the exact rights necessary to do their job and no more then you are on your way to good data security and lock down. You can then lock down the access controls to the data itself and even use context based security such as VPD or OLS, DV, redaction, masking, TSDP and more. This is least privileges.

Then you have some level of initial control. An attack then must take place on one of a small number of general ways:

  1. The user accounts that are allowed to connect can exploit some other feature of the database or data controls. This means that if you have a valid account and can connect to the database you then need to find a gap in the database settings, data access controls or exploit the fact you didn't really have least rights

  2. The attacker could exploit a remote vulnerability in the database access protocols (TNS, OLOGON etc) and find a way to access the database without a username or with a username and no password. This could be as simple as guessing a default users password or as extreme as a network stack buffer overflow, or...

  3. The attacker could find an exploit in the application stack and tunnel to the database. For instance SQL Injection in application code.

  4. Others, possibly....


So, back to my first two points. We want to stop people connecting, for those that we do allow to connect we limit what they can use (programs), we have strong password controls and we then aim for least rights and finally proper data domains, data access controls and even context based security BUT we are put in a difficult position by many default accounts existing that we maybe don't need and those tens of thousands of PUBLIC grants.

If we could have a database with no default accounts and no PUBLIC grants then we would have a much stronger starting point. Unfortunately we get 44K, 45K in a stock 12.2c, 18c, 19c database.

So as part of this discussion and quest I wanted to look at the SYSTEM user. Most sites I go to the DBAs use SYSDBA to do their daily work or if not they use SYSTEM as the default DBA account. But what does SYSTEM have. First lets connect to my 11.2.0.4 database:

SQL> sho user
USER is "SYS"
SQL> select banner from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Release 11.2.0.4.0 - 64bit Production
PL/SQL Release 11.2.0.4.0 - Production
CORE 11.2.0.4.0 Production
TNS for Linux: Version 11.2.0.4.0 - Production
NLSRTL Version 11.2.0.4.0 - Production

SQL>

Now what objects does SYSTEM have:

SQL> select count(*),object_type from dba_objects where owner='SYSTEM' group by object_type;

COUNT(*) OBJECT_TYPE
---------- -------------------
64 INDEX PARTITION
20 SEQUENCE
45 TABLE PARTITION
4 QUEUE
1 PROCEDURE
25 LOB
1 PACKAGE
1 PACKAGE BODY
2 TRIGGER
167 TABLE
253 INDEX

COUNT(*) OBJECT_TYPE
---------- -------------------
8 SYNONYM
14 VIEW
4 FUNCTION
9 TYPE

15 rows selected.

SQL>

What are the main PL/SQL objects owned by SYSTEM:

SQL> col object_name for a30
SQL> col object_type for a30
SQL> l
1* select object_name,object_type from dba_objects where owner='SYSTEM' and object_type in('PROCEDURE','FUNCTION','PACKAGE','PACKAGE BODY')
SQL> /

OBJECT_NAME OBJECT_TYPE
------------------------------ ------------------------------
ORA$_SYS_REP_AUTH PROCEDURE
DBMS_REPCAT_AUTH PACKAGE
LOGMNR$TAB_GG_TABF_PUBLIC FUNCTION
LOGMNR$COL_GG_TABF_PUBLIC FUNCTION
LOGMNR$SEQ_GG_TABF_PUBLIC FUNCTION
LOGMNR$KEY_GG_TABF_PUBLIC FUNCTION
DBMS_REPCAT_AUTH PACKAGE BODY

7 rows selected.

SQL>

These are REPCAT and LogMiner objects. Interesting. What about tables:

SQL> select object_name,object_type from dba_objects where owner='SYSTEM' and object_type ='TABLE';

OBJECT_NAME OBJECT_TYPE
------------------------------ ------------------------------
LOGMNR_SESSION_EVOLVE$ TABLE
LOGMNR_GLOBAL$ TABLE
LOGMNR_GT_TAB_INCLUDE$ TABLE
LOGMNR_GT_USER_INCLUDE$ TABLE
LOGMNR_GT_XID_INCLUDE$ TABLE
LOGMNR_UID$ TABLE
LOGMNRGGC_GTLO TABLE
LOGMNRGGC_GTCS TABLE
LOGMNRC_DBNAME_UID_MAP TABLE
LOGMNR_LOG$ TABLE
LOGMNR_PROCESSED_LOG$ TABLE

OBJECT_NAME OBJECT_TYPE
------------------------------ ------------------------------
LOGMNR_SPILL$ TABLE
LOGMNR_AGE_SPILL$ TABLE
LOGMNR_RESTART_CKPT_TXINFO$ TABLE
LOGMNR_ERROR$ TABLE
LOGMNR_RESTART_CKPT$ TABLE
LOGMNR_INTEGRATED_SPILL$ TABLE
LOGMNR_FILTER$ TABLE
LOGMNR_SESSION_ACTIONS$ TABLE
LOGMNR_PARAMETER$ TABLE
LOGMNR_SESSION$ TABLE
LOGMNRT_MDDL$ TABLE

OBJECT_NAME OBJECT_TYPE
------------------------------ ------------------------------
MVIEW$_ADV_WORKLOAD TABLE
MVIEW$_ADV_BASETABLE TABLE
MVIEW$_ADV_SQLDEPEND TABLE
MVIEW$_ADV_PRETTY TABLE
MVIEW$_ADV_TEMP TABLE
MVIEW$_ADV_FILTER TABLE
MVIEW$_ADV_LOG TABLE
MVIEW$_ADV_FILTERINSTANCE TABLE
MVIEW$_ADV_LEVEL TABLE
MVIEW$_ADV_ROLLUP TABLE
MVIEW$_ADV_AJG TABLE

OBJECT_NAME OBJECT_TYPE
------------------------------ ------------------------------
MVIEW$_ADV_FJG TABLE
MVIEW$_ADV_GC TABLE
MVIEW$_ADV_CLIQUE TABLE
MVIEW$_ADV_ELIGIBLE TABLE
MVIEW$_ADV_OUTPUT TABLE
MVIEW$_ADV_EXCEPTIONS TABLE
MVIEW$_ADV_PARAMETERS TABLE
MVIEW$_ADV_INFO TABLE
MVIEW$_ADV_JOURNAL TABLE
MVIEW$_ADV_PLAN TABLE
AQ$_QUEUE_TABLES TABLE

OBJECT_NAME OBJECT_TYPE
------------------------------ ------------------------------
AQ$_QUEUES TABLE
AQ$_SCHEDULES TABLE
AQ$_INTERNET_AGENTS TABLE
AQ$_INTERNET_AGENT_PRIVS TABLE
OL$ TABLE
OL$HINTS TABLE
OL$NODES TABLE
DEF$_ERROR TABLE
DEF$_DESTINATION TABLE
DEF$_CALLDEST TABLE
DEF$_DEFAULTDEST TABLE

OBJECT_NAME OBJECT_TYPE
------------------------------ ------------------------------
DEF$_LOB TABLE
DEF$_PROPAGATOR TABLE
DEF$_ORIGIN TABLE
DEF$_PUSHED_TRANSACTIONS TABLE
REPCAT$_REPCAT TABLE
REPCAT$_FLAVORS TABLE
REPCAT$_REPSCHEMA TABLE
REPCAT$_SNAPGROUP TABLE
REPCAT$_REPOBJECT TABLE
REPCAT$_REPCOLUMN TABLE
REPCAT$_KEY_COLUMNS TABLE

OBJECT_NAME OBJECT_TYPE
------------------------------ ------------------------------
REPCAT$_GENERATED TABLE
REPCAT$_REPPROP TABLE
REPCAT$_REPCATLOG TABLE
REPCAT$_DDL TABLE
REPCAT$_REPGROUP_PRIVS TABLE
REPCAT$_PRIORITY_GROUP TABLE
REPCAT$_PRIORITY TABLE
REPCAT$_COLUMN_GROUP TABLE
REPCAT$_GROUPED_COLUMN TABLE
REPCAT$_CONFLICT TABLE
REPCAT$_RESOLUTION_METHOD TABLE

OBJECT_NAME OBJECT_TYPE
------------------------------ ------------------------------
REPCAT$_RESOLUTION TABLE
REPCAT$_RESOLUTION_STATISTICS TABLE
REPCAT$_RESOL_STATS_CONTROL TABLE
REPCAT$_PARAMETER_COLUMN TABLE
REPCAT$_AUDIT_ATTRIBUTE TABLE
REPCAT$_AUDIT_COLUMN TABLE
REPCAT$_FLAVOR_OBJECTS TABLE
REPCAT$_TEMPLATE_STATUS TABLE
REPCAT$_TEMPLATE_TYPES TABLE
REPCAT$_REFRESH_TEMPLATES TABLE
REPCAT$_USER_AUTHORIZATIONS TABLE

OBJECT_NAME OBJECT_TYPE
------------------------------ ------------------------------
REPCAT$_OBJECT_TYPES TABLE
REPCAT$_TEMPLATE_REFGROUPS TABLE
REPCAT$_TEMPLATE_OBJECTS TABLE
REPCAT$_TEMPLATE_PARMS TABLE
REPCAT$_OBJECT_PARMS TABLE
REPCAT$_USER_PARM_VALUES TABLE
REPCAT$_TEMPLATE_SITES TABLE
REPCAT$_SITE_OBJECTS TABLE
REPCAT$_RUNTIME_PARMS TABLE
REPCAT$_TEMPLATE_TARGETS TABLE
REPCAT$_EXCEPTIONS TABLE

OBJECT_NAME OBJECT_TYPE
------------------------------ ------------------------------
REPCAT$_INSTANTIATION_DDL TABLE
REPCAT$_EXTENSION TABLE
REPCAT$_SITES_NEW TABLE
LOGMNR_DICTSTATE$ TABLE
LOGMNRC_GTLO TABLE
LOGMNRC_GTCS TABLE
LOGMNRC_SEQ_GG TABLE
LOGMNRC_CON_GG TABLE
LOGMNRC_CONCOL_GG TABLE
LOGMNRC_IND_GG TABLE
LOGMNRC_INDCOL_GG TABLE

OBJECT_NAME OBJECT_TYPE
------------------------------ ------------------------------
LOGMNRC_GSII TABLE
LOGMNRC_GSBA TABLE
LOGMNR_SEED$ TABLE
LOGMNR_DICTIONARY$ TABLE
LOGMNR_OBJ$ TABLE
LOGMNR_TAB$ TABLE
LOGMNR_COL$ TABLE
LOGMNR_ATTRCOL$ TABLE
LOGMNR_TS$ TABLE
LOGMNR_IND$ TABLE
LOGMNR_USER$ TABLE

OBJECT_NAME OBJECT_TYPE
------------------------------ ------------------------------
LOGMNR_TABPART$ TABLE
LOGMNR_TABSUBPART$ TABLE
LOGMNR_TABCOMPART$ TABLE
LOGMNR_TYPE$ TABLE
LOGMNR_COLTYPE$ TABLE
LOGMNR_ATTRIBUTE$ TABLE
LOGMNR_LOB$ TABLE
LOGMNR_CON$ TABLE
LOGMNR_CDEF$ TABLE
LOGMNR_CCOL$ TABLE
LOGMNR_ICOL$ TABLE

OBJECT_NAME OBJECT_TYPE
------------------------------ ------------------------------
LOGMNR_LOBFRAG$ TABLE
LOGMNR_INDPART$ TABLE
LOGMNR_INDSUBPART$ TABLE
LOGMNR_INDCOMPART$ TABLE
LOGMNR_LOGMNR_BUILDLOG TABLE
LOGMNR_NTAB$ TABLE
LOGMNR_OPQTYPE$ TABLE
LOGMNR_SUBCOLTYPE$ TABLE
LOGMNR_KOPM$ TABLE
LOGMNR_PROPS$ TABLE
LOGMNR_ENC$ TABLE

OBJECT_NAME OBJECT_TYPE
------------------------------ ------------------------------
LOGMNR_REFCON$ TABLE
LOGMNR_PARTOBJ$ TABLE
LOGMNRP_CTAS_PART_MAP TABLE
SCHEDULER_PROGRAM_ARGS_TBL TABLE
SCHEDULER_JOB_ARGS_TBL TABLE
LOGSTDBY$PARAMETERS TABLE
LOGSTDBY$EVENTS TABLE
LOGSTDBY$APPLY_PROGRESS TABLE
LOGSTDBY$APPLY_MILESTONE TABLE
LOGSTDBY$SCN TABLE
LOGSTDBY$FLASHBACK_SCN TABLE

OBJECT_NAME OBJECT_TYPE
------------------------------ ------------------------------
LOGSTDBY$PLSQL TABLE
LOGSTDBY$SKIP_TRANSACTION TABLE
LOGSTDBY$SKIP TABLE
LOGSTDBY$SKIP_SUPPORT TABLE
LOGSTDBY$HISTORY TABLE
LOGSTDBY$EDS_TABLES TABLE
DEF$_AQCALL TABLE
DEF$_AQERROR TABLE
SQLPLUS_PRODUCT_PROFILE TABLE
HELP TABLE
MVIEW$_ADV_INDEX TABLE

OBJECT_NAME OBJECT_TYPE
------------------------------ ------------------------------
MVIEW$_ADV_PARTITION TABLE
MVIEW$_ADV_OWB TABLE

167 rows selected.

SQL>

Again a lot of LogMiner, repcat and even outlines in OL$. What roles does SYSTEM have granted directly; not roles granted to roles etc but just the direct grants:

SQL> select granted_role from dba_role_privs where grantee='SYSTEM';

GRANTED_ROLE
------------------------------
AQ_ADMINISTRATOR_ROLE
DBA
MGMT_USER

SQL>

So, finally what grants are made on the SYSTEM objects:

SQL> col privilege for a30
SQL> col grantee for a30
SQL> col table_name for a30
SQL> set lines 220
SQL> select p.privilege,p.grantee,p.table_name,o.object_type from dba_tab_privs p, dba_objects o where p.owner='SYSTEM' and o.owner=p.owner and o.object_name=p.table_name;

PRIVILEGE GRANTEE TABLE_NAME OBJECT_TYPE
------------------------------ ------------------------------ ------------------------------ --------------------
DELETE PUBLIC OL$ TABLE
INSERT PUBLIC OL$ TABLE
SELECT PUBLIC OL$ TABLE
UPDATE PUBLIC OL$ TABLE
DELETE PUBLIC OL$HINTS TABLE
INSERT PUBLIC OL$HINTS TABLE
SELECT PUBLIC OL$HINTS TABLE
UPDATE PUBLIC OL$HINTS TABLE
DELETE PUBLIC OL$NODES TABLE
INSERT PUBLIC OL$NODES TABLE
SELECT PUBLIC OL$NODES TABLE

PRIVILEGE GRANTEE TABLE_NAME OBJECT_TYPE
------------------------------ ------------------------------ ------------------------------ --------------------
UPDATE PUBLIC OL$NODES TABLE
SELECT SYS REPCAT$_REPSCHEMA TABLE
SELECT SYS REPCAT$_REPPROP TABLE
SELECT SYS DEF$_CALLDEST TABLE
SELECT SYS DEF$_ERROR TABLE
SELECT SYS DEF$_DESTINATION TABLE
SELECT SELECT_CATALOG_ROLE SCHEDULER_PROGRAM_ARGS VIEW
SELECT SELECT_CATALOG_ROLE SCHEDULER_JOB_ARGS VIEW
SELECT SELECT_CATALOG_ROLE SCHEDULER_PROGRAM_ARGS_TBL TABLE
SELECT SELECT_CATALOG_ROLE SCHEDULER_JOB_ARGS_TBL TABLE
SELECT SYS DEF$_AQCALL TABLE

PRIVILEGE GRANTEE TABLE_NAME OBJECT_TYPE
------------------------------ ------------------------------ ------------------------------ --------------------
SELECT SYS DEF$_AQCALL QUEUE
SELECT PUBLIC PRODUCT_PRIVS VIEW
SELECT PUBLIC HELP TABLE
DELETE PUBLIC MVIEW$_ADV_OWB TABLE
INSERT PUBLIC MVIEW$_ADV_OWB TABLE
SELECT PUBLIC MVIEW$_ADV_OWB TABLE
UPDATE PUBLIC MVIEW$_ADV_OWB TABLE
DELETE PUBLIC MVIEW$_ADV_PARTITION TABLE
INSERT PUBLIC MVIEW$_ADV_PARTITION TABLE
SELECT PUBLIC MVIEW$_ADV_PARTITION TABLE
UPDATE PUBLIC MVIEW$_ADV_PARTITION TABLE

PRIVILEGE GRANTEE TABLE_NAME OBJECT_TYPE
------------------------------ ------------------------------ ------------------------------ --------------------
DELETE PUBLIC MVIEW$_ADV_INDEX TABLE
INSERT PUBLIC MVIEW$_ADV_INDEX TABLE
SELECT PUBLIC MVIEW$_ADV_INDEX TABLE
UPDATE PUBLIC MVIEW$_ADV_INDEX TABLE
DELETE OLAPSYS MVIEW$_ADV_OUTPUT TABLE
INSERT OLAPSYS MVIEW$_ADV_OUTPUT TABLE
SELECT OLAPSYS MVIEW$_ADV_OUTPUT TABLE
UPDATE OLAPSYS MVIEW$_ADV_OUTPUT TABLE
DELETE OLAPSYS MVIEW$_ADV_PARTITION TABLE
INSERT OLAPSYS MVIEW$_ADV_PARTITION TABLE
SELECT OLAPSYS MVIEW$_ADV_PARTITION TABLE

PRIVILEGE GRANTEE TABLE_NAME OBJECT_TYPE
------------------------------ ------------------------------ ------------------------------ --------------------
UPDATE OLAPSYS MVIEW$_ADV_PARTITION TABLE
DELETE OLAPSYS MVIEW$_ADV_INDEX TABLE
INSERT OLAPSYS MVIEW$_ADV_INDEX TABLE
SELECT OLAPSYS MVIEW$_ADV_INDEX TABLE
UPDATE OLAPSYS MVIEW$_ADV_INDEX TABLE

49 rows selected.

SQL>

So, SYSTEM looks like a DBA account as it has the DBA role and its well known for many years as the default DBA account in an Oracle but it also has objects such as OL$ and also LogMiner objects. This is a classic case of a conflict. Is it a DBA or is it a schema?. Well like the rest of us who create Oracle databases and create users and schemas Oracle seems to have muddied the waters a bit with SYSTEM.

Ideally no one should use SYSTEM; its a default and it is the opposite of Least Rights in the database so clearly does not serve a purpose in a well designed and secure database. So can we drop SYSTEM:

SQL> drop user system cascade;
drop user system cascade
*
ERROR at line 1:
ORA-28050: specified user or role cannot be dropped


SQL>

No, we are stuck with SYSTEM; this is bad news. Ideally we should be able to have an Oracle database with just SYS and no other users and no PUBLIC grants; but that is never going to happen. It should and then we have a chance of Least Rights in our databases.

OK, more soon!

Bye from WFH

Setting Users Impossible Passwords BY VALUES and Schema Only Accounts

I plan to try and write some Oracle security based blog posts whilst working from home. These promises when I have made them in the past usually end up not coming true due to other work and things getting more priority. But; I will try as it's good to spend a little time in research and writing and sharing in this important time. I am busy with work, so that's also good but I would like to try and find some time and share some Oracle Security knowledge to somehow help people (Oracle and Security people) stuck at home to at least learn something or at least be entertained a bit.

I do have a massive list of potential blog post subjects and topics that I always collect and write down. Some I have already started some research and tests and examples and some are just titles for now. As you will have seen I have blogged more in the last couple of years than I did for some time; I want to try and do more and more regularly and get the knowledge out there.

So here goes for todays subject. A guy from the USA sent me a question. He said in Oracle 11g he used syntax such as:

SQL> connect system/oracle1@//192.168.56.85:1521/bfora.localdomain
Connected.
SQL> select banner from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Release 11.2.0.4.0 - 64bit Production
PL/SQL Release 11.2.0.4.0 - Production
CORE 11.2.0.4.0 Production
TNS for Linux: Version 11.2.0.4.0 - Production
NLSRTL Version 11.2.0.4.0 - Production

SQL> alter user pete identified by values 'LOCKED';

User altered.

SQL>

He said when he does this it creates a value in SYS.USER$.PASSWORD that can never be hashed to a real hex value so the account cannot be logged into if it is open. He asked if his thinking is correct or flawed.

Yes, this is the most famous undocumented feature of Oracle and I have been telling people to do this with accounts for 20 years or more to stop them from being logged into. In more recent times (since proxy was added to Oracle) this is a great tool to use make sure that a user does not log into a schema directly. So we do not give the schema passwords to developers / DBAs or release teams. Instead the schema remains inaccessible directly and instead the support or release is done via a proxy account. In this way no one logs onto schemas but code can still be run and installed to create objects such as tables, views, PL/SQL code. We can even enable audit targeted at the support person or release person using their proxy and audit every action whilst not auditing every action as the schema when not proxied.

But the syntax he showed and used in 11g is actually the syntax for 10g and earlier as the syntax in the BY VALUES clause didn't include the SHA1 password hash. We can see that it did work:

SQL> connect sys/oracle1@//192.168.56.85:1521/bfora.localdomain as sysdba
Connected.
SQL> select name,password,spare4 from sys.user$ where name='PETE';

NAME PASSWORD
------------------------------ ------------------------------
SPARE4
--------------------------------------------------------------------------------
PETE LOCKED


SQL>

But it is not strictly correct as we should also have the SHA1 hash in SYS.USER$.SPARE4 but it works still in 11g. The questioner said if the method is correct then he gets an error in 12c when he uses the same syntax. Lets try in 18c:

SQL> connect system/oracle1@//192.168.56.78:1523/xepdb1
Connected.
SQL> select banner from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production

SQL>

Lets create a sample user to test with:

SQL> create user pete identified by pete;

User created.

SQL>

Now try and use the old syntax as the questioner said he used it in 12c and got an error:

SQL> alter user pete identified by values 'LOCKED';
alter user pete identified by values 'LOCKED'
*
ERROR at line 1:
ORA-02153: invalid VALUES password string


SQL>

Yes, we get the same issue that the questioner said he got in 12c. He asked is this still possible from 12c as he felt its more secure to stop connections as schemas. I agree, its better to never connect as the schema so this is a method BUT 18c and 19c have a new way. Lets look at the old way first. The BY VALUES clause failed because it doesn't include the later password hashes. So instead we can use DBMS_METADATA.GET_DDL to get the right syntax:

SQL> set serveroutput on
SQL> begin
2 dbms_output.put_line(dbms_metadata.get_ddl('USER','PETE'));
3 end;
4 /

CREATE USER "PETE" IDENTIFIED BY VALUES
'S:03E63AA057AE0C4C55D184E9BF44719C43ABBC5E8B8A5C8FE06ECAFE9EDA;T:BC005789B76E3B
7E1BCD1DFDEF98B04C8DA8B1DC02170444001A59092242301AA18D93BD99D9E60187BD38DDE9A274
21C0FB77C72166B53A27199F17203E7D8B69FCD1E1F8EE26A1CA57D8BD9ED78D97'

DEFAULT TABLESPACE "USERS"
TEMPORARY TABLESPACE "TEMP"

PL/SQL procedure successfully completed.

SQL>

This gives me the right syntax. I can modify the statement above and change CREATE USER to ALTER USER and also change the hashes to 0000... instead. I can run this as follows:

SQL> ALTER USER "PETE" IDENTIFIED BY VALUES 'S:000000000000000000000000000000000000000000000000000000000000;T:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000';

User altered.

SQL>

What is stored in sys.user$:

SQL> connect sys/oracle1@//192.168.56.78:1523/xepdb1 as sysdba
Connected.
SQL> select name,password,spare4 from sys.user$ where name='PETE';

NAME
--------------------------------------------------------------------------------
PASSWORD
--------------------------------------------------------------------------------
SPARE4
--------------------------------------------------------------------------------
PETE

S:000000000000000000000000000000000000000000000000000000000000;T:000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000


SQL>

Can we instead change the string to LOCKED or similar as with the older syntax:

SQL> ALTER USER "PETE" IDENTIFIED BY VALUES 'S:LOCKED;T:LOCKED';
ALTER USER "PETE" IDENTIFIED BY VALUES 'S:LOCKED;T:LOCKED'
*
ERROR at line 1:
ORA-02153: invalid VALUES password string


SQL>

No, it seems not, maybe we can use LOCKED as a string but match the length of the original strings, 60 characters for the SHA1 S: string and 160 characters for the SHA2 T: string:

SQL> ALTER USER "PETE" IDENTIFIED BY VALUES 'S:LOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKED;T:LOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCK';
ALTER USER "PETE" IDENTIFIED BY VALUES 'S:LOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKED;T:LOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCKEDLOCK'
*
ERROR at line 1:
ORA-02153: invalid VALUES password string


SQL>

No, that doesn't work, what if we just change the zeros to a HEX letter such as A:

SQL> ALTER USER "PETE" IDENTIFIED BY VALUES 'S:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA;T:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';

User altered.

SQL>

So the number uses is most likely tested to see if it is a valid HEX string. Lets change one letter to an invalid hex string and see what happens:

SQL> ALTER USER "PETE" IDENTIFIED BY VALUES 'S:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA;T:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
ALTER USER "PETE" IDENTIFIED BY VALUES 'S:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA;T:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
*
ERROR at line 1:
ORA-02153: invalid VALUES password string


SQL>

I changed the first letter to G of the SHA1 hash and the error comes back. So lets try one more test. If we change the SHA1 hash to 59 characters BUT valid HEX what happens:

SQL> ALTER USER "PETE" IDENTIFIED BY VALUES 'S:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA;T:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
ALTER USER "PETE" IDENTIFIED BY VALUES 'S:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA;T:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
*
ERROR at line 1:
ORA-02153: invalid VALUES password string


SQL>

So, in summary, the old BY VALUES still works in 12c, 18c, 19c BUT its much stricter than the methods in 11g where you could type in any old text as an invalid password. Now you must supply a string for the SHA1 and SHA2 hashes that are the correct length, 60 characters and 160 characters and also the hash value must be valid HEX. So if you use this method set the strings to valid HEX, BUT that presumably means that because its valid hex then its maybe possible to enter some password that would hash to that HEX value. The chances of someone guessing a password combination that would hash to the HEX value you chose is pretty pretty slim.

In 18c and 19c there is now a better method. The BY VALUES is in effect now built into the DDL syntax with the NO AUTHENTICATION syntax. This is called "SCHEMA ONLY ACCOUNTS" in Oracle and is a new welcome shortcut. We can test this for my sample user PETE in 18cXE:

SQL> alter user pete no authentication;

User altered.

SQL>

The values in SYS.USER$ are:

SQL> select name,password,spare4 from sys.user$ where name='PETE';

NAME
--------------------------------------------------------------------------------
PASSWORD
--------------------------------------------------------------------------------
SPARE4
--------------------------------------------------------------------------------
PETE

S:000000000000000000000000000000000000000057C9FE8ED313BD2F8D26;T:000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000104D5ED049FF791913E7242803485640


SQL>

The values are not all zeros. For instance the last 20 characters of the SHA1 hash are the SALT. A simple SQL script called sha1.sql on my site from 2007 shows how this password algorithm works and shows that the SALT is the last 20 characters of this hash. This is interesting and if you chose to use the BY VALUES instead of this feature in 18c or 19c or indeed 20c then it would make sense to generate a random SALT also and not just use zeros. If you are on 12.1 or 12.2 then the NO AUTHENTICATION syntax is not there anyway. Why not just use all ZEROs or all 99999s or AAAAs or whatever. Well if everyone just used all 000s then it may be possible that someone at some point could brute force inputs (possible passwords) and crack or find a password that could hash to 60 zeros or 60 AAAs or whatever. A random SALT would prevent that pre-defined hash/password problem. Also don't use DBMS_METADATA.GET_DDL and use the same SYS.USER$.SPARE4 values from one database for all passwords in another.

Any schema in your database should have one of these impossible passwords or from 18c a SCHEMA ONLY ACCOUNT - the same thing really.

More on this soon!! Bye from WFH (Working From Home)

CoronaVirus - We are Still Open

Everyone must now be affected in some way about coronavirus. We had an inkling that Boris Johnson and his government would enact a more severe lock down in the UK. So in anticipation I decided on Monday that we needed to work from home and not travel to our office anymore this week. So we spent time on Monday packing up all of our IT and other files and paperwork and tools. This is all now transported and re-installed and working.

So we are still open and working full time as normal helping people secure and protect data in their Oracle databases. The only thing that has changed is that we cannot receive manual post (letters) and our office phone is not being manned as we cannot now visit the office and its not worth to re-direct for a short while.

We are open for business and are working still for a number of clients world wide remotely currently helping them in their projects to secure their data held and processed in their Oracle databases. I also recently added a lot of new online training dates to our public training schedule and this is great to fill time when you cannot work normally and of course its coronavirus safe as you can join a live in person class safely from your own home or office and interact and ask questions live with me over web conferencing.

So please note our landline phone is not being manned as its in our office and we are all working remotely now until we can get back to the office. Please contact us by email or via a direct message on any of our social media channels. Please see buttons in the footer of any of our website pages for our social channels.

Thanks!!