Skip to content

PoC Base Class

In order to simplify the writing of PoC scripts, Pocsuite3 implements the PoC base class: POCBase, where many common code can be placed. When writing PoC, we only need to inherit the base class, and write the core code of the Vulnerability. The commonly used properties and methods are as follows:


Common properties:

self.url # target url
self.scheme # the protocol of the target url
self.rhost # hostname of the target url
self.rport # port of the target url
self.host_ip # WAN ip address

Common method:

self._check()

# Get the value of the custom command line parameter
self.get_option('key')

# The method to return the result, the parameter is a dictionary,
# it is recommended to use this method to return the result
self.parse_output({})

The self._check() method code is as follows, it will perform port opening check, http/https protocol automatic correction, home page keyword check, honeypot check. It can avoid sending Payload to the honeypot, reducing false positives.

   def _check(self, dork='', allow_redirects=False, return_obj=False, is_http=True, honeypot_check=True):
        self.url = self.url.rstrip('/')
        u = urlparse(self.url)
        # the port closed
        if u.port and not check_port(u.hostname, u.port):
            logger.debug(f'{mosaic(self.url)}, the port is closed.')
            return False

        if not is_http:
            return True

        res = None
        netloc = self.url.split('://', 1)[-1]
        urls = OrderedSet()
        urls.add(self.url)
        urls.add(f'http://{netloc}')
        urls.add(f'https://{netloc}')
        for url in urls:
            try:
                time.sleep(0.5)
                res = requests.get(url, allow_redirects=allow_redirects)
                # access ok, the url need to be correct
                if 'plain HTTP request was sent to HTTPS port' in res.text:
                    self.url = f'https://{netloc}'
                    res = requests.get(self.url, allow_redirects=allow_redirects)
                    logger.warn(f'auto correct url to: {mosaic(self.url)}')
                # another protocol is access ok
                elif url != self.url:
                    self.url = url
                    logger.warn(f'auto correct url to: {mosaic(self.url)}')
                break
            except requests.RequestException:
                pass

        if not self.url.startswith(self.scheme):
            self.scheme = 'https' if self.url.startswith('https') else 'http'
            port = urlparse(self.url).port
            self.rport = port if port else 443 if self.scheme.startswith('https') else 80

        if return_obj:
            return res

        if res is None:
            return False

        content = str(res.headers).lower() + res.text.lower()
        dork = dork.lower()

        if dork not in content:
            return False

        if not honeypot_check:
            return True

        is_honeypot = False

        # detect honeypot
        # https://www.zoomeye.org/searchResult?q=%22GoAhead-Webs%22%20%2B%22Apache-Coyote%22
        keyword = [
            'goahead-webs',
            'apache-coyote',
            'upnp/',
            'openresty',
            'tomcat'
        ]

        sin = 0
        for k in keyword:
            if k in content:
                sin += 1

        if sin >= 3:
            logger.debug(f'honeypot: sin({sin}) >= 3')
            is_honeypot = True

        # maybe some false positives
        elif len(re.findall('<title>(.*)</title>', content)) > 5:
            logger.debug('honeypot: too many title')
            is_honeypot = True

        elif len(re.findall('basic realm=', content)) > 5:
            logger.debug('honeypot: too many www-auth')
            is_honeypot = True

        elif len(re.findall('server: ', content)) > 5:
            logger.debug('honeypot: too many server')
            is_honeypot = True

        if is_honeypot:
            logger.warn(f'{mosaic(self.url)} is a honeypot.')

        return not is_honeypot

Released under the GPLv2 License.