Skip to content

Commit 9b6640b

Browse files
authored
Merge pull request #137 from TophantTechnology/update/2.3.1
Update/2.3.1
2 parents cc4fe1c + b72366a commit 9b6640b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+198
-61
lines changed

app/dicts/altdnsdict.txt

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ region
8383
reset
8484
s3
8585
sandbox
86+
scan
8687
scm
8788
search
8889
secure

app/dicts/blackdomain.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@
2323
.book.4.qq.com
2424
.o.tencent.com
2525
.o.qcloud.com
26-
.mur.qq.com
26+
.mur.qq.com
27+
.waf.taobao.com

app/dicts/domain_dict_test.txt

+1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ blog
44
service
55
mi
66
ebank
7+
active
78
un

app/modules/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class CollectSource:
2626
SITESPIDER = "site_spider"
2727
SEARCHENGINE = "search_engine"
2828
MONITOR = "monitor"
29+
CRTSH = "crtsh"
2930

3031
class TaskStatus:
3132
WAITING = "waiting"

app/routes/export.py

+26-5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import re
88
from collections import Counter
99
from openpyxl.writer.excel import save_virtual_workbook
10+
from openpyxl.styles import Font, Color
1011
from app.utils import get_logger, auth
1112
from app import utils
1213
from urllib.parse import quote
@@ -149,22 +150,34 @@ def __init__(self, task_id):
149150
self.wb = Workbook()
150151
self.is_ip_task = False
151152

153+
def set_style(self, ws):
154+
font = Font(name="Consolas", color="111111")
155+
column = "ABCDEFGHIJKLMNO"
156+
for x in column:
157+
for y in range(1, 256):
158+
ws["{}{}".format(x,y)].font = font
159+
152160
def build_service_xl(self):
153161
ws = self.wb.create_sheet(title="系统服务")
154162
ws.column_dimensions['A'].width = 22.0
155-
ws.column_dimensions['B'].width = 20.0
156-
ws.column_dimensions['C'].width = 40.0
157-
column_tilte = ["IP端口", "服务", "产品", "版本"]
163+
ws.column_dimensions['B'].width = 10.0
164+
ws.column_dimensions['C'].width = 20.0
165+
ws.column_dimensions['D'].width = 40.0
166+
167+
column_tilte = ["IP", "端口","服务", "产品", "版本"]
158168
ws.append(column_tilte)
159169
for item in get_ip_data(self.task_id):
160170
for port_info in item["port_info"]:
161171
row = []
162-
row.append("{}:{}".format(item["ip"], port_info["port_id"]))
172+
row.append(item["ip"])
173+
row.append("{}".format(port_info["port_id"]))
163174
row.append(port_info["service_name"])
164175
row.append(port_info.get("product", ""))
165176
row.append(port_info.get("version", ""))
166177
ws.append(row)
167178

179+
self.set_style(ws)
180+
168181
def build_ip_xl(self):
169182
ws = self.wb.create_sheet(title="IP")
170183
ws.column_dimensions['A'].width = 22.0
@@ -227,6 +240,8 @@ def build_ip_xl(self):
227240
row.append(osname)
228241
ws.append(row)
229242

243+
self.set_style(ws)
244+
230245
def ignore_illegal(self, content):
231246
ILLEGAL_CHARACTERS_RE = re.compile(r'[\000-\010]|[\013-\014]|[\016-\037]')
232247
content = ILLEGAL_CHARACTERS_RE.sub(r'', content)
@@ -251,6 +266,8 @@ def build_site_xl(self):
251266
row.append(item["favicon"].get("hash", ""))
252267
ws.append(row)
253268

269+
self.set_style(ws)
270+
254271
def build_domain_xl(self):
255272
ws = self.wb.create_sheet(title="域名")
256273
ws.column_dimensions['A'].width = 30.0
@@ -269,6 +286,8 @@ def build_domain_xl(self):
269286
row.append(" \r\n".join(item["ips"]))
270287
ws.append(row)
271288

