0x01 前言
好久不见,搞了个知识星球,大学生补贴一下生活费,因为技术菜,所以也就50意思下,大佬勿喷,也算是记录一下自己成长的过程,最近打算学习下优秀的安全工具,就从WEB目录扫描工具DirSearch入手了,这个系列是周更,点点关注,和我一起开启自律之旅吧。
0x02 Demo
因为优秀的工具一般比较完善了,代码比较多,对新手不太友好,所以我们化繁为简,只把实现功能的最核心的代码留下,复现一个demo出来
实现命令行读取参数,并设置默认参数
from optparse import Option, OptionGroup, OptionParser
usage = "usage: %prog [options] -u baidu -f file.txt"
optparse = OptionParser(usage=usage)
general = OptionGroup(optparse,'general','default mode')
general.add_option('-u','--url',action='store',type='string',dest='URL',help='add a target,such as %default',default='baidu.com')
general.add_option('-r','--random-useragent',action='store_true',dest='UA',help='random useragent')
advanced = OptionGroup(optparse,'advanced','open advanced scan')
advanced.add_option('-t','--thread',action='store',type='int',help='set thread',dest='thread')
optparse.add_option_group(general)
optparse.add_option_group(advanced)
options,args = OptionParser.parse_args(optparse)
print(options)
输出如下:
生成配置与读取配置
import configparser
import os.path
#生成配置文件
config = configparser.ConfigParser()
config['default'] = {'user':'韬光养晦安全','id':'1'}
config['advanced'] = {'thread':'25'}
dir = os.path.dirname(__file__)
path = dir+'\'+'config.ini'
with open(path,'w') as file:
config.write(file)
#读取配置文件
config.read(path)
print(config.sections())
print(config['default']['user'])
print(config.get('default','user'))
生成的配置文件如下:
0x03 正文
由于DirSearch功能太多了,所以作者把功能点细化成了很多个模块,代码阅读起来交错复杂,于是我把【读取参数与配置】这个功能点的代码进行了整合,分成了三个文件,如下:
file.py
#关于@property和@xx.setter参考文章https://blog.csdn.net/qq_41359051/article/details/82939655
#关于*args的参考文章https://blog.csdn.net/weixin_40796925/article/details/107574267
#关于os.access的参考文章https://www.runoob.com/python/os-access.html
#关于raise NotImplementedError的参考文章https://blog.csdn.net/qq_40666620/article/details/105026716
#关于@staticmethod的参考文章https://blog.csdn.net/polyhedronx/article/details/81911548
#关于__init__的参考文章https://www.jb51.net/article/188360.htm
import os
import os.path
class FileUtils:
def exists(file_name):
return os.access(file_name,os.F_OK)
def build_path(*path_components):
if path_components:
path = os.path.join(*path_components)
else:
path = ""
return path
class File:
def __init__(self,*path_components):
self._path = FileUtils.build_path(*path_components)
def path(self):
return self._path
def path(self,value):
raise NotImplemented
def exists(self):
return FileUtils.exists(self.path)
def __enter__(self):#删除后无法读取文件流
return self
def __exit__(self,type,value,tb):#删除后无法读取文件流
pass
def _access_file(path):
with File(path) as fd:
if not fd.exists():
print(f"{path} no exists")
else:
print(f"{path} exists")
config.py
#关于configparser的参考文章https://www.cnblogs.com/plf-Jack/p/11170284.html
#关于optionparser的参考文章https://blog.csdn.net/qq_38684504/article/details/100975952
import configparser
import os
class ConfigParser(configparser.ConfigParser):
def __init__(self):
configparser.ConfigParser.__init__(self)
def safe_get(self, section, option, default="", allowed=None):
try:
result = configparser.ConfigParser.get(self, section, option)
if allowed is not None:
return result if result in allowed else default
return result
except (configparser.NoSectionError, configparser.NoOptionError):
return default
def safe_getfloat(self, section, option, default=0, allowed=None):
try:
result = configparser.ConfigParser.getfloat(self, section, option)
if allowed is not None:
return result if result in allowed else default
return result
except (configparser.NoSectionError, configparser.NoOptionError):
return default
def safe_getboolean(self, section, option, default=False, allowed=None):
try:
result = configparser.ConfigParser.getboolean(self, section, option)
if allowed is not None:
return result if result in allowed else default
return result
except (configparser.NoSectionError, configparser.NoOptionError):
return default
def safe_getint(self, section, option, default=0, allowed=None):
try:
result = configparser.ConfigParser.getint(self, section, option)
if allowed is not None:
return result if result in allowed else default
return result
except (configparser.NoSectionError, configparser.NoOptionError):
return default
def parse_config(opt):
config = ConfigParser()
config.read(opt.config)
opt.thread_count = opt.thread_count or config.safe_getint(
"general", "threads", 25
)
return opt
from file import FileUtils
import sys
SCRIPT_PATH = os.path.dirname(__file__)
VERSION = 1.0
from optparse import OptionGroup,OptionParser
def parse_arguments():
usage = "Usage: %prog [-u|--url] target [-e|--extensions] extensions [options]"
parser = OptionParser(usage, version=f"dirsearch v{VERSION}")
mandatory = OptionGroup(parser, "Mandatory")
mandatory.add_option(
"-u",
"--url",
action="append",
dest="urls",
metavar="URL",
help="Target URL(s), support multiple flags",
)
mandatory.add_option(
"--config",
action="store",
dest="config",
metavar="PATH",
help="Full path to config file, see 'config.ini' for example (Default: config.ini)",
default=FileUtils.build_path(SCRIPT_PATH, "config.ini"),
)
mandatory.add_option(
"-t",
"--threads",
action="store",
type="int",
dest="thread_count",
metavar="THREADS",
help="Number of threads",
)
parser.add_option_group(mandatory)
options, _ = parser.parse_args()
return options
def parse_options():
opt = parse_config(parse_arguments())
print(opt)
if not opt.urls:
print("URL target is missing, try using -u <url>")
exit(1)
parse_options()
config.ini
# If you want to edit dirsearch default configurations, you can
# edit values in this file. Everything after `#` is a comment
# and won't be applied
[general]
threads = 25
recursive = False
deep-recursive = False
force-recursive = False
recursion-status = 200-399,401,403
max-recursion-depth = 0
exclude-subdirs = %%ff/,.;/,..;/,;/,./,../,%%2e/,%%2e%%2e/
random-user-agents = False
max-time = 0
# subdirs = /,api/
# include-status = 200-299,401
# exclude-status = 400,500-999
# exclude-sizes = 0b,123gb
# exclude-texts = "Not found"
# exclude-regex = "^403$"
# exclude-redirect = "*/error.html"
# exclude-response = 404.html
# skip-on-status = 429,999
[dictionary]
default-extensions = php,aspx,jsp,html,js
force-extensions = False
overwrite-extensions = False
lowercase = False
uppercase = False
capitalization = False
# exclude-extensions = old,log
# prefixes = .,admin
# suffixes = ~,.bak
# wordlists = /path/to/wordlist1.txt,/path/to/wordlist2.txt
[request]
http-method = get
follow-redirects = False
# headers-file = /path/to/headers.txt
# user-agent = MyUserAgent
# cookie = SESSIONID=123
[connection]
timeout = 7.5
delay = 0
max-rate = 0
max-retries = 1
exit-on-error = False
## By disabling `scheme` variable, dirsearch will automatically identify the URI scheme
# scheme = http
# proxy = localhost:8080
# proxy-file = /path/to/proxies.txt
# replay-proxy = localhost:8000
[advanced]
crawl = False
[view]
full-url = False
quiet-mode = False
color = True
show-redirects-history = False
[output]
## Support: plain, simple, json, xml, md, csv, html, sqlite
report-format = plain
autosave-report = True
autosave-report-folder = reports/
# log-file = /path/to/dirsearch.log
# log-file-size = 50000000
原文始发于微信公众号(韬光养晦安全):【工具学习】DirSearch解构1——读取参数与配置
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论