-- -- detect.sql -- Pete Finnigan -- 16-Jun-2003 -- -- Example code for an article for www.securityfocus.com called "detecting -- SQL injection in Oracle" by Pete Finnigan (pete@petefinnigan.com) -- website http://www.petefinnigan.com -- set serveroutput on size 1000000 spool detect.lis -- -- use a default user such as dbsnmp, of course any other user can be used, this user -- is used here for simplicity to avoid creating a user. In a production system -- first of all do not run tests like this one and do not use DBSNMP. -- -- UN-COMMENT THIS IF YOU CHOOSE THIS USER --connect dbsnmp/dbsnmp -- -- create a sample table to use in the examples -- drop table customers; create table customers ( customer_forname varchar2(30), customer_surname varchar2(30), customer_phone varchar2(30), customer_fax varchar2(30), customer_type number(10) ) tablespace users; -- -- insert three records to test with -- insert into customers ( customer_forname, customer_surname, customer_phone, customer_fax, customer_type ) values ( 'Fred', 'Clark', '999444888', '999444889', 3 ) / insert into customers ( customer_forname, customer_surname, customer_phone, customer_fax, customer_type ) values ( 'Bill', 'Jones', '999555888', '999555889', 2 ) / insert into customers ( customer_forname, customer_surname, customer_phone, customer_fax, customer_type ) values ( 'Jim', 'Clark', '999777888', '999777889', 1 ) / -- -- create a sample PL/SQL procedure to SQL Inject -- create or replace procedure get_cust (pv_surname in varchar2) is type cv_typ is ref cursor; cv cv_typ; lv_phone customers.customer_phone%type; lv_stmt varchar2(32767):='select customer_phone'|| ' from customers '|| 'where customer_surname='''|| pv_surname||''''; begin dbms_output.put_line('debug:'||lv_stmt); open cv for lv_stmt; loop fetch cv into lv_phone; exit when cv%notfound; dbms_output.put_line('::'||lv_phone); end loop; close cv; exception when others then dbms_output.put_line(sqlcode||sqlerrm); end get_cust; / sho err -- -- This is the call used for each test throughout the paper. -- exec get_cust('x'' union select username from all_users where ''x''=''x'); -- -- check before using log miner -- -- check ARCHIVELOGMODE is on select log_mode from v$database / -- check the log destination and start flag select name,value from v$parameter where name in('log_archive_start','log_archive_dest') / -- check if transaction_auditing is on, this is needed so that usernames -- are recorded in the redo select name,value from v$parameter where name = 'transaction_auditing' / -- now do the logminer test connect sys as sysdba alter system archive log current / connect dbsnmp/dbsnmp@emil set serveroutput on size 100000 exec get_cust('x'' union select username from all_users where ''x''=''x') / connect sys as sysdba alter system archive log current / -- create the logminer dictionary set serveroutput on size 1000000 exec dbms_logmnr_d.build('logmnr.dat','/tmp') / -- find the correct archive log select name from v$archived_log where completion_time=(select max(completion_time) from v$archived_log) / -- load the file into logminer and start it (note readers need to use the file -- found above not mine!!) exec dbms_logmnr.add_logfile('/export/home/u01/app/oracle/admin/emil/archive/1_7.dbf',sys.dbms_logmnr.NEW) / exec dbms_logmnr.start_logmnr(dictFileName => '/tmp/logmnr.dat') / -- search the results select scn,username,timestamp,sql_redo from v$logmnr_contents / -- -- get the OS PID for sql*net trace -- select p.spid,s.username from v$session s,v$process p where s.paddr=p.addr / -- -- test internal trace files : -- alter session set sql_trace=true / exec get_cust('x'' union select username from all_users where ''x''=''x') / -- run tkprof -- add the relevant path to the trace file. host tkprof emil_ora_616.trc output.trc sys=yes -- find the ID (change the ID to the one from your trace file) select username,user_id from dba_users where user_id=17 / -- -- reading SQL from the SGA -- select a.address address, s.hash_value hash_value, s.piece piece, s.sql_text sql_text, u.username parsing_user_id, c.username parsing_schema_id from v$sqlarea a, v$sqltext_with_newlines s, dba_users u, dba_users c where a.address=s.address and a.hash_value=s.hash_value and a.parsing_user_id=u.user_id and a.parsing_schema_id=c.user_id and exists (select 'x' from v$sqltext_with_newlines x where x.address=a.address and x.hash_value=a.hash_value and upper(x.sql_text) like '%UNION%') order by 1,2,3 / -- -- using the audit trail to monitor abuse -- -- turn on audit audit select on sys.all_users by access / audit select on dbsnmp.customers by access / -- run the exploit exec get_cust('x'' union select username from all_users where ''x''=''x') / -- check the audit trail col username for a8 col timestamp for a20 col action_name for a15 col obj_name for a10 col owner for a8 col sessionid for 999 col returncode for 999 select username, to_char(timestamp,'DD-MON-YYYY HH24:MI:SS') timestamp, action_name, obj_name, owner, sessionid, returncode from dba_audit_object order by timestamp / -- -- explore fine grained audit -- -- analyse the sample table analyze table dbsnmp.customers compute statistics / -- check if CBO is used select name,value from v$parameter where name='optimizer_mode' / -- create an audit policy begin dbms_fga.add_policy(object_schema=>'DBSNMP', object_name=>'CUSTOMERS', policy_name=>'SQL_INJECT', audit_condition=>'1=1', audit_column=>null, handler_schema=>null, handler_module=>null, enable=>true); end; / -- run the exploit set serveroutput on size 100000 exec get_cust('x'' union select username from all_users where ''x''=''x') / -- check the audit trail col db_user for a15 col object_name for a20 col sql_text for a30 word_wrapped select db_user,timestamp,object_name,sql_text from dba_fga_audit_trail order by timestamp / -- SQL to generate standard audit policies select 'exec dbms_fga.add_policy(object_schema=>'''||owner||''',object_name=>''' ||table_name||''',policy_name=>'''||table_name||''',audit_condition=>''1=1'',aud it_column=>null,handler_schema=>null,handler_module=>null,enable=>true);' from dba_tables where owner not in ('SYS','SYSTEM') / spool off