在前面一节中,我们主要根据程序的入口走了一遍POC-T的大致流程,了解了POC-T的一个基本的工作机制,下面我们将从各个方面进行对源代码深入分析(主要安装目录来进行解析)
文件根目录
1、toolkit.conf文件(用于配置ZoomEye、Shodan、Google、fofa、bing、cloudeye的账户、代理、api_key等信息)
如上图所示,如果你想要使用POC-T进行网络爬虫以及对一些信息进行搜集等,期间如果使用到ZoomEye、shodan、bing等,那么建议您增加上面的配置类信息。
2、requirement.txt(指明该框架的使用需要哪些python功能模块的支持)
3、POC-T.py(框架的入口)
data目录————资源库(用户可控)
1、pass100.txt\pass1000.txt(弱口令)
排名前100、1000的弱口令字典,主要用于爆破处理。
2、User-agents.txt(UA字典库)
上面的字典中包含了多种UA信息,用户也可以根据自己的需求增加特殊的UA。
3、wooyun_domain(域名信息)
以上的字典当中包含了域名信息,用户也可以根据需要进行增加。
doc目录————文件及版权声明
1、banner.png
2、usage.png
lib目录————项目代码
1、__init__.py(初始化)
2、cli.py(框架整个逻辑的处理流程)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author = [email protected]
#import各种功能模块
import os.path #系统path
import traceback #异常处理
from lib.parse.cmdline import cmdLineParser #命令行信息匹配
from lib.core.option import initOptions #初始化功能选项
from lib.controller.loader import loadModule, loadPayloads #导入功能模块、payload模块
from lib.core.common import setPaths, banner, systemQuit, openBrowser #设置Path、打印banner信息、退出系统、使用浏览器打开等
from lib.core.data import paths, conf, logger, cmdLineOptions #path、配置、日志、命令行选项
from lib.core.enums import EXIT_STATUS #退出状态
from lib.core.settings import IS_WIN #是否是Windows系统
from lib.core.exception import ToolkitUserQuitException #用户退出异常
from lib.core.exception import ToolkitMissingPrivileges #权限错误
from lib.core.exception import ToolkitSystemException #系统异常
from lib.controller.engine import running #运行
from thirdparty.colorama.initialise import init as winowsColorInit #Windows界面颜色
#main函数(整个框架的入口)
def main():
"""
Main function of POC-T when running from command line.
"""
try:
paths.ROOT_PATH = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
try:
os.path.isdir(paths.ROOT_PATH)
except UnicodeEncodeError:
errMsg = "your system does not properly handle non-ASCII paths. "
errMsg += "Please move the project root directory to another location"
logger.error(errMsg)
raise SystemExit
setPaths() #设置path路径等选项
cmdLineOptions.update(cmdLineParser().__dict__) #命令参数选项匹配规则
initOptions(cmdLineOptions) #初始化功能选项
if IS_WIN:
winowsColorInit()
banner() #框架banner信息
loadModule() #导入功能模块
loadPayloads() #导入payload
run() #处理
if conf.OPEN_BROWSER:
openBrowser()
systemQuit(EXIT_STATUS.SYSETM_EXIT) #结束(退出)
except ToolkitMissingPrivileges, e: #各种异常
logger.error(e)
systemQuit(EXIT_STATUS.ERROR_EXIT)
except ToolkitSystemException, e:
logger.error(e)
systemQuit(EXIT_STATUS.ERROR_EXIT)
except ToolkitUserQuitException:
systemQuit(EXIT_STATUS.USER_QUIT)
except KeyboardInterrupt:
systemQuit(EXIT_STATUS.USER_QUIT)
except Exception:
print traceback.format_exc()
logger.warning('It seems like you reached a unhandled exception, please report it to author\'s mail: or raise a issue via:.')
if __name__ == "__main__":
main()
3、debug.py(调试\测试信息)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author = [email protected]
"""
POC-T functional testing script
"""
auto = """
# help
-h;powered by cdxy
--help;powered by cdxy
# version
-v;2.
--version;2.
# show
--show;Script Name
# --browser --single -iA -iN -iS -iF
-s test;[-] Please load targets
-s test -iA 1-10 --single;[*] [single-mode] found!
-s test -iN 10.10.0/30 --browser -oF;[-] [--browser] is based on file output
-s test -iS "http://test.com" --browser;[*] System exit.
-s test -iF data/pass100.txt -t 50 -oF;concurrent: 50;[*] System exit.
# -s
-iA 1-10;Use -s to load script
-s 1234567890 -iS aaa;Script [1234567890.py] not exist
-s test -iS aaa;[*] System exit.
-s test.py -iS aaa;[*] System exit.
-s script/test.py -iS aaa;[*] System exit.
-s ./ -iS aaa;[-] [./] not a file.
# -eT -eC -t
-eT -s test -iA 1-10 -t 5 -oF;concurrent: 5;[*] System exit.
-eT -s test -iF data/pass100.txt -t 50 -oF;concurrent: 50;[*] System exit.
-eT -s test -iA 1-10 -t 500 -oF;range: 1 to 100
-eG -s test -iS http://sss.com -oF;[*] System exit
# -oS
-s test -iS aaa;by cdxy mail:[email protected] };[*] System exit.
-s test -iS aaa -oS;[*] System exit.$mail:[email protected] }
# --limit -aS -aZ -aG
-s test -aS 1 --limit=0;[-] Invalid value in [--limit]
-s test -aS 1 --limit=2;[+] Total: 2;[*] System exit.
-s test -aZ 1 --limit=2;[+] Total: 10;[*] System exit.
-s test -aZ 1 --limit=10;[+] Total: 10;[*] System exit.
-s test -aZ 1 --limit=11;[+] Total: 20;[*] System exit.
-s test -aG 1 --limit=2;[+] Total: 10;[*] System exit.
-s test -aG 1 --limit=10;[+] Total: 10;[*] System exit.
-s test -aG 1 --limit=11;[+] Total: 20;[*] System exit.
-s test -aG faefafw32qtfafw3;[+] Total: 0;[*] System exit.
# --offset
-s test -aS 1 --offset=0;[*] System exit.
-s test -aS 1 --offset=10;[*] System exit.
# --search-type
-s test -aZ 1 --search-type "hello";[-] Invalid value in [--search-type]
-s test -aZ 1 --search-type 111;[-] Invalid value in [--search-type]
-s test -aZ 1 --search-type web;[*] System exit.
-s test -aZ 1 --search-type host;[*] System exit.
-s test -aZ 1 --search-type web,host;[-] Invalid value in [--search-type]
# --gproxy
-s test -aG 1 --gproxy="http 127.0.0.1 1111";[-] Unable to connect Google
-s test -aG 1 --gproxy="http 127.0.0.1";[-] SyntaxError in GoogleProxy string
-s test -aG 1 --gproxy="1 127.0.0.1 1";[-] Invalid proxy-type
-s test -aG 1 --gproxy="http 127.0.0.1 fa";[-] Invalid port in GoogleProxy string
-s test -aG 1 --gproxy="http 127.0.0.1 1894";[*] System exit.
-s test -aG 1 --gproxy="sock5 127.0.0.1 7070";[*] System exit.
-s test -aG 1 --gproxy "http 127.0.0.1 23124";[-] Unable to connect Google
# output
-s test -iA 1-10 -o _checko.txt;[*] System exit.
-s test -iA 1-10 -o _checko1.txt -oF;[-] Cannot use [-oF] and [-o] together
-s test -iA 1-10 -o _checko2.txt -oS;[*] System exit.
# scripts
"""
header = """#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author"""
import os
import subprocess
def headerCheck(path):
parents = os.listdir(path)
for parent in parents:
if parent == 'thirdparty':
continue
child = os.path.join(path, parent)
if os.path.isdir(child):
headerCheck(child)
elif os.path.isfile(child):
if child.endswith('.py'):
if open(child).read().startswith(header):
pass
else:
print 'Invalid header in %s' % child
def autoCheckResult(output, error, expect, unexpect):
for each in expect:
if each in output or each in error:
pass
else:
return False
for each in unexpect:
if each in output or each in error:
return False
else:
pass
return True
def autoCheck():
base = 'python POC-T.py '
for each in auto.split('\n'):
if not each or each.startswith('#'):
continue
u = each.split('$')[1:]
each = each.split('$')[0]
c = each.split(';')[0]
r = each.split(';')[1:]
command = base + c
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,shell=True)
o = process.stdout.read()
e = process.stderr.read()
if autoCheckResult(o, e, r, u):
pass
else:
print command
def checkInvalidVersion():
command = 'python3 POC-T.py -h'
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
o = process.stdout.read()
e = process.stderr.read()
if autoCheckResult(o, e, ['[CRITICAL] incompatible Python version'], []):
pass
else:
print command
def checkOutput(base_path):
target1 = os.path.join(base_path, '_checko.txt')
target2 = os.path.join(base_path, '_checko1.txt')
target3 = os.path.join(base_path, '_checko2.txt')
try:
if len(open(target1).read()) and not os.path.isfile(target2) and len(open(target3).read()):
os.remove(target1)
os.remove(target3)
else:
print '!!!failed!!!'
except IOError:
print '!!!failed!!!'
def debugMain():
try:
root_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
os.chdir(root_dir)
print '>>> base-dir [%s]' % root_dir
print '>>> start header check'
headerCheck(root_dir)
print '>>> start invalid-version check'
checkInvalidVersion()
print '>>> start command check'
autoCheck()
print '>>> start output check'
checkOutput(root_dir)
except KeyboardInterrupt:
exit('User quit!')
return
if __name__ == '__main__':
debugMain()
API子目录————用于调用fofa\google\shodan\zoomeye
fofa
1..__init__.py(初始化)
2、pack.py(核心——完成fofa认证之后使用fofa去根据用户输入的信息去查询数据)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author = bit4
import sys #sys库
from lib.core.data import paths, logger #路径、日志
from lib.utils.config import ConfigFileParser #匹配文件匹配
from lib.core.common import getSafeExString
import getpass #各种第三方库
import urllib
import base64
import json
def check(email, key): #fofa身份认证
if email and key:
auth_url = "https://fofa.so/api/v1/info/my?email={0}&key={1}".format(email, key)
try:
response = urllib.urlopen(auth_url)
if response.code == 200:
return True
except Exception, e:
# logger.error(e)
return False
return False
def FofaSearch(query, limit=100, offset=0): # TODO 付费获取结果的功能实现
try:
msg = 'Trying to login with credentials in config file: %s.' % paths.CONFIG_PATH
logger.info(msg)
email = ConfigFileParser().FofaEmail()
key = ConfigFileParser().FofaKey()
if check(email, key):
pass
else:
raise # will go to except block
except:
msg = 'Automatic authorization failed.'
logger.warning(msg)
msg = 'Please input your FoFa Email and API Key below.'
logger.info(msg)
email = raw_input("Fofa Email: ").strip()
key = getpass.getpass(prompt='Fofa API Key: ').strip()
if not check(email, key):
msg = 'Fofa API authorization failed, Please re-run it and enter a valid key.'
sys.exit(logger.error(msg))
query = base64.b64encode(query)
request = "https://fofa.so/api/v1/search/all?email={0}&key={1}&qbase64={2}".format(email, key, query)
result = []
try:
response = urllib.urlopen(request)
resp = response.readlines()[0]
resp = json.loads(resp)
if resp["error"] is None:
for item in resp.get('results'):
result.append(item[0])
if resp.get('size') >= 100:
logger.info("{0} items found! just 100 returned....".format(resp.get('size')))
except Exception, e:
sys.exit(logger.error(getSafeExString(e)))
finally:
return result
其余的三个都差不多,都是实现的API的认证之后进行的查询。
controller子目录
1、__init__.py(初始化)
2、api.py(根据API名称匹配API,之后调用API进行操作)
3、engine.py(处理机制)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author = [email protected]
import threading
import time
import traceback
from lib.core.data import th, conf, logger
from lib.core.common import dataToStdout
from lib.utils.console import getTerminalSize
from lib.utils.versioncheck import PYVERSION
from lib.core.enums import POC_RESULT_STATUS, ENGINE_MODE_STATUS
def initEngine():
th.thread_mode = True if conf.ENGINE is ENGINE_MODE_STATUS.THREAD else False
th.module_name = conf.MODULE_NAME
th.f_flag = conf.FILE_OUTPUT
th.s_flag = conf.SCREEN_OUTPUT
th.output = conf.OUTPUT_FILE_PATH
th.thread_count = th.threads_num = th.THREADS_NUM
th.single_mode = conf.SINGLE_MODE
th.scan_count = th.found_count = 0
th.console_width = getTerminalSize()[0] - 2
th.is_continue = True
th.found_single = False
th.start_time = time.time()
setThreadLock()
msg = 'Set the number of concurrent: %d' % th.threads_num
logger.success(msg)
def singleMode():
th.is_continue = False
th.found_single = True
def scan():
while 1:
if th.thread_mode: th.load_lock.acquire()
if th.queue.qsize() > 0 and th.is_continue:
payload = str(th.queue.get(timeout=1.0))
if th.thread_mode: th.load_lock.release()
else:
if th.thread_mode: th.load_lock.release()
break
try:
# POC在执行时报错如果不被处理,线程框架会停止并退出
status = th.module_obj.poc(payload)
resultHandler(status, payload)
except Exception:
th.errmsg = traceback.format_exc()
th.is_continue = False
changeScanCount(1)
if th.s_flag:
printProgress()
if th.s_flag:
printProgress()
changeThreadCount(-1)
def run():
initEngine()
if conf.ENGINE is ENGINE_MODE_STATUS.THREAD:
for i in range(th.threads_num):
t = threading.Thread(target=scan, name=str(i))
setThreadDaemon(t)
t.start()
# It can quit with Ctrl-C
while 1:
if th.thread_count > 0 and th.is_continue:
time.sleep(0.01)
else:
break
elif conf.ENGINE is ENGINE_MODE_STATUS.GEVENT:
from gevent import monkey
monkey.patch_all()
import gevent
while th.queue.qsize() > 0 and th.is_continue:
gevent.joinall([gevent.spawn(scan) for i in xrange(0, th.threads_num) if
th.queue.qsize() > 0])
dataToStdout('\n')
if 'errmsg' in th:
logger.error(th.errmsg)
if th.found_single:
msg = "[single-mode] found!"
logger.info(msg)
def resultHandler(status, payload):
if not status or status is POC_RESULT_STATUS.FAIL:
return
elif status is POC_RESULT_STATUS.RETRAY:
changeScanCount(-1)
th.queue.put(payload)
return
elif status is True or status is POC_RESULT_STATUS.SUCCESS:
msg = payload
else:
msg = str(status)
changeFoundCount(1)
if th.s_flag:
printMessage(msg)
if th.f_flag:
output2file(msg)
if th.single_mode:
singleMode()
def setThreadLock():
if th.thread_mode:
th.found_count_lock = threading.Lock()
th.scan_count_lock = threading.Lock()
th.thread_count_lock = threading.Lock()
th.file_lock = threading.Lock()
th.load_lock = threading.Lock()
def setThreadDaemon(thread):
# Reference: http://stackoverflow.com/questions/190010/daemon-threads-explanation
if PYVERSION >= "2.6":
thread.daemon = True
else:
thread.setDaemon(True)
def changeFoundCount(num):
if th.thread_mode: th.found_count_lock.acquire()
th.found_count += num
if th.thread_mode: th.found_count_lock.release()
def changeScanCount(num):
if th.thread_mode: th.scan_count_lock.acquire()
th.scan_count += num
if th.thread_mode: th.scan_count_lock.release()
def changeThreadCount(num):
if th.thread_mode: th.thread_count_lock.acquire()
th.thread_count += num
if th.thread_mode: th.thread_count_lock.release()
def printMessage(msg):
dataToStdout('\r' + msg + ' ' * (th.console_width - len(msg)) + '\n\r')
def printProgress():
msg = '%s found | %s remaining | %s scanned in %.2f seconds' % (
th.found_count, th.queue.qsize(), th.scan_count, time.time() - th.start_time)
out = '\r' + ' ' * (th.console_width - len(msg)) + msg
dataToStdout(out)
def output2file(msg):
if th.thread_mode: th.file_lock.acquire()
f = open(th.output, 'a')
f.write(msg + '\n')
f.close()
if th.thread_mode: th.file_lock.release()
4、loader.py(导入各种功能模块)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author = [email protected]
import Queue
import sys
import imp
import os
from lib.core.data import th, conf, logger, paths
from lib.core.enums import API_MODE_NAME, TARGET_MODE_STATUS
from lib.core.settings import ESSENTIAL_MODULE_METHODS
from lib.core.exception import ToolkitValueException
from lib.controller.api import runApi
from thirdparty.IPy import IPy
#导入功能模块
def loadModule():
_name = conf.MODULE_NAME
msg = 'Load custom script: %s' % _name
logger.success(msg)
fp, pathname, description = imp.find_module(os.path.splitext(_name)[0], [paths.SCRIPT_PATH])
try:
th.module_obj = imp.load_module("_", fp, pathname, description)
for each in ESSENTIAL_MODULE_METHODS:
if not hasattr(th.module_obj, each):
errorMsg = "Can't find essential method:'%s()' in current script,Please modify your script/PoC."
sys.exit(logger.error(errorMsg))
except ImportError, e:
errorMsg = "Your current scipt [%s.py] caused this exception\n%s\n%s" \
% (_name, '[Error Msg]: ' + str(e), 'Maybe you can download this module from pip or easy_install')
sys.exit(logger.error(errorMsg))
#导入payload
def loadPayloads():
infoMsg = 'Initialize targets...'
logger.success(infoMsg)
th.queue = Queue.Queue()
if conf.TARGET_MODE is TARGET_MODE_STATUS.RANGE:
int_mode()
elif conf.TARGET_MODE is TARGET_MODE_STATUS.FILE:
file_mode()
elif conf.TARGET_MODE is TARGET_MODE_STATUS.IPMASK:
net_mode()
elif conf.TARGET_MODE is TARGET_MODE_STATUS.SINGLE:
single_target_mode()
elif conf.TARGET_MODE is TARGET_MODE_STATUS.API:
api_mode()
else:
raise ToolkitValueException('conf.TARGET_MODE value ERROR.')
logger.success('Total: %s' % str(th.queue.qsize()))
#文件
def file_mode():
for line in open(conf.INPUT_FILE_PATH):
sub = line.strip()
if sub:
th.queue.put(sub)
#数列
def int_mode():
_int = conf.I_NUM2.strip().split('-')
for each in range(int(_int[0].strip()), int(_int[1].strip())):
th.queue.put(str(each))
#网段
def net_mode():
ori_str = conf.NETWORK_STR
try:
_list = IPy.IP(ori_str)
except Exception, e:
sys.exit(logger.error('Invalid IP/MASK,%s' % e))
for each in _list:
th.queue.put(str(each))
#单一目标
def single_target_mode():
th.queue.put(str(conf.SINGLE_TARGET_STR))
#api
def api_mode():
conf.API_OUTPUT = os.path.join(paths.DATA_PATH, conf.API_MODE)
if not os.path.exists(conf.API_OUTPUT):
os.mkdir(conf.API_OUTPUT)
file = runApi()
for line in open(file):
sub = line.strip()
if sub:
th.queue.put(sub)
未完,待续,后期继续更新!