Skip to content

Commit b3369ac

Browse files
bobsbobs
authored andcommitted
ODAT version 2.O: New module named 'privesc', for local privilege escalation using Oracle system privileges
1 parent fdc7bd6 commit b3369ac

File tree

8 files changed

+1106
-15
lines changed

8 files changed

+1106
-15
lines changed

Constants.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
TIMEOUT_VALUE = 5
3535
PASSWORD_EXTENSION_FILE = ".odat.save"
3636
CHALLENGE_EXT_FILE = ".odat.challenge"
37-
SHOW_SQL_REQUESTS_IN_VERBOSE_MODE = False
3837
MAX_WIDTH_TEXTTABLES = 120
3938
DEFAULT_ENCODING = 'utf8'
4039
#SEARCH module
@@ -50,3 +49,9 @@
5049
"%hasło%",
5150
"%senha%",
5251
]
52+
EXPLOITABLE_SYSTEM_PRIVILEGES = [
53+
'CREATE ANY PROCEDURE',
54+
'ANALYZE ANY',
55+
'CREATE ANY TRIGGER',
56+
'CREATE ANY INDEX',
57+
]

OracleDatabase.py

Lines changed: 138 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def __execThisQuery__(self,query=None,ld=[],isquery=True):
124124
'''
125125
cursor = self.args['dbcon'].cursor()
126126
try:
127-
if SHOW_SQL_REQUESTS_IN_VERBOSE_MODE == True: logging.info("SQL request executed: {0}".format(query))
127+
if self.args['show_sql_requests'] == True: logging.info("SQL request executed: {0}".format(query))
128128
cursor.execute(query)
129129
except Exception, e:
130130
logging.info("Impossible to execute the query `{0}`: `{1}`".format(query, self.cleanError(e)))
@@ -171,6 +171,9 @@ def __execQuery__(self,query,ld=[]):
171171
def __execProc__(self,proc,options=None):
172172
'''
173173
Execute the stored procedure
174+
- proc: procedure name
175+
- options: callproc parameters (see http://cx-oracle.readthedocs.org/en/latest/cursor.html)
176+
Return True if no error. Otherwise returns Exception (ErrorSQLRequest)
174177
'''
175178
cursor = cx_Oracle.Cursor(self.args['dbcon'])
176179
try:
@@ -283,6 +286,8 @@ def loadInformationRemoteDatabase(self):
283286
self.remoteOS = response[0]['OS']
284287
logging.info("OS version : {0}".format(self.remoteOS))
285288
return True
289+
else:
290+
return False
286291

287292
def remoteSystemIsWindows(self):
288293
'''
@@ -297,3 +302,135 @@ def remoteSystemIsLinux(self):
297302
'''
298303
if "linux" in self.remoteOS.lower() or 'solaris' in self.remoteOS.lower() : return True
299304
else : return False
305+
306+
def hasThisRole(self, role, user=None):
307+
'''
308+
Returns True if user has role. Otherwise returns False
309+
Returns None if error
310+
If user = None, user = current user
311+
'''
312+
if user == None : user = self.args['user']
313+
self.REQ_HAS_THIS_ROLE = "SELECT username FROM user_role_privs WHERE username='{0}' and granted_role='{1}'".format(user.upper(), role)
314+
response = self.__execQuery__(query=self.REQ_HAS_THIS_ROLE,ld=['username'])
315+
if isinstance(response,Exception):
316+
logging.info("Impossible to know if {0} has the role {1}: {2}".format(user, role, self.cleanError(response)))
317+
return None
318+
else:
319+
if isinstance(response,list):
320+
if len(response)==0:
321+
logging.debug("{0} has not the '{1}' role".format(user, role))
322+
return False
323+
else:
324+
logging.debug("{0} has the '{1}' role".format(user, role))
325+
return True
326+
else:
327+
logging.info("Impossible to know if {0} has the '{1}' role".format(user, role))
328+
return None
329+
330+
def hasThisPrivilege (self, privilege, user=None):
331+
'''
332+
Returns True if user has privilege. Otherwise returns False
333+
Returns None if error
334+
If user = None, user = current user
335+
'''
336+
if user == None : user = self.args['user']
337+
self.REQ_HAS_THIS_PRIVILEGE = "SELECT privilege FROM user_sys_privs WHERE privilege ='{0}'".format(privilege)
338+
response = self.__execQuery__(query=self.REQ_HAS_THIS_PRIVILEGE,ld=['privilege'])
339+
if isinstance(response,Exception):
340+
logging.info("Impossible to know if {0} has the '{1}' privilege: {2}".format(user, privilege, self.cleanError(response)))
341+
return None
342+
else:
343+
if isinstance(response,list):
344+
if len(response)==0:
345+
logging.debug("{0} has not the '{1}' privilege".format(user, privilege))
346+
return False
347+
else:
348+
logging.debug("{0} has the '{1}' privilege".format(user, privilege))
349+
return True
350+
else:
351+
logging.info("Impossible to know if {0} has the '{1}' privilege".format(user, privilege))
352+
return None
353+
354+
def grantPrivilegeOnObjectToUser(self, privilege, objectname, user):
355+
'''
356+
Grant the privilege on objectname to user
357+
Returns True ifprivilege has been granted. Otherwise returns Exception
358+
If user = None, user = current user
359+
'''
360+
if user == None : user = self.args['user']
361+
REQUEST_GRANT_PRIVILEGE_ON_OBJECT_TO_USER = "GRANT {0} ON {1} TO {2}".format(privilege, objectname, user)
362+
logging.info("Trying to grant '{0}' privilege on '{1}' to '{2}'".format(privilege, objectname, user))
363+
status = self.__execPLSQL__(REQUEST_GRANT_PRIVILEGE_ON_OBJECT_TO_USER)
364+
if isinstance(status, Exception):
365+
logging.info("Impossible to grant '{0}' privilege on '{1}' to '{2}': '{3}'".format(privilege, objectname, user, self.cleanError(status)))
366+
return status
367+
else :
368+
logging.debug("'{0}' privilege on '{1}' to '{2}' has been granted".format(privilege, objectname, user))
369+
return True
370+
371+
def dropStoredProcedure(self, procName, schema=None):
372+
'''
373+
returns True if dropped. Otherwise returns False
374+
'''
375+
if schema==None : REQUEST_DROP_STORED_PROCEDURE = "DROP PROCEDURE {0}".format(procName)
376+
else: REQUEST_DROP_STORED_PROCEDURE = "DROP PROCEDURE {1}.{0}".format(procName, schema)
377+
logging.info("Trying to drop the stored procedure '{0}'".format(procName))
378+
status = self.__execPLSQL__(REQUEST_DROP_STORED_PROCEDURE)
379+
if isinstance(status, Exception):
380+
logging.info("Impossible to drop the stored procedure '{0}': '{1}'".format(procName, self.cleanError(status)))
381+
return False
382+
else :
383+
logging.debug("The stored procedure '{0}' has bee dropped".format(procName))
384+
return True
385+
386+
def dropStoredFunction(self, fctName, schema=None):
387+
'''
388+
returns True if dropped. Otherwise returns False
389+
'''
390+
if schema==None : REQUEST_DROP_STORED_FUNCTION = "DROP FUNCTION {0}".format(fctName)
391+
else: REQUEST_DROP_STORED_FUNCTION = "DROP FUNCTION {1}.{0}".format(fctName, schema)
392+
logging.info("Trying to drop the stored function '{0}'".format(fctName))
393+
status = self.__execPLSQL__(REQUEST_DROP_STORED_FUNCTION)
394+
if isinstance(status, Exception):
395+
logging.info("Impossible to drop the stored function '{0}': '{1}'".format(fctName, self.cleanError(status)))
396+
return False
397+
else :
398+
logging.debug("The stored function '{0}' has bee dropped".format(fctName))
399+
return True
400+
401+
def dropIndex(self, indexName, schema=None):
402+
'''
403+
returns True if dropped. Otherwise returns False
404+
'''
405+
indexName = indexName.upper()
406+
if schema==None : REQUEST_DROP_INDEX = "DROP INDEX {0}".format(indexName)
407+
else: REQUEST_DROP_INDEX = "DROP INDEX {1}.{0}".format(indexName, schema)
408+
logging.info("Trying to drop the index named '{0}'".format(indexName))
409+
status = self.__execPLSQL__(REQUEST_DROP_INDEX)
410+
if isinstance(status, Exception):
411+
logging.info("Impossible to drop the index '{0}': '{1}'".format(indexName, self.cleanError(status)))
412+
return False
413+
else :
414+
logging.debug("The stored function '{0}' has been dropped".format(indexName))
415+
return True
416+
417+
def dropTrigger(self, triggerName, schema=None):
418+
'''
419+
returns True if dropped. Otherwise returns False
420+
'''
421+
triggerName = triggerName.upper()
422+
if schema==None : REQUEST_DROP_TRIGGER = "DROP TRIGGER {0}".format(triggerName)
423+
else: REQUEST_DROP_TRIGGER = "DROP TRIGGER {1}.{0}".format(triggerName, schema)
424+
logging.info("Trying to drop the trigger named '{0}'".format(triggerName))
425+
status = self.__execPLSQL__(REQUEST_DROP_TRIGGER)
426+
if isinstance(status, Exception):
427+
logging.info("Impossible to drop the trigger '{0}': '{1}'".format(triggerName, self.cleanError(status)))
428+
return False
429+
else :
430+
logging.debug("The trigger '{0}' has been dropped".format(triggerName))
431+
return True
432+
433+
434+
435+
436+

Output.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
except ImportError:
99
TERMCOLOR_AVAILABLE = False
1010

11+
1112
class Output ():
1213
'''
1314
All output except log used this object
@@ -20,6 +21,7 @@ def __init__(self, args):
2021
self.noColor = args['no-color']
2122
self.titlePos = 0
2223
self.subTitlePos = 0
24+
self.subSubTitlePos = 0
2325

2426
def title (self, m):
2527
'''
@@ -43,10 +45,21 @@ def subtitle (self, m):
4345
'''
4446
m = m.encode(encoding='UTF-8',errors='ignore')
4547
self.subTitlePos += 1
48+
self.subSubTitlePos += 0
4649
formatMesg = '[{0}.{1}] {2}'.format(self.titlePos, self.subTitlePos, m)
4750
if self.noColor == True or TERMCOLOR_AVAILABLE == False: print formatMesg
4851
else : print colored(formatMesg, 'white',attrs=['bold'])
4952

53+
def subsubtitle (self, m):
54+
'''
55+
print a sub-subtitle
56+
'''
57+
m = m.encode(encoding='UTF-8',errors='ignore')
58+
self.subSubTitlePos += 1
59+
formatMesg = '[{0}.{1}.{2}] {3}'.format(self.titlePos, self.subTitlePos, self.subSubTitlePos, m)
60+
if self.noColor == True or TERMCOLOR_AVAILABLE == False: print formatMesg
61+
else : print colored(formatMesg, 'white',attrs=['bold'])
62+
5063
def badNews (self, m):
5164
'''
5265
print a stop message
@@ -79,3 +92,9 @@ def printOSCmdOutput(self,m):
7992
print the output of a OS command
8093
'''
8194
print m.encode(encoding='UTF-8',errors='ignore')
95+
96+
def getColoredString(self, string, color, attrs=[]):
97+
'''
98+
'''
99+
if self.noColor == True or TERMCOLOR_AVAILABLE == False: return string
100+
else : return colored(string, color, attrs=attrs)

0 commit comments

Comments
 (0)