Skip to content

PoC 插件基类

为了简化 PoC 插件的编写,Pocsuite3 实现了 PoC 基类:POCBase,很多共用的代码片段都可以放到此基类中。我们编写 PoC 时,只需要继承该基类就可,比较常用的属性和方法如下:


常用属性:

self.url  # 目标 url
self.scheme  # 目标 url 的协议
self.rhost  # 目标 url 的主机名
self.rport  # 目标 url 的端口
self.host_ip  # 本机的 wan 口 ip

常用方法:

self._check()
self.get_option('key')  # 获取自定义命令行参数的值
self.parse_output({})  # 返回结果的方法,参数是一个字典,建议统一使用该方法返回结果

self._check() 方法代码如下,会进行端口开放检查、http/https 协议自动纠正,首页关键词 check,关键词蜜罐检查等功能。可以一定程度避免将 Payload 发送到蜜罐,减少误报。

   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.