289+
self.set_style(ws)
290+
272291
def build_statist(self):
273292
statist = port_service_product_statist(self.task_id)
274293
ws = self.wb.create_sheet(title="资产统计")
@@ -334,6 +353,7 @@ def build_statist(self):
334353
ws["K27"] = "产品类别总数"
335354
ws["K28"] = product_total
336355

356+
self.set_style(ws)
337357

338358
def run(self):
339359
task_data = get_task_data(self.task_id)
@@ -356,7 +376,8 @@ def run(self):
356376

357377
return save_virtual_workbook(self.wb)
358378

379+
359380
def export_arl(task_id):
360381
task_id = task_id.strip()
361382
save = SaveTask(task_id)
362-
return save.run()
383+
return save.run()

app/routes/policy.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ def get(self):
3939
"domain_brute_type": fields.String(description="域名爆破类型(big)", example="big"),
4040
"alt_dns": fields.Boolean(description="DNS字典智能生成", default=True),
4141
"riskiq_search": fields.Boolean(description="RiskIQ 调用", default=True),
42-
"arl_search": fields.Boolean(description="ARL 历史查询", default=True)
42+
"arl_search": fields.Boolean(description="ARL 历史查询", default=True),
43+
"crtsh_search": fields.Boolean(description="crtsh 查询", default=True)
4344
})
4445

4546
'''IP 相关配置选项'''

app/routes/task.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@
3535
'options.search_engines': fields.Boolean(description="是否开启搜索引擎调用"),
3636
'options.site_spider': fields.Boolean(description="是否开启站点爬虫"),
3737
'options.riskiq_search': fields.Boolean(description="是否开启 Riskiq 调用"),
38-
'options.arl_search': fields.Boolean(description="是否开启 ARL 历史查询")
38+
'options.arl_search': fields.Boolean(description="是否开启 ARL 历史查询"),
39+
'options.crtsh_search': fields.Boolean(description="是否开启 crt.sh 查询")
3940

4041
}
4142

@@ -65,7 +66,8 @@
6566
"ssl_cert": fields.Boolean(),
6667
"fetch_api_path": fields.Boolean(),
6768
"fofa_search": fields.Boolean(),
68-
"sub_takeover": fields.Boolean()
69+
"sub_takeover": fields.Boolean(),
70+
"crtsh_search": fields.Boolean(example=True, default=True)
6971
})
7072

7173

app/routes/vuln.py

+5-7
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,11 @@
77
logger = get_logger()
88

99
base_search_fields = {
10-
'fld': fields.String(required=False, description="IP"),
11-
'site': fields.String(description="域名"),
12-
'url': fields.String(required=False, description="URL"),
13-
'content_length': fields.Integer(description="body 长度"),
14-
'status_code': fields.Integer(description="状态码"),
15-
'title': fields.String(description="标题"),
16-
'source': fields.String(description="来源"),
10+
'plg_name': fields.String(required=False, description="plugin ID"),
11+
'plg_type': fields.String(description="类别"),
12+
'vul_name': fields.String(description="漏洞名称"),
13+
'app_name': fields.String(description="应用名"),
14+
'target': fields.String(description="目标"),
1715
"task_id": fields.String(description="任务ID")
1816
}
1917

app/services/__init__.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@
1818
from .pageFetch import page_fetch
1919
from .webAppIdentify import web_app_identify
2020
from .syncAsset import sync_asset
21-
from .npoc import run_risk_cruising, run_sniffer
21+
from .npoc import run_risk_cruising, run_sniffer
22+
from .crtshClient import crtsh_search

app/services/baseThread.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def _run(self):
4242
target = target.strip()
4343

4444
cnt += 1
45-
logger.info("[{}/{}] work on {}".format(cnt, len(self.targets), target))
45+
logger.debug("[{}/{}] work on {}".format(cnt, len(self.targets), target))
4646

4747
if not target:
4848
continue

