Known PostgreSQL Bugs

Known PostgreSQL Bugs

PostgreSQL has fared well when comparing the number of reported security vulnerabilities against bugs in other commercial and open source databases. The Common Vulnerabilities and Exposures database ( http://www.cve.mitre.org/cgi-bin/cvekey.cgi?keyword=postgresql ) reveals in the region of 20 entries for PostgreSQL and associated applications as of January 2005, far fewer than in other DBMS. Furthermore, PostgreSQL has not had a vulnerability in the core database code that permits an unauthenticated compromise.

A number of factors perhaps explain the paucity of reported PostgreSQL vulnerabilities. First, the general standard of coding is high, and security has been integral to the development of the product for a number of years . It can also be argued that PostgreSQL has a smaller attack surface than other DBMSes. Evidence of this presents itself in the installation procedure that, by default, prevents network access and refuses to allow operation under a privileged user context; contrast this with Microsoft SQL Server, which used to install with a blank administrator password, run with system-level privilege, and listen on a number of protocols.

Table 25-1 lists the vulnerabilities that have been reported in PostgreSQL.

Table 25-1: PostgreSQL Vulnerabilities

CVE/CAN Name

Description

CVE-2002-0802

The multibyte support in PostgreSQL 6.5.x with SQL_ASCII encoding consumes an extra character when processing a character that cannot be converted, which could remove an escape character from the query and make the application subject to SQL injection attacks.

CAN-1999-0862

Insecure directory permissions in RPM distribution for PostgreSQL allows local users to gain privileges by reading a plaintext password file.

CAN-2000-1199

PostgreSQL stores usernames and passwords in plaintext in (1) pg_shadow and (2) pg_pwd, which allows attackers with sufficient privileges to gain access to databases.

CAN-2002-0972

Buffer overflows in PostgreSQL 7.2 allow attackers to cause a denial of service and possibly execute arbitrary code via long arguments to the functions (1) lpad or (2) rpad.

CAN-2002-1397

Vulnerability in the cash_words() function for PostgreSQL 7.2 and earlier allows local users to cause a denial of service and possibly execute arbitrary code via a large negative argument, possibly triggering an integer signedness error or buffer overflow.

CAN-2002-1398

Buffer overflow in the date parser for PostgreSQL before 7.2.2 allows attackers to cause a denial of service and possibly execute arbitrary code via a long date string, aka, a vulnerability "in handling long datetime input."

CAN-2002-1399

Unknown vulnerability in cash_out and possibly other functions in PostgreSQL 7.2.1 and earlier, and possibly later versions before 7.2.3, with unknown impact, based on an invalid integer input that is processed as a different data type, as demonstrated using cash_out(2).

CAN-2002-1400

Heap-based buffer overflow in the repeat() function for PostgreSQL before 7.2.2 allows attackers to execute arbitrary code by causing repeat() to generate a large string.

CAN-2002-1401

Buffer overflows in (1) circle_poly, (2) path_encode and (3) path_add (also incorrectly identified as path_addr) for PostgreSQL 7.2.3 and earlier allow attackers to cause a denial of service and possibly execute arbitrary code, possibly as a result of an integer overflow.

CAN-2002-1402

Buffer overflows in the (1) TZ and (2) SET TIME ZONE environment variables for PostgreSQL 7.2.1 and earlier allow local users to cause a denial of service and possibly execute arbitrary code.

CAN-2003-0901

Buffer overflow in to_ascii for PostgreSQL 7.2.x, and 7.3.x before 7.3.4, allows remote attackers to execute arbitrary code.

CAN-2004-0547

Buffer overflow in the ODBC driver for PostgreSQL before 7.2.1 allows remote attackers to cause a denial of service (crash).

CAN-2004-0977

The make_oidjoin_check script in the postgresql package allows local users to overwrite files via symlink attack on temporary files.

Configuration Vulnerabilities

PostgreSQL is available in tarballs containing source as well as packages containing binaries. The RPM packages up to PostgreSQL version 6.5.3-1 contained a vulnerability that permitted any local user to read usernames and passwords. The backend process creates a flat-file copy of the pg_shadow username and password database called pg_pwd. The first issue was that this file was created in mode 666, permitting read/write access to everyone. This should have been mitigated by the file permissions on the directory that this file resided in (/var/lib/pgsql); a mode of 700 (owner has read/write) would have prevented any problems.

This directory was actually set to mode 755 (everyone has read access, owner has read/write), allowing local users to read the file. It was resolved by changing the permissions on the /var/lib/pgsql directory to 700.

Versions of PostgreSQL prior to 7.4.5 contained a symlink vulnerability affecting the make_oidjoin_check script. It naively wrote to a predictable filename in /tmp without first checking whether it already existed. A local attacker could therefore place a symlink in /tmp and wait for the database administrator to execute the script. When executed, the script would overwrite data in the file pointed to via the symlink. The patch used umask() to specify file open flags of 077 (O_EXCL O_CREAT). This causes open() to fail if the file already exists; the check for existence is atomically linked to the file's creation to eliminate race conditions.

Code Execution Vulnerabilities

In August 2002 PostgreSQL version 7.2.2 was released, rectifying several buffer overflows that were made public in a series of advisories released by "Sir Mordred" of Mordred Labs. The reported issues required the attacker to have already authenticated to the database. They potentially permitted the execution of arbitrary code as the operating system database user. The original Sir Mordred advisories can be found at http://mslabs.iwebland.com/advisories/adv-0x0001.php - adv-0x0005.php .

Sir Mordred followed a full and immediate disclosure policy although exploit code was never released to the security community, if it existed. More than two years later there do not appear to be public exploits for any of the reported issues. This is in part because of the difficulty in exploiting some of the vulnerabilities.

The TZ environmental variable overflow was triggered by calling SET TIMEZONE with an overly long string. The vulnerable code is found in src/backend/commands/variable.c; there is an unbounded strcat() that places user-supplied data into the static buffer, tzbuf, which is 64 characters in size .

 static char *defaultTZ = NULL; static char TZvalue[64]; static char tzbuf[64];     /* parse_timezone()  * Handle SET TIME ZONE...  * Try to save existing TZ environment variable for later use in RESET TIME ZONE.  * - thomas 1997-11-10  */ bool parse_timezone(const char *value) {       char         *tok;           if (value == NULL)       {             reset_timezone();             return TRUE;       }           while ((value = get_token(&tok, NULL, value)) != 0)       {             /* Not yet tried to save original value from environment? */             if (defaultTZ == NULL)             {                   /* found something? then save it for later */                   if ((defaultTZ = getenv("TZ")) != NULL)                         strcpy(TZvalue, defaultTZ);                       /* found nothing so mark with an invalid pointer */                   else                         defaultTZ = (char *) -1;             }                 strcpy(tzbuf, "TZ=");             strcat(tzbuf, tok);             if (putenv(tzbuf) != 0)                   elog(ERROR, "Unable to set TZ environment variable to %s", tok);                 tzset();             pfree(tok);       }           return TRUE; }      /* parse_timezone() */ 

The patch to solve this issue was to replace the strcpy() and strcat() calls with a call to snprintf :

 snprintf(tzbuf, sizeof(tzbuf), "TZ=%s", TZvalue); 

The cash_words() function (src/backend/ utils /adt/cash.c) was also vulnerable to a buffer overflow via calls to strcat(). cash_words is used to convert a numeric value into its representation in words:

 select cash_words('1234'); one thousand two hundred thirty four dollars and zero cents 

The vulnerability occurs because the buffer "buf" is appended to without verifying there is sufficient space. The buffer is 128 characters in size and is repeatedly filled by calls to strcat(). It is easy to crash the backend via this vulnerability by simply specifying a huge negative value, but since the postmaster spawns a new backend for each connection, it is not a permanent denial of service:

 SELECT cash_words('-700000000000000000000000000000');     Backend closed the channel unexpectedly. The connection to the server was lost... 

The vulnerable code is reproduced here:

 const char * cash_words_out(Cash *value) {       static char buf[128];       char         *p = buf;       Cash            m0;       Cash            m1;       Cash            m2;       Cash            m3;           /* work with positive numbers */       if (*value < 0)       {             *value *= -1;             strcpy(buf, "minus ");             p += 6;       }       else       {             *buf = 0;       }           m0 = *value % 100;                        /* cents */       m1 = (*value / 100) % 1000;               /* hundreds */       m2 = (*value / 100000) % 1000;            /* thousands */       m3 = *value / 100000000 % 1000;            /* millions */           if (m3)       {             strcat(buf, num_word(m3));             strcat(buf, " million ");       }           if (m2)       {             strcat(buf, num_word(m2));             strcat(buf, " thousand ");       }           if (m1)             strcat(buf, num_word(m1));           if (!*p)             strcat(buf, "zero");           strcat(buf, (int) (*value / 100) == 1 ? " dollar and " : "                                                  dollars and ");       strcat(buf, num_word(m0));       strcat(buf, m0 == 1 ? " cent" : " cents");       *buf = toupper(*buf);       return (buf); }       /* cash_words_out() */ 

Exploiting this vulnerability is likely to be extremely difficult since the attacker cannot overwrite the saved return address with totally arbitrary data. The attacker is constrained to overwrite it with ASCII characters that form part of the resulting string representation of the supplied input value.

PostgreSQL contains a number of geometric data types and functions to define and manipulate them. The circle_poly() function (src/backend/utils/adt/geo_ops.c) uses the integer "npts" in a size calculation without validation: offsetof(POLYGON, p[0]) +(sizeof(poly->p[0]) * npts). An integer overflow occurs by specifying a suitably large value of npts; this causes a small amount of memory to be allocated and consequently heap data is overwritten. This vulnerability is also unlikely to be exploitable given that the heap memory overwritten will contain coordinate data of points on the circle. It was fixed by inserting an explicit integer overflow check:

 base_size = sizeof(poly->p[0]) * npts;        size = offsetof(POLYGON, p[0]) + base_size;          /* Check for integer overflow */        if (base_size / npts != sizeof(poly->p[0])  size <= base_size)              elog(ERROR, "too many points requested"); 

Integer overflows were found in several other places. The repeat() command (src/backend/utils/adt/oracle_compat.c) is used to repeat a string the specified number of times:

 select repeat('abc', 4); abcabcabcabc 

Specifying a very large count parameter caused an integer overflow to occur as the required space to store the resulting string is calculated.

 select repeat('xxx',1431655765);     Backend closed the channel unexpectedly. The connection to the server was lost... 

The vulnerable code is partially reproduced here:

 Datum repeat(PG_FUNCTION_ARGS) {       text         *string = PG_GETARG_TEXT_P(0);       int32            count = PG_GETARG_INT32(1);       text         *result;       int                  slen,                         tlen;       int                  i;       char         *cp;           if (count < 0)             count = 0;           slen = (VARSIZE(string) - VARHDRSZ);       tlen = (VARHDRSZ + (count * slen));           result = (text *) palloc(tlen);       ... 

This vulnerability is more likely to be exploitable, given that the attacker can directly influence the contents of the overwritten heap memory. The subsequent patch checks that slen does not overflow.

The lpad() and rpad() functions (src/backend/utils/adt/oracle_compat.c) contained similar integer overflows. lpad() fills up the string to the specified length by prepending the specified characters (a space by default). Rpad() functions in the same way but appends the specified characters.

 select lpad('test', 12, 'fill') fillfilltest 

These vulnerabilities are also likely to be exploitable because the attacker controls the data that is used to overwrite the heap.

Vulnerabilities in PostgreSQL Components

In addition to vulnerabilities in the core database code, various PostgreSQL components and dependencies have also had problems. The PostgreSQL ODBC driver prior to version 07.03.0200 had a buffer overflow that was triggered by specifying large username and password values. A typical web application might contain hardcoded values (because it will connect to the database with a single username/password pair). If, however, these values are user supplied, for example, via PHP, code as follows :

 $connection = @odbc_connect(DSN, $_POST['username'], $_POST['password']) 

Subsequently, an attacker would be able to exploit this by posting large strings. The attacker's exploit code would run with the privilege of the web server user. The patch, partially reproduced below, replaced the definition of make_string(), a function that returns a null- terminated string, so that it takes a maximum length parameter. All calls to make_string() were then amended.

 diff -u -r1.1.1.1 connection.c --- connection.c      22 Jan 2004 15:02:52 -0000      1.1.1.1 +++ connection.c      13 May 2004 08:47:22 -0000 @@ -107,7 +107,7 @@          ci = &conn->connInfo;   -      make_string(szDSN, cbDSN, ci->dsn); +      make_string(szDSN, cbDSN, ci->dsn, sizeof(ci->dsn));          /* get the values for the DSN from the registry */        memcpy(&ci->drivers, &globals, sizeof(globals)); @@ -120,8 +120,8 @@         * override values from DSN info with UID and authStr(pwd) This only         * occurs if the values are actually there.         */ -      make_string(szUID, cbUID, ci->username); -      make_string(szAuthStr, cbAuthStr, ci->password); +      make_string(szUID, cbUID, ci->username,sizeof(ci->username)); +      make_string(szAuthStr, cbAuthStr, ci->password, sizeof(ci->password));          /* fill in any defaults */        getDSNdefaults(ci); 

PostgreSQL's SSL support is provided via OpenSSL. OpenSSL has had a number of reported vulnerabilities, ranging from statistical attacks to buffer overflows. Perhaps the most serious of these was reported in late July 2002. It affected OpenSSL 0.9.6d and below, permitting an attacker to execute arbitrary code because of a bug in the SSLv2 handshake. It is triggered by sending a malformed CLIENT_MASTER_KEY message. The SSL handshake occurs before PostgreSQL authentication, and would therefore result in an unauthenticated compromise. The SSLv2 handshake mechanism is shown here:

 Client                   Server CLIENT_HELLO      -->                      <-- SERVER_HELLO CLIENT_MASTER_KEY -->                      <-- SERVER_VERIFY CLIENT_FINISHED   -->                      <-- SERVER_FINISHED 

The CLIENT_HELLO message contains a list of the ciphers the client supports, a session identifier, and some challenge data. The session identifier is used if the client wishes to reuse an already established session, otherwise it's empty.

The server replies with a SERVER_HELLO message, also listing all supported cipher suites, and includes a certificate with its public RSA key. The server also sends a connection identifier, which will later be used by the client to verify that the encryption works.

The client generates a random master key, encrypts it with the server's public key, and sends it with a CLIENT_MASTER_KEY message. This message also specifies the cipher selected by the client and a KEY_ARG field, whose meaning depends on the specified cipher (KEY_ARG often contains initialization vectors).

Now that both the client and the server have the master key they can generate the session keys from it. From this point on, all messages are encrypted.

The server replies with a SERVER_VERIFY message, containing the challenge data from the CLIENT_HELLO message. If the key exchange has been successful, the client will be able to decrypt this message and the challenge data returned from the server will match the challenge data sent by the client.

The client sends a CLIENT_FINISHED message with a copy of the connection identifier from the SERVER_HELLO packet. It is now the server's turn to decrypt this message and check if the connection identifier returned by the client matches that sent by the server.

Finally the server sends a SERVER_FINISHED message, completing the handshake. This message contains a session identifier, generated by the server. If the client wishes to reuse the session later, it can send this in the CLIENT_HELLO message.

The vulnerability occurred in ssl/s2_srvr.c, in the get_client_master_key() function. This function reads and processes CLIENT_MASTER_KEY packets. It reads the KEY_ARG_LENGTH value from the client and then copies the specified number of bytes into an array of a fixed size. This array is part of the SSL_SESSION structure. If the client specifies a KEY_ARG longer than 8 bytes, the variables in the SSL_SESSION structure can be overwritten with user-supplied data.

Despite some difficulties in exploiting this, a reliable exploit was produced for Apache/OpenSSL by Solar Eclipse (entitled "OpenSSL-Too-Open"). Shortly afterwards, the Slapper worm appeared, affecting approximately 14,000 Apache servers. The official OpenSSL advisory can be found at http://www.openssl.org/news/secadv_20020730.txt .



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