实现finder模块(从响应体和JS文件中再次发现新子域)

This commit is contained in:
Jing Ling
2020-07-24 01:43:59 +08:00
parent 3a935c201d
commit 62d8b76c21
12 changed files with 797 additions and 116 deletions
+2 -2
View File
@@ -276,8 +276,8 @@ FLAGS
- [ ] 各模块持续优化和完善
- [x] 子域监控(标记每次新发现的子域)
- [ ] 子域收集爬虫实现(包括从JS等静态资源文件中收集子域)
- [ ] 操作强大交互人性的前端界面实现(暂定:前端:Element + 后端:Flask
- [x] 子域收集爬虫实现(包括从JS等静态资源文件中收集子域)
- [ ] 操作强大交互人性的前端界面实现
更多详细信息请阅读[todo.md](https://github.com/shmilylty/OneForAll/tree/master/docs/todo.md)。
+1 -1
View File
@@ -95,7 +95,7 @@ class Database(object):
:param str table_name: table name
:param list results: results list
:param str module_name: mo
:param str module_name: module
"""
logger.log('TRACE', f'Saving the subdomain results of {table_name} '
f'found by module {module_name} into database')
+3 -35
View File
@@ -212,39 +212,7 @@ class Module(object):
return self.proxy
def match_subdomains(self, html, distinct=True, fuzzy=True):
"""
Use regexp to match subdomains
:param str html: response html text
:param bool distinct: deduplicate results or not (default True)
:param bool fuzzy: fuzzy match subdomain or not (default True)
:return set/list: result set or list
"""
logger.log('TRACE', f'Use regexp to match subdomains in the response body')
if fuzzy:
regexp = r'(?:[a-z0-9](?:[a-z0-9\-]{0,61}[a-z0-9])?\.){0,}' \
+ self.domain.replace('.', r'\.')
result = re.findall(regexp, html, re.I)
if not result:
return set()
deal = map(lambda s: s.lower(), result)
if distinct:
return set(deal)
else:
return list(deal)
else:
regexp = r'(?:\>|\"|\'|\=|\,)(?:http\:\/\/|https\:\/\/)?' \
r'(?:[a-z0-9](?:[a-z0-9\-]{0,61}[a-z0-9])?\.){0,}' \
+ self.domain.replace('.', r'\.')
result = re.findall(regexp, html, re.I)
if not result:
return set()
regexp = r'(?:http://|https://)'
deal = map(lambda s: re.sub(regexp, '', s[1:].lower()), result)
if distinct:
return set(deal)
else:
return list(deal)
return utils.match_subdomains(self.domain, html, distinct, fuzzy)
@staticmethod
def get_maindomain(domain):
@@ -305,11 +273,11 @@ class Module(object):
'new': None,
'url': None,
'subdomain': None,
'port': None,
'level': None,
'cname': None,
'content': None,
'public': None,
'port': None,
'status': None,
'reason': None,
'title': None,
@@ -369,11 +337,11 @@ class Module(object):
'new': None,
'url': url,
'subdomain': subdomain,
'port': 80,
'level': level,
'cname': cname,
'content': content,
'public': public,
'port': 80,
'status': None,
'reason': reason,
'title': None,
+14 -19
View File
@@ -9,7 +9,6 @@ from bs4 import BeautifulSoup
from common import utils
from config.log import logger
from config import setting
from common.database import Database
def get_limit_conn():
@@ -35,7 +34,7 @@ def get_ports(port):
if not ports: # 意外情况
logger.log('ERROR', 'The specified request port range is incorrect')
ports = {80}
logger.log('INFOR', 'Port range:{ports}')
logger.log('INFOR', f'Port range:{ports}')
return set(ports)
@@ -110,7 +109,7 @@ async def fetch(session, method, url):
text = await resp.text(encoding=None, errors='ignore')
return resp, text
except Exception as e:
return e
return e, None
def get_title(markup):
@@ -154,15 +153,15 @@ def get_title(markup):
def request_callback(future, index, datas):
result = future.result()
if isinstance(result, BaseException):
logger.log('TRACE', result.args)
name = utils.get_classname(result)
datas[index]['reason'] = name + ' ' + str(result)
resp, text = future.result()
if isinstance(resp, BaseException):
exception = resp
logger.log('TRACE', exception.args)
name = utils.get_classname(exception)
datas[index]['reason'] = name + ' ' + str(exception)
datas[index]['request'] = 0
datas[index]['alive'] = 0
elif isinstance(result, tuple):
resp, text = result
else:
datas[index]['reason'] = resp.reason
datas[index]['status'] = resp.status
datas[index]['request'] = 1
@@ -257,17 +256,17 @@ def run_request(domain, data, port):
:param str domain: domain to be requested
:param list data: subdomains data to be requested
:param str port: range of ports to be requested
:param any port: range of ports to be requested
:return list: result
"""
logger.log('INFOR', 'Start subdomain request module')
logger.log('INFOR', f'Start requesting subdomains of {domain}')
loop = set_loop()
data = utils.set_id_none(data)
request_coroutine = bulk_request(data, port)
data = loop.run_until_complete(request_coroutine)
loop.run_until_complete(asyncio.sleep(0.25))
count = utils.count_alive(data)
logger.log('INFOR', f'Request module found {domain} have {count} alive subdomains')
logger.log('INFOR', f'Found that {domain} has {count} alive subdomains')
return data
@@ -277,7 +276,6 @@ def urls_request(urls):
request_coroutine = async_request(urls)
data = loop.run_until_complete(request_coroutine)
loop.run_until_complete(asyncio.sleep(0.25))
logger.log('INFOR', 'End urls request module')
return data
@@ -288,8 +286,5 @@ def save_db(name, data):
:param str name: table name
:param list data: data to be saved
"""
db = Database()
db.drop_table(name)
db.create_table(name)
db.save_db(name, data, 'request')
db.close()
logger.log('INFOR', f'Saving requested results')
utils.save_db(name, data, 'request')
+5 -9
View File
@@ -50,17 +50,13 @@ def update_data(data, records):
def save_db(name, data):
"""
保存解析结果到数据库
Save resolved results to database
:param str name: 保存表名
:param list data: 待保存的数据
:param str name: table name
:param list data: data to be saved
"""
logger.log('INFOR', f'Saving resolved results')
db = Database()
db.drop_table(name)
db.create_table(name)
db.save_db(name, data, 'resolve')
db.close()
utils.save_db(name, data, 'resolve')
def save_subdomains(save_path, subdomain_list):
@@ -161,7 +157,7 @@ def run_resolve(domain, data):
:return: 解析得到的结果列表
:rtype: list
"""
logger.log('INFOR', f'Start resolve subdomains of {domain}')
logger.log('INFOR', f'Start resolving subdomains of {domain}')
subdomains = filter_subdomain(data)
if not subdomains:
return data
+53
View File
@@ -17,6 +17,7 @@ from records import Record, RecordCollection
from dns.resolver import Resolver
from common.domain import Domain
from common.database import Database
from config import setting
from config.log import logger
@@ -214,6 +215,21 @@ def check_format(format, count):
return 'csv'
def save_db(name, data, module):
"""
Save request results to database
:param str name: table name
:param list data: data to be saved
:param str module: module name
"""
db = Database()
db.drop_table(name)
db.create_table(name)
db.save_db(name, data, module)
db.close()
def save_data(path, data):
"""
保存数据到文件
@@ -663,3 +679,40 @@ def ip_to_int(ip):
logger.log('ERROR', e.args)
return None
return int(ipv4)
def match_subdomains(domain, html, distinct=True, fuzzy=True):
"""
Use regexp to match subdomains
:param str domain: main domain
:param str html: response html text
:param bool distinct: deduplicate results or not (default True)
:param bool fuzzy: fuzzy match subdomain or not (default True)
:return set/list: result set or list
"""
logger.log('TRACE', f'Use regexp to match subdomains in the response body')
if fuzzy:
regexp = r'(?:[a-z0-9](?:[a-z0-9\-]{0,61}[a-z0-9])?\.){0,}' \
+ domain.replace('.', r'\.')
result = re.findall(regexp, html, re.I)
if not result:
return set()
deal = map(lambda s: s.lower(), result)
if distinct:
return set(deal)
else:
return list(deal)
else:
regexp = r'(?:\>|\"|\'|\=|\,)(?:http\:\/\/|https\:\/\/)?' \
r'(?:[a-z0-9](?:[a-z0-9\-]{0,61}[a-z0-9])?\.){0,}' \
+ domain.replace('.', r'\.')
result = re.findall(regexp, html, re.I)
if not result:
return set()
regexp = r'(?:http://|https://)'
deal = map(lambda s: re.sub(regexp, '', s[1:].lower()), result)
if distinct:
return set(deal)
else:
return list(deal)
+1
View File
@@ -18,6 +18,7 @@ temp_save_dir = result_save_dir.joinpath('temp')
enable_check_version = True # 开启最新版本检查
enable_dns_resolve = True # 使用DNS解析子域(默认True)
enable_http_request = True # 使用HTTP请求子域(默认True)
enable_finder_module = True # 开启finder模块(默认True)
enable_takeover_check = False # 开启子域接管风险检查(默认False)
# 参数port可选值有'default', 'small', 'large'
http_request_port = 'default' # HTTP请求子域(默认'default',探测80端口)
+621
View File
@@ -0,0 +1,621 @@
[
"npm.js",
"bower.js",
"component.js",
"spm.js",
"jam.js",
"jspm.js",
"ender.js",
"volo.js",
"duo.js",
"yarn.js",
"requirejs.js",
"browserify.js",
"seajs.js",
"headjs.js",
"curl.js",
"lazyload.js",
"systemjs.js",
"lodjs.js",
"esl.js",
"modulejs.js",
"webpack.js",
"rollup.js",
"brunch.js",
"parcel.js",
"microbundle.js",
"typescript.js",
"hegel.js",
"typl.js",
"mocha.js",
"jasmine.js",
"qunit.js",
"jest.js",
"prova.js",
"dalekjs.js",
"protractor.js",
"tape.js",
"testcafe.js",
"ava.js",
"cypress.js",
"chai.js",
"enzyme.js",
"proxyquire.js",
"istanbul.js",
"blanket.js",
"jscover.js",
"phantomjs.js",
"slimerjs.js",
"casperjs.js",
"zombie.js",
"totoro.js",
"karma.js",
"nightwatch.js",
"intern.js",
"yolpo.js",
"puppeteer.js",
"webdriverio.js",
"prettier.js",
"jshint.js",
"jscs.js",
"jsfmt.js",
"jsinspect.js",
"eslint.js",
"jslint.js",
"aurelia.js",
"backbone.js",
"meteor.js",
"ractive.js",
"vue.js",
"svelte.js",
"knockout.js",
"spine.js",
"canjs.js",
"react.js",
"hyperapp.js",
"preact.js",
"nativescript.js",
"riot.js",
"thorax.js",
"chaplin.js",
"marionette.js",
"ripple.js",
"rivets.js",
"derby.js",
"jsblocks.js",
"liquidlava.js",
"feathers.js",
"keo.js",
"atvjs.js",
"makefun.js",
"keystonejs.js",
"ghost.js",
"apostrophe.js",
"taracotjs.js",
"nodizecms.js",
"cody.js",
"pencilblue.js",
"strapi.js",
"factor.js",
"nunjucks.js",
"dot.js",
"dustjs.js",
"eco.js",
"pug.js",
"ejs.js",
"xtemplate.js",
"marko.js",
"swig.js",
"ehtml.js",
"d3.js",
"peity.js",
"raphael.js",
"echarts.js",
"vis.js",
"arbor.js",
"cubism.js",
"vega.js",
"envisionjs.js",
"rickshaw.js",
"flot.js",
"nvd3.js",
"trianglify.js",
"d4.js",
"epoch.js",
"c3.js",
"babylonjs.js",
"recharts.js",
"graphicsjs.js",
"mxgraph.js",
"amchart.js",
"anychart.js",
"plotly.js",
"highchart.js",
"handsontable.js",
"ace.js",
"codemirror.js",
"esprima.js",
"quill.js",
"pen.js",
"editor.js",
"epiceditor.js",
"jsoneditor.js",
"squire.js",
"tinymce.js",
"trix.js",
"trumbowyg.js",
"wysihtml5.js",
"popline.js",
"summernote.js",
"devdocs.js",
"dexy.js",
"docco.js",
"styledocco.js",
"ronn.js",
"dox.js",
"jsdox.js",
"esdoc.js",
"yuidoc.js",
"coddoc.js",
"sphinx.js",
"jsduck.js",
"codecrumbs.js",
"jbinary.js",
"diff2html.js",
"jspdf.js",
"underscore.js",
"lodash.js",
"sugar.js",
"ramda.js",
"mout.js",
"mesh.js",
"preludejs.js",
"rxjs.js",
"bacon.js",
"kefir.js",
"highland.js",
"mobx.js",
"mori.js",
"buckets.js",
"hashmap.js",
"moment.js",
"date.js",
"fecha.js",
"dayjs.js",
"voca.js",
"selecting.js",
"he.js",
"multiline.js",
"jsurl.js",
"plexis.js",
"odometer.js",
"localforage.js",
"jstorage.js",
"cookies.js",
"crumbsjs.js",
"randomcolor.js",
"color.js",
"colors.js",
"pleasejs.js",
"tinycolor.js",
"i18next.js",
"polyglot.js",
"babelfish.js",
"ttag.js",
"async.js",
"q.js",
"step.js",
"contra.js",
"bluebird.js",
"when.js",
"objecteventtarget.js",
"sporadic.js",
"director.js",
"pathjs.js",
"crossroads.js",
"navaid.js",
"dompurify.js",
"log.js",
"conzole.js",
"loglevel.js",
"minilog.js",
"storyboard.js",
"regex101.js",
"regexr.js",
"regexpbuilder.js",
"annyang.js",
"axios.js",
"bottleneck.js",
"amygdala.js",
"wretch.js",
"farfetch.js",
"tailor.js",
"convnetjs.js",
"dn2a.js",
"synapses.js",
"bowser.js",
"matcha.js",
"prismjs.js",
"nprogress.js",
"pace.js",
"topbar.js",
"nanobar.js",
"pageloadingeffects.js",
"spinkit.js",
"ladda.js",
"ajaxload.js",
"preloaders.js",
"cssload.js",
"validatr.js",
"formvalidation.js",
"fieldval.js",
"funval.js",
"mousetrap.js",
"keymaster.js",
"keypress.js",
"keyboardjs.js",
"jwerty.js",
"shepherd.js",
"tourist.js",
"pageguide.js",
"hopscotch.js",
"joyride.js",
"focusable.js",
"izitoast.js",
"messenger.js",
"noty.js",
"pnotify.js",
"toastr.js",
"notie.js",
"swiper.js",
"slick.js",
"slidesjs.js",
"flexslider.js",
"unslider.js",
"sly.js",
"vegas.js",
"sequence.js",
"strut.js",
"photoswipe.js",
"jcslider.js",
"slidr.js",
"flickity.js",
"jqrangeslider.js",
"nouislider.js",
"fancyinput.js",
"awesomplete.js",
"pikaday.js",
"fullcalendar.js",
"rome.js",
"datedropper.js",
"select2.js",
"chosen.js",
"dropzone.js",
"fileapi.js",
"plupload.js",
"form.js",
"countable.js",
"card.js",
"stretchy.js",
"analytics.js",
"tipsy.js",
"opentip.js",
"qtip2.js",
"tooltipster.js",
"simptip.js",
"toolbar.js",
"vex.js",
"sweetalert.js",
"colorbox.js",
"fancybox.js",
"swipebox.js",
"jbox.js",
"scrollmonitor.js",
"headroom.js",
"iscroll.js",
"skrollr.js",
"parallax.js",
"plax.js",
"jparallax.js",
"fullpage.js",
"scrollmenu.js",
"simpleparallax.js",
"slideout.js",
"jtable.js",
"datatables.js",
"tabulator.js",
"floatthead.js",
"masonry.js",
"packery.js",
"isotope.js",
"flexboxgrid.js",
"w2ui.js",
"fluidity.js",
"ink.js",
"dataformsjs.js",
"webplate.js",
"cerberus.js",
"touchemulator.js",
"dragula.js",
"leaflet.js",
"cesium.js",
"gmaps.js",
"polymaps.js",
"jqvmap.js",
"openlayers3.js",
"html5media.js",
"polyplayer.js",
"flowplayer.js",
"mediaelement.js",
"soundjs.js",
"clappr.js",
"exifr.js",
"bigtext.js",
"circletype.js",
"slabtext.js",
"velocity.js",
"transitionend.js",
"textillate.js",
"animatable.js",
"tsparticles.js",
"pica.js",
"cropper.js",
"es6features.js",
"gridsome.js",
"docusaurus.js",
"echo.js",
"picturefill.js",
"json3.js",
"mixitup.js",
"grid.js",
"ky.js",
"fcal.js",
"iooxa.js",
"idyll.js",
"primer.js",
"glue.js",
"postcss.js",
"mui.js",
"img2css.js",
"weui.js",
"csscss.js",
"simditor.js",
"htmlhint.js",
"csslint.js",
"grunt.js",
"yeoman.js",
"gulp.js",
"zrender.js",
"highcharts.js",
"tweenjs.js",
"swipe.js",
"superslides.js",
"slider.js",
"polymer.js",
"ionic.js",
"timelinejs.js",
"togetherjs.js",
"foundation.js",
"todomvc.js",
"vuejs.js",
"webuploader.js",
"fastclick.js",
"wangeditor.js",
"tooling.js",
"judge.js",
"amdoc.js",
"amazeui.js",
"zepto.js",
"nodeclub.js",
"nodeppt.js",
"hexo.js",
"koa.js",
"connect.js",
"nvm.js",
"flux.js",
"browserquest.js",
"html5shiv.js",
"ulkit.js",
"arttemplate.js",
"jade.js",
"modernizr.js",
"css3please.js",
"babel.js",
"f2etest.js",
"brackets.js",
"ueditor.js",
"electron.js",
"base.js",
"basscss.js",
"bootflat.js",
"bootswatch.js",
"bulma.js",
"cardinal.js",
"caramel.js",
"corpus.js",
"kube.js",
"materialize.js",
"milligram.js",
"papercss.js",
"papier.js",
"pavilion.js",
"picnicss.js",
"pure.js",
"skeleton.js",
"tachyons.js",
"tacit.js",
"uikit.js",
"wing.js",
"angular.js",
"choo.js",
"deku.js",
"displayjs.js",
"inferno.js",
"mercury.js",
"mithril.js",
"moon.js",
"skatejs.js",
"solid.js",
"bliss.js",
"cash.js",
"jquery.js",
"nanojs.js",
"selector.js",
"umbrella.js",
"zeptojs.js",
"chartist.js",
"charts.js",
"chartjs.js",
"dc.js",
"dimple.js",
"d3xter.js",
"f2.js",
"frappe.js",
"ggraph.js",
"jsplumb.js",
"metricsgraphics.js",
"morrisjs.js",
"muze.js",
"sparkline.js",
"sparky.js",
"taucharts.js",
"uvcharts.js",
"vivagraph.js",
"z3d.js",
"kartograph.js",
"mapsicon.js",
"osmbuildings.js",
"planetary.js",
"smallworld.js",
"tangram.js",
"topojson.js",
"turf.js",
"dynatables.js",
"listjs.js",
"sortable.js",
"tablesaw.js",
"flipside.js",
"nudge.js",
"glide.js",
"lory.js",
"siema.js",
"blotter.js",
"fitty.js",
"flowtype.js",
"lettering.js",
"shave.js",
"typeplate.js",
"fitvid.js",
"medialementjs.js",
"plyr.js",
"talkie.js",
"videojs.js",
"abcjs.js",
"audio5js.js",
"bap.js",
"blip.js",
"howler.js",
"soundcite.js",
"tonal.js",
"vexflow.js",
"easeljs.js",
"konva.js",
"panzoom.js",
"p5js.js",
"vizflow.js",
"zdog.js",
"scenejs.js",
"whitestormjs.js",
"camanjs.js",
"grafijs.js",
"smartcrop.js",
"basicscroll.js",
"moveto.js",
"scrollmagic.js",
"scrollreveal.js",
"verge.js",
"alloyfinger.js",
"anime.js",
"choreographer.js",
"gsap.js",
"impulse.js",
"mojs.js",
"popmotion.js",
"rebound.js",
"repaintless.js",
"shifty.js",
"snabbt.js",
"snapsvg.js",
"vivus.js",
"dotjs.js",
"handlebars.js",
"hogan.js",
"mustache.js",
"vdo.js",
"aja.js",
"fetch.js",
"qwest.js",
"reqwest.js",
"superagent.js",
"bean.js",
"eventemitter2.js",
"mitt.js",
"elegant.js",
"feather.js",
"flaticon.js",
"fontawesome.js",
"fontello.js",
"icomoon.js",
"ikonate.js",
"ionicons.js",
"octicons.js",
"weloveiconfonts.js",
"chromajs.js",
"coolors.js",
"colorbrewer2.js",
"colorhexa.js",
"colourco.js",
"colormind.js",
"kewler.js",
"khroma.js",
"polychrome.js",
"uigradients.js",
"forerunnerdb.js",
"lokijs.js",
"lovefield.js",
"pouchdb.js",
"rxdb.js",
"taffydb.js",
"zangodb.js",
"parsley.js",
"dateformat.js",
"flatpickr.js",
"instadate.js",
"luxon.js",
"tinytime.js",
"l10ns.js",
"globalize.js",
"datakit.js",
"datalib.js",
"gauss.js",
"jstat.js",
"statkit.js",
"stdlib.js",
"theoremjs.js",
"stealjs.js",
"aload.js",
"lazysizes.js",
"loadxt.js",
"unveil.js",
"brain.js",
"mind.js",
"neurojs.js",
"rrssb.js",
"sharingbuttons.js",
"socialcount.js",
"moutjs.js",
"ramdajs.js",
"formstone.js",
"tether.js",
"upup.js"
]
+2 -2
View File
@@ -274,8 +274,8 @@ Very warmly welcome all people to make OneForAll better together!
- [ ] Continuous optimize and improve of each module
- [x] Subdomain monitoring (mark newly discovered subdomain)
- [ ] Subdomain collection crawler (collect subdomains from static files such as JS)
- [ ] Implementation of front-end interface for powerful interaction (tentative: front-end: Element + back-end: Flask)
- [x] Subdomain collection crawler (collect subdomains from static files such as JS)
- [ ] Implementation of front-end interface for powerful interaction
For more details, read [todo.md](https://github.com/shmilylty/OneForAll/tree/master/docs/todo.md).
+1 -1
View File
@@ -31,7 +31,7 @@ class Collect(object):
# The crawl module has some problems
modules = ['certificates', 'check', 'datasets',
'dnsquery', 'intelligence', 'search']
# modules = ['datasets']
# modules = ['certificates']
for module in modules:
module_path = setting.module_dir.joinpath(module)
for path in module_path.rglob('*.py'):
+88 -47
View File
@@ -1,47 +1,39 @@
import re
import json
import time
from urllib import parse
from common import utils
from common import resolve
from common import request
from common.module import Module
from config import setting
from config.log import logger
class Finder(Module):
def __init__(self, domain):
def __init__(self):
Module.__init__(self)
self.module = 'Finder'
self.source = ''
self.domain = domain
self.ts = utils.get_timestring()
self.name = f'found_subdomains_{self.domain}_{self.ts}'
self.path = setting.temp_save_dir.joinpath(self.name)
self.start = time.time() # 模块开始执行时间
def save_subdomain(self, data, path):
if not path:
path = self.path
utils.save_data(path, data)
def remove_subdomain(self, path):
if not path:
path = self.path
utils.remove_data(path)
def find_url(self):
pass
def batch_find_url(self):
pass
def find_subdomain(self, html):
subdomains = self.match_subdomains(html, fuzzy=False)
self.subdomains.add(subdomains)
def find_js(self):
pass
def filter_js(self):
pass
def run(self, domain, data, port):
logger.log('INFOR', f'Start finder module')
existing_subdomains = set(map(lambda x: x.get('subdomain'), data)) # 已有的子域
found_subdomains = find_subdomains(domain, data)
new_subdomains = found_subdomains - existing_subdomains
if not len(new_subdomains): # 未发现新的子域就直接返回
return data
self.subdomains = new_subdomains
self.gen_result()
temp_data = resolve.run_resolve(domain, self.results)
fina_data = request.run_request(domain, temp_data, port)
data = data + fina_data
self.finish()
logger.log('INFOR', f'Saving finder results')
utils.save_db(domain, data, 'finder')
return data
# Regular expression comes from https://github.com/GerbenJavado/LinkFinder
@@ -104,29 +96,78 @@ def process_url(req_url, rel_url):
return result
def filter_url(urs):
pass
def filter_name(path, black_name):
for name in black_name:
if path.endswith(name):
return True
black_ext = ['io.js', 'ui.js', 'fp.js', 'en.js', 'dev.js', 'min.js', 'umd.js',
'esm.js', 'all.js', 'cjs.js', 'prod.js', 'slim.js', 'core.js',
'global.js', 'bundle.js', 'browser.js', 'brands.js', 'simple.js',
'common.js', 'development.js', 'production.js']
for ext in black_ext:
if path.endswith(ext):
return True
r = re.compile(r'\d+.\d+.\d+')
if r.search(path):
return True
return False
def run_finder(domain, data):
existing_subdomains = set(map(lambda x: x.get('subdomain'), data)) # 已有的子域
found_subdomains = set()
found_urls = set()
finder = Finder(domain)
def filter_url(domain, url, black_name):
raw_url = parse.urlparse(url)
scheme = raw_url.scheme.lower()
if not scheme:
return True
if scheme not in ['http', 'https']:
return True
netloc = raw_url.netloc.lower()
if not netloc:
return True
if not netloc.endswith(domain):
return True
path = raw_url.path.lower()
if not path:
return True
if not path.endswith('.js'):
return True
if path.endswith('min.js'):
return True
return filter_name(path, black_name)
def get_black_name():
path = setting.data_storage_dir.joinpath('common_js_library.json')
with open(path) as fp:
return json.load(fp)
def match_subdomains(domain, text):
subdomains = utils.match_subdomains(domain, text)
logger.log('DEBUG', f'matched subdomains: {subdomains}')
return subdomains
def find_subdomains(domain, data):
subdomains = set()
js_urls = set()
black_name = get_black_name()
for item in data:
req_url = item.get('url')
rsp_html = item.get('response')
found_subdomains.add(finder.match_subdomains(rsp_html))
if not rsp_html:
continue
logger.log('DEBUG', f'matching subdomains from response of {req_url}')
subdomains = subdomains.union(match_subdomains(domain, rsp_html))
urls = find_url(rsp_html)
if not urls:
continue
for rel_url in urls:
found_url = process_url(req_url, rel_url)
found_urls.add(found_url)
resp_data = request.urls_request(found_urls)
new_subdomains = found_subdomains - existing_subdomains
def save_db(domain, data):
pass
url = process_url(req_url, rel_url)
if not filter_url(domain, url, black_name):
js_urls.add(url)
resp_data = request.urls_request(js_urls)
for resp, text in resp_data:
if text:
logger.log('DEBUG', f'matching subdomains from response of {resp.url}')
subdomains = subdomains.union(match_subdomains(domain, text))
return subdomains
+6
View File
@@ -17,6 +17,7 @@ from brute import Brute
from common import utils, resolve, request
from common.database import Database
from modules.collect import Collect
from modules.finder import Finder
from config import setting
from config.log import logger
from takeover import Takeover
@@ -209,6 +210,11 @@ class OneForAll(object):
# Save HTTP request result
request.save_db(self.domain, self.data)
# Finder module
if setting.enable_finder_module:
finder = Finder()
self.data = finder.run(self.domain, self.data, self.port)
# Add the final result list to the total data list
self.datas.extend(self.data)