app/services/crtshClient.py

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from app import utils
2+
logger = utils.get_logger()
3+
4+
5+
class CrtshClient:
6+
def __init__(self):
7+
self.url = "https://crt.sh/"
8+
9+
def search(self, domain):
10+
param = {
11+
"output": "json",
12+
"q": domain
13+
}
14+
15+
data = utils.http_req(self.url, 'get', params=param, timeout=(30.1, 50.1)).json()
16+
return data
17+
18+
19+
def crtsh_search(domain):
20+
name_list = []
21+
try:
22+
c = CrtshClient()
23+
items = c.search(domain)
24+
for item in items:
25+
for name in item["name_value"].split():
26+
name = name.strip()
27+
name = name.strip("*.")
28+
name = name.lower()
29+
if name.endswith("."+domain):
30+
name_list.append(name)
31+
32+
name_list = list(set(name_list))
33+
logger.info("search crtsh {} {}".format(domain, len(name_list)))
34+
35+
except Exception as e:
36+
logger.exception(e)
37+
38+
return name_list
39+

app/services/fetchSite.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import time
22
from pyquery import PyQuery as pq
33
import binascii
4-
from urllib.parse import urljoin
4+
from urllib.parse import urljoin, urlparse
55
from urllib3.util.url import get_host
66
import mmh3
77
from app import utils
@@ -44,6 +44,10 @@ def work(self, site):
4444
if conn.status_code == 301 or conn.status_code == 302:
4545
url_302 = urljoin(site, conn.headers.get("Location", ""))
4646
if url_302 != site and url_302.startswith(site):
47+
site_path = urlparse(site).path.strip("/")
48+
url_302_path = urlparse(url_302).path
49+
if len(site_path) > 5 and url_302_path.endswith(site_path):
50+
return
4751
self.work(url_302)
4852

4953
def run(self):

app/services/fileLeak.py

-5
Original file line numberDiff line numberDiff line change
@@ -364,11 +364,6 @@ def check_page_200(self):
364364
page_404 = Page(self.http_req(url_404))
365365
self.page404_set.add(page_404)
366366

367-
if page_404.is_302():
368-
self.location_404_url.add(page_404.location_url)
369-
if page.location_url in self.location_404_url:
370-
self.page404_set.add(page)
371-
372367
if page_404.is_302() and page_404.location_url.endswith(page_404.url.payload + "/"):
373368
self.page404_set.add(page)
374369
self.skip_302 = True

app/services/npoc.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,18 @@ def run_risk_cruising(plugins, targets):
183183
def run_sniffer(targets):
184184
n = NPoC(concurrency=15, tmp_dir=Config.TMP_PATH)
185185
x = n.plugin_name_list
186-
items = n.run_poc(n.sniffer_plugin_name_set, targets)
186+
new_targets = []
187+
188+
##跳过80 和 443 的识别
189+
for t in targets:
190+
t = t.strip()
191+
if t.endswith(":80"):
192+
continue
193+
if t.endswith(":443"):
194+
continue
195+
new_targets.append(t)
196+
197+
items = n.run_poc(n.sniffer_plugin_name_set, new_targets)
187198
ret = []
188199
for x in items:
189200
target = x["verify_data"]

app/services/webAnalyze.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def work(self, site):
1919
Config.DRIVER_JS ,
2020
site
2121
]
22-
logger.info("WebAnalyze=> {}".format(" ".join(cmd_parameters)))
22+
logger.debug("WebAnalyze=> {}".format(" ".join(cmd_parameters)))
2323

2424
output = utils.check_output(cmd_parameters, timeout=20)
2525
output = output.decode('utf-8')

app/tasks/domain.py

+47-2
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,9 @@ def __init__(self, base_domain = None, task_id = None, options = None):
467467
#用来区分是正常任务还是监控任务
468468
self.task_tag = "task"
469469

470+
#用来存放泛解析域名映射的IP
471+
self._not_found_domain_ips = None
472+
470473
self.npoc_service_target_set = set()
471474

