Senin, 28 Juni 2010

Examining the Oracle Architecture

Chapter 2 (1)

We begin this chapter by examining the physical layout of the database, such as the Oracle processes and how they interact with the network. We move on to examining authentication and authorization and then move to the logical layout of the database.

Oracle Processes and Oracle on the Network

This section describes the major components of Oracle and their interaction with the network. We begin with perhaps the most crucial network-facing component, the TNS Listener.

The Oracle TNS Listener

The TNS Listener is the hub of all communications in Oracle. "TNS" stands for Transparent Network Substrate and this is the protocol that Oracle uses to communicate between client and server. The TNS protocol is described on the Ethereal web site at http://www.ethereal.com/docs/dfref/t/tns.html.

The TNS Listener responds to a number of commands such as "version," "status," and "services," and when a database server is first started, it registers with the TNS Listener using the service_register_NSGR command. This lets the TNS Listener know that the database server is ready to accept connections. Incidentally, although the service_register_NSGR command is intended to be used locally the command can be sent over the network. In the past there have been denial of service issues with this command that can kill the TNS Listener.

When a client wishes to access the database server, the client connects first to the Listener. The Listener replies back with a TCP port that the client should connect to. The client connects to this port and then authenticates to the database server. If, however, the database has been configured in MTS, or Multi Threaded Server, mode then no port is assigned as such and communication with the database server takes place over the same TCP port that the Listener is listening on. The TNS Listener usually listens on TCP port 1521 but, depending upon the version of Oracle and what applications have been installed this port may be different, for example 1526. Regardless, the TNS Listener can be configured to listen on any TCP port.

The TNS Listener is also integral to PL/SQL and external procedures that we'll talk about later. Essentially when a PL/SQL procedure calls an external procedure, the RDBMS connects to the Listener, and the Listener launches a program called extproc to which the RDBMS connects. Extproc loads the library and executes the required function. As you'll see later this can be abused by attackers to run commands without a user ID or password.

If the XML Database is enabled—and it is by default in Oracle 9 and later—the TNS Listener holds open TCP port 2100 and 8080. The former allows querying of XML data over the FTP protocol and the latter over HTTP. The Listener proxies traffic on these ports to the RDBMS.

In versions of Oracle prior to 10g, the TNS Listener could be administered remotely. What makes this particularly dangerous is the fact that by default the Listener is installed without a password so it is possible for anyone to administer the Listener. A password should be set to help secure the system. The Listener Control Utility, lsnrctl, is the tool used to manage the Listener. Using this tool it's possible, among other things, to query the Listener for registered database services and retrieve status information:

C:\oracle\ora92\bin>lsnrctl
LSNRCTL for 32-bit Windows: Version 9.2.0.1.0 - Production on 10-OCT-2004 17:31:49
Copyright (c) 1991, 2002, Oracle Corporation. All rights reserved.
Welcome to LSNRCTL, type "help" for information.
LSNRCTL> set current_listener 10.1.1.1
Current Listener is 192.168.0.34
LSNRCTL> status
Connecting to (DESCRIPTION=(CONNECT_DATA=(SID=*)(SERVICE_NAME=10.1.1.1))
(ADDRESS=(PROTOCOL=TCP)(HOST=10.1.1.1)(PORT=1521)))
STATUS of the LISTENER
------------------------
Alias LISTENER
Version TNSLSNR for 32-bit Windows: Version 9.2.0.1.0 - Production
Start Date 10-OCT-2004 16:12:50
Uptime 0 days 1 hr. 19 min. 23 sec
Trace Level off
Security ON
SNMP OFF
Listener Parameter File C:\oracle\ora92\network\admin\listener.ora
Listener Log File C:\oracle\ora92\network\log\listener.log
Listening Endpoints Summary...
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(PIPENAME=\\.\pipe\EXTPROC0ipc)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=GLADIUS)(PORT=1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=GLADIUS)(PORT=8080))
(Presentation=HTTP)(Session=RAW))
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=GLADIUS)(PORT=2100))
(Presentation=FTP)(Session=RAW))
Services Summary...
Service "ORAXP" has 1 instance(s).
Instance "ORAXP", status UNKNOWN, has 1 handler(s) for this service...
Service "PLSExtProc" has 1 instance(s).
Instance "PLSExtProc", status UNKNOWN, has 1 handler(s) for this service...
Service "oraxp.ngssoftware.com" has 1 instance(s).
Instance "oraxp", status READY, has 1 handler(s) for this service...
Service "oraxpXDB.ngssoftware.com" has 1 instance(s).
Instance "oraxp", status READY, has 1 handler(s) for this service...
The command completed successfully
LSNRCTL>

As you can see this leaks all kinds of useful information. As an interesting aside, if the Listener receives an invalid TNS packet, it will reply with a packet similar to

