Oracle


This looks like an interesting feature of Oracle 12c. I’m still not sure about the security implications but it does say interesting things about pure network monitoring security tools. Now, more than ever, what you see on the network can be something completely different than what runs on the database. So, you can see a statement like ‘select * from dual’ on the network but in the database it will be translated to ‘select * from credit_cards’…

Again, it’s early days of Oracle 12c and we all need to process a lot to understand the security implications of new features as well as the new shiny security features Oracle 12c offers.

Turns out that Tanel has an artist hidden deep down inside!

I’m sure we all did something similar once or twice in our DBA lives. I had to create a simple script to perform regular expression based data discovery for Oracle. This script will be used as a check in our McAfee Database Vulnerability Manager. We do support data discovery directly in the tool but the advantage of such a script is that all the data is processed directly in the database without pulling it over the network to the discovery tool.

First, we need to create the tables to hold the discovered data:

CREATE SEQUENCE seq_data_discovery MAXVALUE 9999999999 CYCLE
/
CREATE TABLE data_discovery
(
 id NUMBER(10),
 owner VARCHAR2(30),
 table_name VARCHAR2(30),
 column_name VARCHAR2(30),
 CONSTRAINT data_discovery_pk PRIMARY KEY (id)
)
/
CREATE TABLE data_discovery_rows
(
 id NUMBER(10),
 row_id VARCHAR2(20),
 val VARCHAR2(4000),
 CONSTRAINT data_discovery_rows_fk FOREIGN KEY (id) REFERENCES data_discovery(id)
)
/

Next, comes the stored procedure to populate the data using simple PL/SQL.

CREATE OR REPLACE procedure discover_data(p_regex IN VARCHAR2, p_owner IN VARCHAR2 := '%',
    p_table_name IN VARCHAR2 := '%', p_limit IN NUMBER := NULL)
IS
-- Discover data based on the given parameters.
-- We iterate on relevant column types for the given owners and tables and match
-- the contents to the given regex returning data into a table to the specified limit
    l_stmt VARCHAR2(32760);
    l_id NUMBER(10);
BEGIN
    -- Might want to handle varios XML types as well
    FOR r_col IN (
        SELECT tc.owner, tc.table_name, tc.column_name, tc.data_type
        FROM all_tab_columns tc, all_tables t
        WHERE tc.owner LIKE p_owner AND
            tc.table_name LIKE p_table_name AND
            tc.table_name NOT LIKE 'DATA_DISCOVERY%' AND
            tc.owner = t.owner AND
            tc.table_name = t.table_name AND
            tc.data_type IN ('VARCHAR2', 'NVARCHAR2', 'NUMBER', 'CHAR', 'NCHAR', 'CLOB', 'NCLOB')
        ORDER BY owner, table_name, column_id) LOOP
 
        -- Insert the header
        INSERT INTO data_discovery
        VALUES (seq_data_discovery.nextval, r_col.owner, r_col.table_name, r_col.column_name)
        RETURNING id INTO l_id;
        l_stmt := 'INSERT INTO data_discovery_rows SELECT ' || TO_CHAR(l_id) || ', rowid, $col FROM "' ||
            r_col.owner || '"."' || r_col.table_name ||
            '" WHERE REGEXP_LIKE($col, :1, ''i'')';
        IF p_limit IS NOT NULL
        THEN
            l_stmt := l_stmt || ' AND rownum <= :2';
        END IF;
        IF r_col.data_type IN ('VARCHAR2', 'NVARCHAR2', 'CHAR', 'NCHAR')
        THEN
            l_stmt := REPLACE(l_stmt, '$col', '"' || r_col.column_name || '"');
        ELSIF r_col.data_type IN ('CLOB', 'NCLOB')
        THEN
            l_stmt := REPLACE(l_stmt, '$col', 'dbms_lob.substr("' || r_col.column_name || '", 4000)');
        ELSIF r_col.data_type = 'NUMBER'
        THEN
            l_stmt := REPLACE(l_stmt, '$col', 'TO_CHAR("' || r_col.column_name || '")');
        END IF;
        IF p_limit IS NOT NULL
        THEN
            EXECUTE IMMEDIATE l_stmt USING p_regex, p_limit;
        ELSE
            EXECUTE IMMEDIATE l_stmt USING p_regex;
        END IF;
    END LOOP;
END;
/

