|
@@ -8,9 +8,9 @@ As a penetration tester I have to deal daily with Oracle DBMS, both via SQL Inje
|
|
|
## Basic Information
|
|
|
Most of the times Oracle RDMS run on linux, specifically RedHat or Oracle Linux. The most version I found in the wild were 9 which is extremely old, 10, 11 as most common and 12 in the best cases.
|
|
|
Oracle has an official client called `sqlplus`. Sometimes it is extremely useful to have `sqlplus` and the import and export utilities ready in standalone packages. Please see the #Downloads sections for that.
|
|
|
-Oracle instances are defined in a file called `tnsmaes.ora` where an instance name is associated to a connection string.
|
|
|
+Oracle instances are defined in a file called `tnsnames.ora` where an instance name is associated to a connection string.
|
|
|
|
|
|
-Example tnsnames.ora:
|
|
|
+Example `tnsnames.ora`:
|
|
|
|
|
|
```
|
|
|
PROD_DB = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP) (HOST = 10.50.50.10) (PORT = 1521)) (CONNECT_DATA = (SID = PROD)))
|
|
@@ -40,6 +40,13 @@ sqlplus my_user@"(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(Host=192.168.1.10)(Port=15
|
|
|
# For a local instance if logged in with the oracle user
|
|
|
sqlplus "/ as sysdba"
|
|
|
sqlplus "sys as sysdba"
|
|
|
+sqlplus my_user/my_password@PROD_DB as sysdba
|
|
|
+```
|
|
|
+
|
|
|
+Better formatiing:
|
|
|
+```
|
|
|
+set pagesize 0;
|
|
|
+sel linesize 5000;
|
|
|
```
|
|
|
|
|
|
## Import/Export
|
|
@@ -49,7 +56,7 @@ Oracle uses a proprietary format both for storing the actual data on the disk an
|
|
|
|
|
|
Both require special privileges: this means that even if you have select privileges on a table that doesn't mean you have the privilege to bulk export it. Please refer to https://docs.oracle.com/database/121/SUTIL/GUID-8B6975D3-3BEC-4584-B416-280125EEC57E.htm
|
|
|
|
|
|
-Now the old import export format has been reverse engineered and a python script for decosing the data is provided in the downloads section. You can also find the stabdalone utilities with the required dependencies packed.
|
|
|
+Now the old import export format has been reverse engineered and there's a python script available.
|
|
|
|
|
|
## Password hashes
|
|
|
Oracle password hashes are both stored inside the database and selectable from a privileged users and stored on disk.
|
|
@@ -58,10 +65,51 @@ $ORACLE_HOME/dbs/orapw<sid> # Unix,
|
|
|
%ORACLE_HOME%\database\PWD<sid>.ora # Windows
|
|
|
```
|
|
|
```
|
|
|
-> SELECT * FROM SYS.USER
|
|
|
-```
|
|
|
-
|
|
|
-Fopr more info http://marcel.vandewaters.nl/oracle/security/password-hashes
|
|
|
+> SELECT NAME, PASSWORD FROM SYS.USER$;
|
|
|
+SYS DCB748A5BC5390F2
|
|
|
+PUBLIC
|
|
|
+CONNECT
|
|
|
+RESOURCE
|
|
|
+DBA
|
|
|
+SYSTEM EED9B65CCECDB2E9
|
|
|
+SELECT_CATALOG_ROLE
|
|
|
+EXECUTE_CATALOG_ROLE
|
|
|
+DELETE_CATALOG_ROLE
|
|
|
+EXP_FULL_DATABASE
|
|
|
+IMP_FULL_DATABASE
|
|
|
+OUTLN 4A3BA55E08595C81
|
|
|
+RECOVERY_CATALOG_OWNER
|
|
|
+GATHER_SYSTEM_STATISTICS
|
|
|
+LOGSTDBY_ADMINISTRATOR
|
|
|
+AQ_ADMINISTRATOR_ROLE
|
|
|
+AQ_USER_ROLE
|
|
|
+SCHEDULER_ADMIN
|
|
|
+DIP CE4A36B8E06CA59C
|
|
|
+HS_ADMIN_ROLE
|
|
|
+TSMSYS 3DF26A8B17D0F29F
|
|
|
+_NEXT_USER
|
|
|
+OEM_ADVISOR
|
|
|
+OEM_MONITOR
|
|
|
+DBSNMP E066D214D5421CCC
|
|
|
+PLUSTRACE
|
|
|
+CTXSYS D1D21CA56994CAB6
|
|
|
+CTXAPP
|
|
|
+XDB E76A6BD999EF9FF1
|
|
|
+ANONYMOUS anonymous
|
|
|
+XDBADMIN
|
|
|
+AUTHENTICATEDUSER
|
|
|
+XDBWEBSERVICES
|
|
|
+MDSYS 72979A94BAD2AF80
|
|
|
+HR 4C6D73C3E8B0F0DA
|
|
|
+FLOWS_FILES 364B78B9EABB9E56
|
|
|
+FLOWS_020100 16E4C012E98710D0
|
|
|
+```
|
|
|
+Old password format is `3DES(upper($username.$password))` for <12c and an harder custom method for >12.
|
|
|
+Both are supported by hashcat as `-m3100` and `-m 12300`.
|
|
|
+
|
|
|
+Fopr more info:
|
|
|
+ - http://marcel.vandewaters.nl/oracle/security/password-hashes
|
|
|
+ - https://www.trustwave.com/en-us/resources/blogs/spiderlabs-blog/changes-in-oracle-database-12c-password-hashes/
|
|
|
|
|
|
## Recon
|
|
|
To begin with Oracle has plenty of system tables and views to keep track of its properties. Some of them have either `all`, `dba` or `user` prefix. What does it mean?
|
|
@@ -77,7 +125,8 @@ From https://sqljana.wordpress.com/2016/12/21/oracle-data-dictionary-views-user-
|
|
|
> DBA* Views
|
|
|
> DBA_*: Views that start with DBA_ list all objects unless restricted by the WHERE clause
|
|
|
|
|
|
-Most of the time the most useful will be the ones with the `all_` prefix, exceot if we already are dba.
|
|
|
+Most of the time the most useful will be the ones with the `all_` prefix, except if we already are dba.
|
|
|
+Query to `SYS` tables and to `dba_*` do require high privileges.
|
|
|
|
|
|
|
|
|
Oracle default databases to exclude to get cleaner results for custom tables/columns/procedures (from https://github.com/sqlmapproject/sqlmap/blob/master/lib/core/settings.py):
|
|
@@ -87,33 +136,51 @@ Oracle default databases to exclude to get cleaner results for custom tables/col
|
|
|
|
|
|
Check Oracle version:
|
|
|
```
|
|
|
-SELECT * FROM V$VERSION;
|
|
|
-SELECT * FROM V$INSTANCE;
|
|
|
-SELECT * FROM PRODUCT_COMPONENT_VERSION;
|
|
|
+> SELECT BANNER FROM V$VERSION;
|
|
|
+Oracle Database 10g Express Edition Release 10.2.0.1.0 - Product
|
|
|
+PL/SQL Release 10.2.0.1.0 - Production
|
|
|
+CORE 10.2.0.1.0 Production
|
|
|
+TNS for Linux: Version 10.2.0.1.0 - Production
|
|
|
+NLSRTL Version 10.2.
|
|
|
```
|
|
|
-Get the current user:
|
|
|
```
|
|
|
-SELECT USER FROM DUAL;
|
|
|
+> SELECT INSTANCE_NAME, HOST_NAME, EDITION, VERSION FROM V$INSTANCE;
|
|
|
+INSTANCE_NAME HOST_NAME EDITION VERSION
|
|
|
+---------------- ---------------------------------------------------------------- ------- -----------------
|
|
|
+XE oracle.lsd.cat XE 10.2.0.1.0
|
|
|
```
|
|
|
-Get the instance name:
|
|
|
```
|
|
|
-SELECT SYS_CONTEXT('USERENV','INSTANCE_NAME') FROM DUAL;
|
|
|
-SELECT SYS_CONTEXT('USERENV', 'SID') FROM DUAL;
|
|
|
+> SELECT PRODUCT, VERSION FROM PRODUCT_COMPONENT_VERSION;
|
|
|
+
|
|
|
+PRODUCT VERSION
|
|
|
+---------------------------------------------------------------- ----------------------------------------------------------------
|
|
|
+NLSRTL 10.2.0.1.0
|
|
|
+Oracle Database 10g Express Edition 10.2.0.1.0
|
|
|
+PL/SQL 10.2.0.1.0
|
|
|
+TNS for Linux: 10.2.0.1.0
|
|
|
+
|
|
|
```
|
|
|
-Check if user is DBA:
|
|
|
+
|
|
|
+Get the current user:
|
|
|
+```
|
|
|
+SELECT USER FROM DUAL;
|
|
|
+SELECT USERNAME FROM USER_USERS;
|
|
|
```
|
|
|
|
|
|
+Get current user privileges:
|
|
|
+```
|
|
|
+SELECT * FROM SESSION_PRIVS;
|
|
|
```
|
|
|
Check if Java is available:
|
|
|
```
|
|
|
-SELECT dbms_java.get_ojvm_property(PROPSTRING=>'java.version') FROM DUAL;
|
|
|
+SELECT DBMS_JAVA.GET_OJVM_PROPERTY(PROPSTRING=>'java.version') FROM DUAL;
|
|
|
```
|
|
|
|
|
|
List all users
|
|
|
```
|
|
|
-SELECT USER FROM SYS.USER$
|
|
|
-SELECT USER, PASSWORD FROM SYS.USER$;
|
|
|
-SELECT USERNAME from DBA_USERS;
|
|
|
+SELECT USER, PASSWORD FROM SYS.USER$
|
|
|
+SELECT USERNAME, PASSWORD from DBA_USERS;
|
|
|
+SELECT USERNAME FROM ALL_USERS;
|
|
|
```
|
|
|
|
|
|
List all databases
|
|
@@ -135,19 +202,79 @@ SELECT OWNER, TABLE_NAME, COLUMNS NAME FROM ALL_TAB_COLUMNS;
|
|
|
Linked instances
|
|
|
```
|
|
|
SELECT * FROM SYS.LINK$;
|
|
|
+SELECT * FROM DBA_DB_LINKS;
|
|
|
+SELECT OWNER, USERNAME, HOST, DB_LINK FROM ALL_DB_LINKS;
|
|
|
```
|
|
|
+Password for DB Links may be cleartext, encrypted or non present depending on the version. See #Linked_Instances
|
|
|
|
|
|
-Past queries:
|
|
|
+It is also possibile to view past queries. This is extremely useful to understand how the database is being used.
|
|
|
```
|
|
|
SELECT SQL_TEXT FROM V$SQL;
|
|
|
-SELECT * FROM WRH$_SQLTEXT;
|
|
|
+SELECT SQL_TEXT FROM WRH$_SQLTEXT;
|
|
|
```
|
|
|
|
|
|
-## Common error based vectors
|
|
|
+List all procedures:
|
|
|
+```
|
|
|
+SELECT OWNER, OBJECT_NAME, OBJECT_TYPE FROM ALL_OBJECTS WHERE OBJECT_TYPE IN ('PROCEDURE', 'FUNCTION', 'PACKAGE', 'PACKAGE BODY');
|
|
|
+```
|
|
|
+List user procedures:
|
|
|
+```
|
|
|
+SELECT OBJECT_NAME, OBJECT_TYPE FROM ALL_OBJECTS WHERE OBJECT_TYPE IN ('PROCEDURE', 'FUNCTION', 'PACKAGE', 'PACKAGE BODY');
|
|
|
+```
|
|
|
+
|
|
|
+Get all non system procedures:
|
|
|
+```
|
|
|
+SELECT OWNER, OBJECT_NAME, OBJECT_TYPE FROM ALL_OBJECTS WHERE OBJECT_TYPE IN ('PROCEDURE', 'FUNCTION', 'PACKAGE', 'PACKAGE BODY') AND WHERE OWNER NOT IN ('ANONYMOUS', 'APEX_030200', 'APEX_PUBLIC_USER', 'APPQOSSYS', 'BI', 'CTXSYS', 'DBSNMP', 'DIP', 'EXFSYS', 'FLOWS_%', 'FLOWS_FILES', 'HR', 'IX', 'LBACSYS', 'MDDATA', 'MDSYS', 'MGMT_VIEW', 'OC', 'OE', 'OLAPSYS', 'ORACLE_OCM', 'ORDDATA', 'ORDPLUGINS', 'ORDSYS', 'OUTLN', 'OWBSYS', 'PM', 'SCOTT', 'SH', 'SI_INFORMTN_SCHEMA', 'SPATIAL_CSW_ADMIN_USR', 'SPATIAL_WFS_ADMIN_USR', 'SYS', 'SYSMAN', 'SYSTEM', 'WKPROXY', 'WKSYS', 'WK_TEST', 'WMSYS', 'XDB', 'XS$NULL')
|
|
|
+
|
|
|
+```
|
|
|
+
|
|
|
+Get the source code of an object:
|
|
|
+```
|
|
|
+SELECT TEXT FROM ALL_SOURCE WHERE NAME = 'MY_PROCEDURE' ORDER BY LINE;
|
|
|
+```
|
|
|
+Somatimes a source code might be obfuscated with a method that Oracle calls 'wrapping'. This is the case of most default procedures. THis format is easily reversible:
|
|
|
+ - https://github.com/DarkAngelStrike/UnwrapperPLSQL/blob/master/unwrap.py
|
|
|
+ - https://www.codecrete.net/UnwrapIt/
|
|
|
|
|
|
-## Common out of bound channels
|
|
|
+
|
|
|
+## Common error based vectors
|
|
|
|
|
|
## Linked instances
|
|
|
+Linked instances are used very often. They're very useful to an attacker because they extend the attack surface and may even allow to jump to different network.
|
|
|
+
|
|
|
+Basic Syntax:
|
|
|
+```
|
|
|
+SELECT USER FOM DUAL@MY_LINKED_DB;
|
|
|
+```
|
|
|
+
|
|
|
+Password are stored cleartext or a in a reversible format:
|
|
|
+```
|
|
|
+> SELECT PASSWORDX FROM SYS.LINK$;
|
|
|
+
|
|
|
+PASSWORDX
|
|
|
+--------------------------------------------------
|
|
|
+05D3BB995A60D0F7BC8724E1FB001819169BD0818171F28256
|
|
|
+```
|
|
|
+To decode the password look at:
|
|
|
+ -
|
|
|
+ -
|
|
|
+
|
|
|
+It is important to note that the whole recon process might be done in every linked databases. The user in the linked database might have higher privileges, a different Oracle version and different procedures and packages. It might be possibile to gain RCE in a linked database and not in the one used as entry point.
|
|
|
+
|
|
|
+Queries to linked database may also be nested which means that it is possible to run queries on a database linked to a database linked to the main instance thus making a 'jump' to a third database.
|
|
|
+While the following syntax will not work:
|
|
|
+```
|
|
|
+SELECT USER FROM DUAL@DB1@DB2; error
|
|
|
+```
|
|
|
+It is possible to create a view or a synomin to overcome the syntax problem as described here https://stackoverflow.com/questions/2094843/possible-to-link-to-another-database-link
|
|
|
+```
|
|
|
+DB1:
|
|
|
+CREATE SYNONYM X FOR MyTable@sqlServerDB
|
|
|
+
|
|
|
+DB2:
|
|
|
+(assumes db link to DB1 connects as owner of synonym)
|
|
|
+SELECT * from X@DB1
|
|
|
+```
|
|
|
|
|
|
## Procedures, packages and functions
|
|
|
|