IP Header
Length and version: 0x45
Type of service: 0x00
Total length: 94
Identifier: 61557
Flags: 0x4000
TTL: 128
Protocol: 6 (TCP)
Checksum: 0x884c
Source IP: 10.1.1.1
Dest IP: 10.1.1.2
TCP Header
Source port: 1521
Dest port: 3100
Sequence: 2627528132
ack: 759427443
Header length: 0x50
Flags: 0x18 (ACK PSH )
Window Size: 17450
Checksum: 0xe1e8
Urgent Pointer: 0
Raw Data
00 36 00 00 04 00 00 00 22 00 00 2a 28 44 45 53 ( 6 " *(DES)
43 52 49 50 54 49 4f 4e 3d 28 45 52 52 3d 31 31 (CRIPTION=(ERR=11)
35 33 29 28 56 53 4e 4e 55 4d 3d 31 35 31 30 30 (53)(VSNNUM=15100)
30 30 36 35 29 29 (0065)))

Looking at the value of VSNNUM, 151000065 in this case, we can derive the version of the server. When 151000065 is converted into hex we begin to see it better: 9001401. This equates to Oracle version 9.0.1.4.1. The following code can be used to query this information:

/************************************
/ Compile from a command line
/
/ C:\>cl /TC oraver.c /link wsock32.lib
/
*/
#include
#include
#include

int GetOracleVersion(void);
int StartWinsock(void);
struct hostent *he;
struct sockaddr_in s_sa;
int ListenerPort=1521;
char host[260]="";
unsigned char TNSPacket[200]=
"\x00\x46\x00\x00\x01\x00\x00\x00\x01\x37\x01\x2C\x00\x00\x08\x00"
"\x7F\xFF\x86\x0E\x00\x00\x01\x00\x00\x0C\x00\x3A\x00\x00\x07\xF8"
"\x0C\x0C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0A\x4C\x00\x00"
"\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00";

int main(int argc, char *argv[])
{
unsigned int err=0;
if(argc == 1)
{
printf("\n\t*** OraVer ***");
printf("\n\n\tGets the Oracle version number.");
printf("\n\n\tC:\\>%s host [port]",argv[0]);
printf("\n\n\tDavid Litchfield\n\tdavidl@ngssoftware.com\n\t22th April 2003\n");
return 0;
}
strncpy(host,argv[1],256);
if(argc == 3)
ListenerPort = atoi(argv[2]);
err = StartWinsock();
if(err==0)
printf("Error starting Winsock.\n");
else
GetOracleVersion();
WSACleanup();
return 0;
}

int StartWinsock()
{
int err=0;
unsigned int addr;
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD( 2, 0 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 )
return 0;

if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 0 )
return 0;

s_sa.sin_addr.s_addr=INADDR_ANY;
s_sa.sin_family=AF_INET;
if (isalpha(host[0]))
{
he = gethostbyname(host);
if(he == NULL)
{
printf("Failed to look up %s\n",host);
return 0;
}
memcpy(&s_sa.sin_addr,he->h_addr,he->h_length);
}
else
{
addr = inet_addr(host);
memcpy(&s_sa.sin_addr,&addr,4);
}
return 1;
}

int GetOracleVersion(void)
{

unsigned char resp[200]="";
unsigned char ver[8]="";
unsigned char h=0,l=0,p=0,q=0;
int snd=0,rcv=0,count=0;
SOCKET cli_sock;
char *ptr = NULL;

cli_sock=socket(AF_INET,SOCK_STREAM,0);
if (cli_sock==INVALID_SOCKET)
return printf("\nFailed to create the socket.\n");

s_sa.sin_port=htons((unsigned short)ListenerPort);
if (connect(cli_sock,(LPSOCKADDR)&s_sa,sizeof(s_sa))==SOCKET_ERROR)
{
printf("\nFailed to connect to the Listener.\n");
goto The_End;
}
snd=send(cli_sock, TNSPacket , 0x3A , 0);
snd=send(cli_sock, "NGSSoftware\x00" , 12 , 0);
rcv = recv(cli_sock,resp,196,0);
if(rcv == SOCKET_ERROR)
{
printf("\nThere was a receive error.\n");
goto The_End;
}
while(count < rcv)
{
if(resp[count]==0x00)
resp[count]=0x20;
count++;
}

ptr = strstr(resp,"(VSNNUM=");
if(!ptr)
{
printf("\nFailed to get the version.\n");
goto The_End;
}
ptr = ptr + 8;
count = atoi(ptr);
count = count << 4;
memmove(ver,&count,4);
h = ver[3] >> 4;
l = ver[3] << 4;
l = l >> 4;
p = ver[1] >> 4;
q = ver[0] >> 4;
printf("\nVersion of Oracle is %d.%d.%d.%d.%d\n",h,l,ver[2],p,q);
The_End:
closesocket(cli_sock);
return 0;
}

The Database Hacker's Handbook: Defending Database Servers
by David Litchfield et al.
John Wiley & Sons © 2005

Tidak ada komentar:

Posting Komentar