I’m sure this can be improved in many ways but I basically had 30 minutes to hack this together and connect it to the scan tool.

I’ve attended BlackHat Vegas last week and of course went to see David Litchfield’s presentation. It started rather slow with vulnerabilities I was already familiar with but he saved the best for last. Another Oracle 0day – and I’ve got the pictures to prove it!

Slide image

 

 

And this:

An example of Oracle 0day

 

As you can see above, creating a table with a specially crafted blob column, creating an ODCI (Oracle Data Cartridge Interface) index on it, gathering statistics and then dropping the table triggers a dynamic statement with the column name not properly escaped.

Nice one, David – although we had to scramble and quickly protect against it with our McAfee vPatch solution.

Joxean Koret, a hacker we’ve worked with in the past, has just released a 0day following Oracle’s April 2012 CPU. As far as I understand, Joxean believed that the CPU fixed the issue as his name was mentioned and this was the feedback he got from both Oracle and the company he sold the hack to.

But, to his surprise, it turns out that Oracle did not really fix the issue. Oracle’s response was that the issue will be fixed in the next version. This is really confusing because Oracle’s customers expect the CPU to mention only fixed vulnerabilities.

All in all, a very solid work by Joxean!

UPDATE: official word from Oracle

Here is the presentation and demo application I’ve used for the hacking exposed webinar I did on April 14th. The download file includes an eclipse project and instructions under the “etc” folder. It also includes a few scripts I used for blind SQL injection and worm infection.

Tell me what you think…

HackingExposed

I was preparing a presentation for RMOUG and wanted to show how easy it is to crack Oracle passwords once you get the hashes.

There are a lot of Oracle password crackers out there but I find that using low level C code in a presentation makes theĀ audience leave before you get to the half of the page. Using PL/SQL is a possibility but I wanted a very quick and concise way of showing the relevant code. So, Python to the rescue. But, I did not want to write code that requires installation of the Python Oracle drivers and would be tied to a specific compiled version so I used a simple class I wrote about here to do the DB connection.

The main piece of code is the password calculation which in Python looks like this:

s = hashlib.sha1()
s.update(p)
s.update(salt)
return s.hexdigest().upper()

That’s about it. The rest of the code plays with various options, handles the select from the database, iteration on the dictionary file and splitting the hash from the spare4 field into the hash and salt. I find that using Python allows you to do quick hacks and add more checks to the cracker easily.

So, here is the code. Love to hear your thoughts. Also, if someone can test it on Windows I will be grateful.

PS – if I’ll get permission from Alex, I will post his password file and complete the download package.

I’m flying to UK on the 28th to participate in the UK Oracle user group conference. It’s one of the more technical and interesting conferences out there for Oracle and I love attending.

So, as a speaker, I had to register. While in the process of submitting my details, I got an error from the registration application. Of course the error tells a lot about the registration application technology being used and guess what, it’s not Oracle šŸ™‚

Here is the error – what do you think is the back-end technology?

error '80020009'
/ukoug/reg_m.asp

Not to mention that I got my password sent to me in an email (it’s not a generated password, I chose it a while ago). I think no explanation is required as to why this is bad. And also, the form submits the details as GET parameters with my password there on the URL line for everyone to see. Did I mention no SSL?


So, we all know that Oracle used to be non-case sensitive when it came to user names and passwords. We also know that since 11g this is not the case and Oracle, by default, is case sensitive.

The one thing I wanted to point out is that even if you are using sec_case_sensitive_logon=false and ignore the case of passwords for backward compatibility, Oracle will still compute the spare4 field (hash) just in case you will turn the parameter to true.

This means that when you choose passwords, you should actually choose a mixed-case password even if it does not matter right now because if an attacker will get access to your hashes, mixing the case will make them harder to break. One has to remember that calculating the hash is much faster than the older algorithm (the password field) so an attacker will probably try the spare4 field first.

How many of you are actually using a mixed case password for Oracle accounts?

Alex wrote a nice blog post showing that the 0day found by David Litchfield [pdf] is now fixed in the newest Oracle 11.2.0.1 release for Windows. He has some analysis of the fix as well as some good examples of using Repscan to view permissions and audit records using the online browser.

Whenever I need to check some security related (and sometimes non-security related) stuff in the database, I find myself using Repscan online browser more and more because of its ease of use and prepared queries.

Good stuff, Alex.

Next Page »