Nytro Posted July 26, 2012 Report Posted July 26, 2012 The history of a -probably- 13 years old Oracle bug: TNS PoisonFrom: Joxean Koret <joxeankoret () yahoo es> Date: Wed, 18 Apr 2012 23:03:00 +0200tl;dr -> Patch your database ASAP with Oracle Critical Patch UpdateApril 2012.Introduction------------The following advisory explains a vulnerability I found in 2008 in allversions of Oracle Database server until very recently. The bug isprobably available in any Oracle Database version since 1999 (Oracle 8i)to the latest one (Oracle 11g) without the CPU-APR-2012. The bug wasreported to Oracle in 2008 so it "only" took them 4 years to fix thevulnerability since reported.The vulnerability I called TNS Poison affects the component called TNSListener, which is the responsible of connections establishment. Toexploit the vulnerability no privilege is needed, just network access tothe TNS Listener. The “feature” exploited is enabled by default in allOracle versions starting with Oracle 8i and ending with Oracle 11g(without CPU-APR-2012).Vulnerability details---------------------The Oracle TNS Listener component routes connections from the client tothe database server depending on the database's instance name the clientwants to connect to. These instances are registered at the TNS Listenerby using any of the following methods:1. Local registration. The database's internal process PMON connects viaIPC to the TNS Listener and registers the database's instance name inthe local listener. This can be changed by altering the system parameterLOCAL_LISTENER (ALTER SYSTEM SET LOCAL_LISTENER='LISTENER_NAME').2. Remote registration. The database's internal process PMON connectsvia TCP (or any other network supported protocol such) to the remote TNSListener and registers the database's instance name in the remotelistener. This behavior can be specified by setting the system parameterREMOTE_LISTENER (ALTER SYSTEM SETREMOTE_LISTENER='REMOTE_LISTENER_NAME').This feature (remote registration) appeared first in Oracle 8i (1999)-this is the reason why I say it's probably vulnerable since thisversion, however, I didn't tested with such old database servers- and iscurrently used in Oracle 11g as well as in Oracle9i and 10g. The processof registering an instance is as follows:1. The client sends a TNS packet of type CONNECT (TNS_TYPE_CONNECT = 1)to the TNS Listener with the following NV string: ? Oracle 9i to 11g: (CONNECT_DATA=(COMMAND=SERVICE_REGISTER_NSGR)) ? Oracle 8i: (CONNECT_DATA=(COMMAND=SERVICE_REGISTER))2. The server answers with a TNS packet of type ACCEPT (TNS_TYPE_ACCEPT= 2). After this, the protocol communication changes a bit (all datawill be binary).3. The client sends a “data packet” (TNS_TYPE_DATA = 6) to the TNSlistener which contains the following data: 1. Service name to register. 2. Instances to register under the specified service name. 3. Maximum number of client connections allowed. 4. Current number of client connections established. 5. Handler's name. 6. IP address and port to connect to the database. 7. ...4. If the packet is well formed, the server will answer with another TNS“data packet” with the instances registered.After this step, the instances and service names are registered in theremote TNS Listener and any connection attempt to the TNS listener byusing the specified SERVICE_NAME or SID (database's instance) will berouted to the remote database server.The connection established to register the remote database must be open,otherwise, the remote TNS listener will consider that the database wascrashed and deregisters the Oracle database's instance.According to the Oracle documentation, the “PMON” process, after this,will communicate with the TNS Listener sending update packets(TNS_TYPE_DATA packets) to specify the load of the database, the numberof currently connected users, etc... Every one minute or, as most, every10 minutes (Higher database load, lower update period).This way, an attacker is able to register any instance in the remote TNSlistener and connections to the registered instance will be routed tothe attackers machine but, is this interesting? Well, not very“exciting”. But, what occurs if an attacker tries to register onealready registered instance's name or service name? The TNS listenerwill consider this newer registered instance name a cluster instance(Oracle RAC, Real Application Clusters) or a fail over instance (OracleFail over).When 2 or more database instances are registered with the same name theTNS listener will make load balance between all the registered remotedatabase servers. The latest registered remote database server willreceive the first client connection and the second will be routed to thepreviously registered remote database server.Routing client connections--------------------------The attack explained in this document can be used to, in example, routelegitimate client connections to one attacker controlled machine andforward them to the legitimate database server instance as shown bellow:------------------------------------------------------------------------ [Legit. Client 1]---------------------------- \ \ \ V [Legit. Client 2]---------------+ [Database Server] | A [Legit. Client 3]---------------+ | | | V | [ Attacker ]----------------+[Note: Between 50/75% of the connections gets routed through theattacker controlled box]------------------------------------------------------------------------The clients connects to the attacker's controlled box which acts as aTNS proxy and forwards all connections to the legitimate databaseserver, as shown in the picture. Not all the connections will be routedthrough the attacker's box as the TNS Listener will make load balancebetween all the established instances but, continuously registering thesame instance will assure, at least, that the 50% of the connectionswill be routed through our controlled box.Sniffing connections--------------------The very first use of the attack explained in this document is obvious:The attacker owns the data as almost all the connections goes throughthe attacker's box. The attacker can record all the data exchangedbetween the database server and the client machines and both client andserver will be oblivious of the attack.If the attacker just wants to own the target's data, (s)he is done. Gameover.Injecting arbitrary commands (Session hijack)---------------------------------------------As many of the client connections are connected to the legitimatedatabase through our proxy, we are also able to inject commands and/orhijack connections. To inject commands, simply, wait for the customer tosend an SQL query/statement, replace the contents of the statement withour desired command and that's all.For session's hijack, simply, close the socket opened between the clientand our box and use the established connection channel between the realdatabase server and our machine. You may start sending SQL statementsright now.Exploiting the vulnerability----------------------------The following sections show how can be launched a successful attackagainst one Oracle database. The developed POC registers the servicename ORCL11 in the TNS Listener and forwards all the connections fromthe attacker's controlled machine to the legitimate server.Sniffing connections and forwarding client requests---------------------------------------------------Imagine the following exploit scenario:1. The database server's IP address is 192.168.1.11 and has registeredthe instance ORCL11.2. The legitimate client's address is 192.168.1.12.3. The attackers machine's address is 192.168.1.25.An attacker will follow these steps:1. The attacker runs a TCP proxy which forwards all connections tohis/her local port 1521 to the real database's server port 1521.2. Attacker, now, connects to the TNS Listener via TCP/IP and sends thefollowing connect packet: (COMMAND=SERVICE_REGISTER_NSGR). 1. Note that no authentication is required.3. After receiving the server's answer the attacker sends a packet withthe following data: 1. Service to register: ORCL11. 2. Address of the fake database: 192.168.1.25. 3. Load of the database's server: 0. 1. Remember: The lower load, the higher possibility to receiveclient connections.4. The attacker's developed exploit enters in a loop and registers theinstance every one minute closing the previously opened socket. 1. The last registered database's address is the favorite to routeclient connections and the attacker wants to receive them all.Proof of concept notes----------------------The developed P.O.C. is valid just for 6 characters long service names.However, there is one easy way to change the exploit to make it workingagainst any non 6 characters long instance name:1. Create a database instance with the same name in a machine under yourcontrol.2. Add an entry like the following to your tnsnames.ora file: listener_name = (DESCRIPTION= (ADDRESS=(PROTOCOL=tcp)(HOST=192.168.1.11)(PORT=1521)))3. Change the address and port to those of the target.4. Put an sniffer in your machine listening for any connection at port1521 (Filter: port 1521).5. Connect using SQL*Plus to your locally created database as SYSDBA andexecute the following commands: 1. $ sqlplus / as sysdba 2. SQL> ALTER SYSTEM SET REMOTE_LISTENER='LISTENER_NAME'; 3. SQL> ALTER SYSTEM REGISTER;6. You will see 6 packets in Wireshark (or the sniffer you decided touse). Ignore the 2 first packets. The 3rd packet (TNS_TYPE_DATA) thatyour configured database sends from your box to the target is the oneyou are interested in. You may safely ignore all the other packets.7. Change the contents of the “buf” variable in the supplied exploitwith the contents of this packet.8. Rerun the exploit against the target.NOTE: You may use this as another attack vector. As your database (whichhas the same name as the target) is registered in the remote TNSListener, new connections that goes through the TNS listener youpoisoned will be routed to your new database. Funny.TNS Poison POC: Step by step guide----------------------------------This is the step by step guide to proof the vulnerability explained inthis document by using the supplied POC and the aux module:1. Open a terminal and run the supplied proxy.py script as shown bellow: $ ./proxy.py –localip 192.168.1.25 localport 1521 –remoteip192.168.1.11 remoteport 15212. Open another terminal and run the supplied script tnspoison.pyagainst the target as in the example shown bellow: $ ./tnspoisonv1.py 192.168.1.25 1521 ORCL11 192.168.1.11 1521 Sending initial buffer ... Answer: Accept(2) Sending registration ... '\x04N\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x04D \x08\xff\x03\x01\x00\x124444...' Answer: Data(6) '\x01J\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x01@ \x08\xff\x03\x01\x00\x1244444...' Sleeping for 10 seconds... (Ctrl+C to stop)...Now, wait for the new connections to arrive. If you checks the listenerusing the LSNRCTL tool you will something like the following:$ lsnrctl statusLSNRCTL for Linux: Version 11.1.0.6.0 ProductionConnecting to (ADDRESS=(PROTOCOL=tcp)(HOST=)(PORT=1521))STATUS of the LISTENER----------------------Alias LISTENERVersion TNSLSNR for Linux: Version 11.1.0.6.0 ProductionStart Date 08AUG2008 18:38:08Uptime 0 days 0 hr. 15 min. 46 secTrace Level offSecurity ON: Local OS AuthenticationSNMP OFFListener ParameterFile /home/joxean/oracle11g/product/11.1.0/db_2/network/admin/listener.oraListener Log File /home/joxean/oracle11g/diag/tnslsnr/joxeandesktop/listener/alert/log.xmlListening Endpoints Summary... (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521)))Services Summary...Service "ORCL11" has 2 instance(s). Instance "ORCL11", status READY, has 1 handler(s) for this service... Instance "ORCL11", status READY, has 1 handler(s) for this service...Service "ORCL11XDB" has 2 instance(s). Instance "ORCL11", status READY, has 1 handler(s) for this service... Instance "ORCL11", status READY, has 1 handler(s) for this service...Service "ORCL11_XPT" has 2 instance(s). Instance "ORCL11", status READY, has 1 handler(s) for this service... Instance "ORCL11", status READY, has 1 handler(s) for this service...The command completed successfully$ lsnrctl servicesLSNRCTL for Linux: Version 11.1.0.6.0 ProductionConnecting to (ADDRESS=(PROTOCOL=tcp)(HOST=)(PORT=1521))Services Summary...Service "ORCL11" has 2 instance(s). Instance "ORCL11", status READY, has 1 handler(s) for this service... Handler(s): "DEDICATED" established:0 refused:0 state:ready LOCAL SERVER Instance "ORCL11", status READY, has 1 handler(s) for this service... Handler(s): "DEDICATED" established:0 refused:0 state:ready REMOTE SERVER (ADDRESS=(PROTOCOL=TCP)(HOST=192.168.1.25)(PORT=1521))Service "ORCL11XDB" has 2 instance(s). Instance "ORCL11", status READY, has 1 handler(s) for this service... Handler(s): "D000" established:0 refused:0 current:0 max:972 state:ready DISPATCHER <machine: machine, pid: 19194> (ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=42265)) Instance "ORCL11", status READY, has 1 handler(s) for this service... Handler(s): "D000" established:0 refused:0 current:2048 max:1024 state:ready DISPATCHER <machine: 192.168.1.25 , pid: 11447> (ADDRESS=(PROTOCOL=tcp)(HOST=192.168.1.25)(PORT=57569))Service "ORCL11_XPT" has 2 instance(s). Instance "ORCL11", status READY, has 1 handler(s) for this service... Handler(s): "DEDICATED" established:0 refused:0 state:ready LOCAL SERVER Instance "ORCL11", status READY, has 1 handler(s) for this service... Handler(s): "DEDICATED" established:0 refused:0 state:ready REMOTE SERVER (ADDRESS=(PROTOCOL=TCP)(HOST=192.168.1.25)(PORT=1521))The command completed successfullyDetection---------The following sections explains how this attack can be somewhat detectedat the server side, although no one is perfect (except using OSutilities).Information at the RDBMS Server side------------------------------------One may think the following: “Hey! At the server side, the DBA will seethat the connections are established from untrusted clients, right?”.Well, yes and no.By using operating system tools, as is pretty obvious, the DBA will seethat there are many connections from the same origin host but, by usingthe V$SESSION dynamic view, that is, the Oracle database's suppliedmechanism to see the client connections, the DBA will see that theconnections are established from trusted clients. But, they aren't.Why the server thinks client connections are coming from trustedsources? The answer is the following: The server doesn't check if theconnections comes from a socket created from the trusted client ipaddresses, the RDBMS server just checks the user supplied NV strings inthe TNS connect packet. A TNS connect packet (TNS_TYPE_CONNECT = 1) islike the following (stripping all the binary characters, of course): (DESCRIPTION=(CONNECT_DATA=(SERVICE_NAME=orcl)(CID=(PROGRAM=sqlplus) (HOST=joxeandesktop)(USER=joxean))) (ADDRESS=(PROTOCOL=TCP)(HOST=192.168.1.11)(PORT=1521)))The highlighted fields are those that are fakeable^Wuser modifiable. So,any connection established through our controlled machine will be shownin the RDBMS server as if they were made directly from trusted clients.TNS Listener's log file-----------------------Any attempt to register a new database instance or service will beregistered in the TNS Listener. A line like the following will be shown: 04AUG2008 21:26:29 * service_register * DATABASENAME * 0It isn't sufficient/enough information but, this way, we may detect anattempt to register a new instance. No interesting information (like IPaddress, client port, etc...) is registered so, the TNS listener's logfile is not very interesting.This applies just for Oracle 8i, 9i and 10g. For Oracle 11g, however,the interesting information will logged in the alert file (one XMLformatted file). In Oracle 11g any attempt to register a new instancewill be logged in the alert file with the following information: <msg time='20080807T17: 30:19.436+02:00' org_id='oracle' comp_id='tnslsnr' type='UNKNOWN' level='16' host_id='joxeandesktop' host_addr='127.0.0.1'> <txt>07AUG2008 17:30:19 * service_register * ORCL11 * 0 </txt> </msg>Unfortunately for us^Wthe attacker, the “host_addr” field holds theinformation extracted from the socket, not from the NV strings. Oh...This only applies to Oracle 11g with the newest security featuresenabled which is, by the way, default behavior. Anyway, an attackdetected at the TNS listener's log level is not a detected attack at theRDBMS server level, neither an attack prevention method.Workarounds-----------Better than using workarounds is to patch the vulnerability. However, incase you're using an outdated version for which no patch is available orif you can't pach for a reason, the following is a list of possibleworkarounds.Possible workarounds--------------------There are many possible workarounds. The easier one is to set thefollowing parameter in the listener.ora configuration file:dynamic_registration = off.But, sometimes, you don't want to apply this workaround. In example, ifyou have an Oracle RAC cluster, all the cluster's instances must beregistered in both TNS Listeners so, this workaround is not suitable forOracle RAC clusters. To apply this workaround with Oracle RACenvironments one needs to implement load balancing at the client side,changing all the client's tnsnames.ora configuration file to add thecomplete list of Oracle RAC nodes.However, there is another possible workaround that, sometimes, issuitable for Oracle RAC environments. Edit the file protocol.ora or, forolder versions, sqlnet.ora, at the server side and add the followingdirectives: TCP.VALIDNODE_CHECKING = YES TCP.INVITED_NODE = (Comma,separated,list,of,ALL,valid,clients, ...)But, anyway, this workaround doesn't prevent valid clients from beingused as proxies. Valid clients can still exploit the vulnerabilityregardless the VALIDNODE_CHECKING directive added as the client is avalid node.Then again, there is one more suitable workaround: If customer bought(and enabled) Oracle Advanced Security feature clients can be configuredto use SSL/TLS. Thus, at both client and server side, the followingparameters must be changed in protocol.ora or sqlnet.ora: Client side: SQLNET.ENCRYPTION_CLIENT=REQUIRED Server side: SQLNET.ENCRYPTION_SERVER=REQUIREDThe value of these configuration directives must be REQUIRED and notREQUESTED, as is pretty common, otherwise the attacker can answer to theconnection attempt answering that no SSL cipher is supported at theserver side (as the attacker's controlled box is for the client thetrusted database's server) and the client will reconnect without usingSSL.Patch information-----------------The vulnerability is supposed to be fixed, as reported by Oracle, withOracle Critical Patch Update April 2012. However, I didn't tested itmyself and, to be honest, I'm very tired of the Oracle world so I didnot tested it myself. I would not be surprised if the patch doesn'tcorrectly/completely fix the vulnerability.Proof of concept and documentation----------------------------------You can download the developed proof of concept and the old documentation -wrote back in 2008- from the following links:Documentation: http://www.joxeankoret.com/download/tnspoison.pdfProof of concept: http://www.joxeankoret.com/download/tnspoison.zipReferences----------Oracle Critical Patch Update Advisory - April 2012:http://www.oracle.com/technetwork/topics/security/cpuapr2012-366314.htmlOracle Advanced Security Manual:Oracle 11ghttp://download.oracle.com/docs/cd/B28359_01/network.111/b28530/asossl.htmOracle 10ghttp://download.oracle.com/docs/cd/B19306_01/network.102/b14268/toc.htmOracle 9ihttp://downloadwest.oracle.com/docs/cd/B10500_01/network.920/a96573/toc.htmOracle 8ihttp://downloaduk.oracle.com/docs/cd/A87860_01/doc/network.817/a85430/toc.htmOracle 8.1.6 Registration:http://www.orafaq.com/node/30Configuring Remote Listener Registration:http://download.oracle.com/docs/cd/B10501_01/network.920/a96580/listener.htm#490372Notes-----Many of the notes, outputs from terminals, etc... are simply taken frommy original notes back from 2008 so, probably, there can be many thingsoutdated.Disclaimer----------The information in this advisory and any of its demonstrations isprovided "as is" without any warranty of any kind. I am not liable forany direct or indirect damages caused as a result of using theinformation or demonstrations provided in any part of this advisory.Contact-------The vulnerability was found by Joxean Koret in 2008.All your listeners are belong to us...Attachment: signature.ascDescription: This is a digitally signed message partSursa: Full Disclosure: The history of a -probably- 13 years old Oracle bug: TNS Poison Quote