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):
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 is_http is False or self.current_protocol != POC_CATEGORY.PROTOCOL.HTTP:
return True
res = None
https_res = None
# this only covers most cases
redirect_https_keyword = [
# https://www.zoomeye.org/searchResult?q=%22request%20was%20sent%20to%20HTTPS%20port%22
'request was sent to https port',
# https://www.zoomeye.org/searchResult?q=%22running%20in%20SSL%20mode.%20Try%22
'running in ssl mode. try'
]
redirect_https_keyword_found = False
origin_url = self.url
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)
if url.startswith('https'):
https_res = res
# redirect to https keyword found, continue to next loop
for k in redirect_https_keyword:
if k.lower() in res.text.lower():
redirect_https_keyword_found = True
res = https_res
break
if redirect_https_keyword_found:
continue
"""
https://github.com/knownsec/pocsuite3/issues/330
status_code:
- 30x
- 50x
"""
if not str(res.status_code).startswith('20'):
continue
break
except requests.RequestException:
pass
if not isinstance(res, requests.Response):
return False
self.url = res.request.url.rstrip('/')
if self.url.split('://')[0] != self.scheme:
logger.warn(f'auto correct url: {mosaic(origin_url)} -> {mosaic(self.url)}')
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
self.netloc = f'{self.rhost}:{self.rport}'
if return_obj:
return res
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