472475
scan_port_map = {
@@ -483,6 +486,17 @@ def __init__(self, base_domain = None, task_id = None, options = None):
483486
}
484487
self.scan_port_option = scan_port_option
485488

489+
@property
490+
def not_found_domain_ips(self):
491+
if self._not_found_domain_ips is None:
492+
fake_domain = "at"+utils.random_choices(4) + "." + self.base_domain
493+
self._not_found_domain_ips = utils.get_ip(fake_domain)
494+
495+
if self._not_found_domain_ips:
496+
logger.info("not_found_domain_ips {} {}".format(fake_domain, self._not_found_domain_ips))
497+
498+
return self._not_found_domain_ips
499+
486500
def save_domain_info_list(self, domain_info_list, source = CollectSource.DOMAIN_BRUTE):
487501
for domain_info_obj in domain_info_list:
488502
domain_info = domain_info_obj.dump_json(flag=False)
@@ -515,6 +529,13 @@ def clear_domain_info_by_record(self, domain_info_list):
515529
continue
516530

517531
record = info.record_list[0]
532+
533+
ip = info.ip_list[0]
534+
535+
# 解决泛解析域名问题,果断剔除
536+
if ip in self.not_found_domain_ips:
537+
continue
538+
518539
cnt = self.record_map.get(record, 0)
519540
cnt += 1
520541
self.record_map[record] = cnt
@@ -554,6 +575,20 @@ def arl_search(self):
554575
logger.info("end arl fetch {} {} elapse {}".format(
555576
self.base_domain, len(domain_info_list), elapse))
556577

578+
def crtsh_search(self):
579+
t1 = time.time()
580+
logger.info("start crtsh search {}".format(self.base_domain))
581+
crtsh_domains = services.crtsh_search(self.base_domain)
582+
domain_info_list = self.build_domain_info(crtsh_domains)
583+
if self.task_tag == "task":
584+
domain_info_list = self.clear_domain_info_by_record(domain_info_list)
585+
self.save_domain_info_list(domain_info_list, source=CollectSource.CRTSH)
586+
587+
self.domain_info_list.extend(domain_info_list)
588+
elapse = time.time() - t1
589+
logger.info("end crtsh search {} {} elapse {}".format(
590+
self.base_domain, len(domain_info_list), elapse))
591+
557592
def build_domain_info(self, domains):
558593
"""
559594
构建domain_info_list 带去重功能
@@ -900,14 +935,22 @@ def domain_fetch(self):
900935
self.domain_info_list.append(domain_info)
901936
self.save_domain_info_list([domain_info])
902937

903-
'''***RiskIQ查询****'''
938+
# ***RiskIQ查询****
904939
if self.options.get("riskiq_search") and services.riskiq_quota() > 0:
905940
self.update_task_field("status", "riskiq_search")
906941
t1 = time.time()
907942
self.riskiq_search()
908943
elapse = time.time() - t1
909944
self.update_services("riskiq_search", elapse)
910945

946+
# crt.sh 网站查询
947+
if self.options.get("crtsh_search"):
948+
self.update_task_field("status", "crtsh_search")
949+
t1 = time.time()
950+
self.crtsh_search()
951+
elapse = time.time() - t1
952+
self.update_services("crtsh_search", elapse)
953+
911954
if self.options.get("arl_search"):
912955
self.update_task_field("status", "arl_search")
913956
t1 = time.time()
@@ -1084,6 +1127,7 @@ def brute_config(self):
10841127
item["save_date"] = utils.curr_date()
10851128
utils.conn_db('vuln').insert_one(item)
10861129

1130+
10871131
def run(self):
10881132

10891133
self.update_task_field("start_time", utils.curr_date())
@@ -1133,7 +1177,8 @@ def add_domain_to_scope(domain, scope_id):
11331177
'site_spider': False,
11341178
'search_engines': False,
11351179
'ssl_cert': False,
1136-
'fofa_search': False
1180+
'fofa_search': False,
1181+
'crtsh_search': True
11371182
}
11381183
}
11391184

0 commit comments

Comments
 (0)