Skip to content

Commit 8d79061

Browse files
author
Mohamed Elbadry
committed
Merge branch 'test'
2 parents fcbcde7 + 94a1dfe commit 8d79061

File tree

8 files changed

+100
-31
lines changed

8 files changed

+100
-31
lines changed

Dockerfile

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ RUN pip3 install -r requirements.txt
88
RUN go get -u github.com/melbadry9/subover
99
RUN go get -u github.com/OJ/gobuster
1010
RUN go get -u github.com/tomnomnom/assetfinder
11+
RUN go get -u github.com/tomnomnom/httprobe
1112
ENV GOROOT=/root/go GOPATH=/go PATH=/root/go/bin:$PATH
12-
RUN wget wget https://github.com/OWASP/Amass/releases/download/v3.1.10/amass_v3.1.10_linux_amd64.zip;
13+
RUN wget https://github.com/OWASP/Amass/releases/download/v3.1.10/amass_v3.1.10_linux_amd64.zip
1314
RUN unzip -j amass_v3.1.10_linux_amd64.zip amass_v3.1.10_linux_amd64/amass -d ${GOROOT}/bin/
1415
CMD ["gunicorn", "-b", "0.0.0.0:8000", "app:Scan"]

README.md

+30-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# ScanApi ![Python 3.5](https://img.shields.io/badge/Python-3.x-blue.svg) ![linux 64-bit](https://img.shields.io/badge/Linux-64bit-blue.svg)
22

3-
Subdomains-enumeration and subdomain-takeover monitoring api.
3+
Subdomains-enumeration, subdomain-takeover monitoring api and S3 bucket scanner.
44

55
## Installing
66

@@ -20,31 +20,50 @@ docker build -t scanapi:latest .
2020
docker run -d -p 8000:8000 scanapi
2121
```
2222

23-
- Add slack hook in `config.ini`
23+
- Update `config.ini` before building docker image.
2424

25-
- For custom options edit `config.ini`
25+
- Add slack hook in `config.ini` if Slack is Enabled.
2626

27-
## Running
27+
- Commit docker image `docker commit <container id> scanapi:latest` to avoid losing data from db.
2828

29-
- Open `http://127.0.0.1:8000/enum/domain/example.com/` in your browser.
30-
- Get Result `http://127.0.0.1:8000/db/domain/example.com/`.
31-
- S3 Scanner `http://127.0.0.1:8000/enum/s3/bucket-name/`
32-
- S3 Result `http://127.0.0.1:8000/db/s3/bucket-name/`
29+
## Endpoints
30+
31+
1. `/enum/domain/<domain>/`
32+
- Start subdomain enumeration task in background then update db
33+
- Domain ex: `example.com`
34+
35+
2. `/enum/s3/<bucket-name>/`
36+
- Start s3 bucket permissions scanner and update db
37+
- Bucket-name ex: `example-prod`
38+
39+
3. `/db/domain/<domain>/`
40+
- Retrieve all subdomains from db if any exist
41+
42+
4. `/db/domain/<domain>/?pro=http`
43+
- Retrieve subdomains with port 80 opened from db if any exist
44+
45+
5. `/db/domain/<domain>/?pro=https`
46+
- Retrieve subdomains with port 443 opened from db if any exist
47+
48+
6. `/db/s3/<bucket-name>/`
49+
- Retrieve s3 bucket scanner data from db if any exist
3350

3451
## Supported Tools
3552

3653
- [Amass](https://github.com/OWASP/Amass)
3754
- [Gasset](https://github.com/melbadry9/gasset)
3855
- [Subover](https://github.com/melbadry9/SubOver)
3956
- [Sublist3r](https://github.com/melbadry9/Sublist3r)
57+
- [Httprobe](https://github.com/tomnomnom/httprobe)
4058
- [Gobuster](https://github.com/OJ/gobuster)
4159
- [Assetfinder](https://github.com/tomnomnom/assetfinder)
4260

4361
## To-Do list
4462

45-
- Add directory brute forcing monitoring.
46-
- Add open ports monitoring.
47-
- Add scheduling jobs.
63+
- [ ] Add directory brute forcing monitoring
64+
- [ ] Add open ports monitoring
65+
- [ ] Add scheduling jobs
66+
- [ ] Add UI
4867

4968
## Donation
5069

app.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import json
22
import multiprocessing
3-
from flask import Flask, jsonify, render_template, Response
3+
from flask import Flask, jsonify, render_template, Response, request
44

55
import lib.core.log_handler
66
from lib.core.config import config
@@ -30,7 +30,8 @@ def S3_check(bucket):
3030

3131
@Scan.route("/db/domain/<domain>/")
3232
def Subdomain_from_db(domain):
33-
return Response(get_subdomains(domain),200,mimetype="text/plain")
33+
protocol = request.args.get("pro") or ""
34+
return Response(get_subdomains(domain, protocol),200,mimetype="text/plain")
3435

3536
@Scan.route("/db/s3/<bucket>/")
3637
def s3_from_db(bucket):

config.ini

+5-2
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,23 @@ debug = False
55
secret = anything_12456547_1524556
66

77
[SLACK]
8-
enabled = False
98
hook =
9+
enabled = False
10+
1011

1112
[COOKIE]
1213
# gasset cookie to enable censys and virustotal
1314
fb_cookie =
1415

1516
[GENERAL]
16-
threads = 20
17+
threads = 30
1718
resolver = 8.8.8.8
1819

1920
[TOOLS]
2021
amass = True
2122
gasset = True
2223
subover = True
24+
httprobe = True
2325
gobuster = True
2426
sublist3r = True
2527
assetfinder = True
@@ -45,5 +47,6 @@ s3transfer = False
4547
file_path = app.log
4648

4749
[aws]
50+
# aws keys
4851
id =
4952
secret =

install.sh

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export PATH=$PATH:$GOROOT/bin:$GOPATH/bin;
77
go get -u github.com/melbadry9/subover;
88
go get -u github.com/OJ/gobuster;
99
go get -u github.com/tomnomnom/assetfinder;
10+
go get -u github.com/tomnomnom/httprobe;
1011
wget https://github.com/OWASP/Amass/releases/download/v3.1.10/amass_v3.1.10_linux_amd64.zip;
1112
unzip amass_v3.1.10_linux_amd64.zip;
1213
cp amass_v3.1.10_linux_amd64/amass $GOPATH/bin/;

lib/core/database.py

+17-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def __del__(self):
7575

7676
def create_db(self):
7777
with self.lock:
78-
self.cdb.executescript("""CREATE TABLE IF NOT EXISTS "domains" ( `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, `main_domain` TEXT NOT NULL , `sub_domain` TEXT )""")
78+
self.cdb.executescript("""CREATE TABLE IF NOT EXISTS "domains" ( `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, `main_domain` TEXT NOT NULL, `sub_domain` TEXT, `http` INTEGER NOT NULL DEFAULT 0, `https` INTEGER NOT NULL DEFAULT 0 )""")
7979
self.db.commit()
8080

8181
def insert_domains(self, sub_domain:list):
@@ -89,5 +89,21 @@ def read_domains(self):
8989
self.cdb.execute("select sub_domain from domains where main_domain = ?",(self.domain,))
9090
return [i[0] for i in self.cdb.fetchall()]
9191

92+
def update_protocol(self, protocol:str, sub_domain:list):
93+
with self.lock:
94+
for item in sub_domain:
95+
if protocol == "http":
96+
self.cdb.execute("update domains set http = 1 where sub_domain = ?",(item,))
97+
elif protocol == "https":
98+
self.cdb.execute("update domains set https = 1 where sub_domain = ?",(item,))
99+
self.db.commit()
100+
101+
def read_domains_protocol(self, protocol:str):
102+
if protocol == "http":
103+
self.cdb.execute("select sub_domain from domains where main_domain = ? and http=1",(self.domain,))
104+
elif protocol == "https":
105+
self.cdb.execute("select sub_domain from domains where main_domain = ? and https=1",(self.domain,))
106+
return [i[0] for i in self.cdb.fetchall()]
107+
92108
def new_domains(self):
93109
return list(set(self.read_domains()) - set(self.old_sub))

lib/core/opp.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,11 @@ def __init__(self, domain):
6464
ProcessBase.__init__(self)
6565
self.name = "GoBusterDNS"
6666
self.command = "gobuster dns -z -q -d {0} -r {1} -w {2} -t {3}".format(domain, config['GENERAL']['resolver'], DNS_LIST, self.threads)
67-
self.pattern = r"Found: (.+)\n"
67+
self.pattern = r"Found: (.+)\n"
68+
69+
class Httprobe(ProcessBase):
70+
def __init__(self, file):
71+
ProcessBase.__init__(self)
72+
self.name = "Httprobe"
73+
self.command = "cat {0} | httprobe -c {1}".format(file, self.threads)
74+
self.pattern = r"(.+)\n"

lib/scan/subdomain_job.py

+34-13
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
from ..core.database import SubDomainData
99
from ..core.log_handler import scan_logger
1010
from ..thirdparty.Gasset.asset import main as Gasset
11-
from ..core.opp import SubOver, GoBuster, AssetFinder, Amass, GoBusterDNS
1211
from ..thirdparty.Sublist3r.sublist3r import main as Sublist3r
12+
from ..core.opp import SubOver, GoBuster, AssetFinder, Amass, GoBusterDNS, Httprobe
1313

1414

1515
def sub_job(domain):
@@ -78,15 +78,15 @@ def sub_job(domain):
7878
# All Subdomains
7979
final_list = clean(set(final_list))
8080
meta_data['count'] = len(final_list)
81-
82-
# SubOver
83-
if config['TOOLS'].getboolean('subover'):
8481

85-
# Temp file
86-
temp_file = tempfile.NamedTemporaryFile("w+t", encoding="utf-8")
87-
for dom in final_list:
88-
temp_file.writelines(dom + "\n")
82+
# Temp file
83+
temp_file = tempfile.NamedTemporaryFile("w+t", encoding="utf-8", delete=False)
84+
for item in final_list:
85+
temp_file.writelines(item + "\n")
86+
temp_file.seek(0)
8987

88+
# SubOver
89+
if config['TOOLS'].getboolean('subover'):
9090
try:
9191
pro_subover = SubOver(temp_file.name)
9292
data = pro_subover.exec_command()
@@ -98,15 +98,31 @@ def sub_job(domain):
9898
error_msg = "SubOver: " + str(e)
9999
scan_logger.error(error_msg, exc_info=True)
100100
final_error.append(error_msg)
101-
101+
102102
DB.insert_domains(final_list)
103103
new_subs = DB.new_domains()
104104

105-
# Bypass first run
105+
# Httprobe
106+
if config['TOOLS'].getboolean('httprobe'):
107+
try:
108+
http_probe = Httprobe(temp_file.name)
109+
data = http_probe.exec_command()
110+
alive_data = data['Httprobe']['data']
111+
https_domain = [dom.replace("https://","") for dom in alive_data if dom.startswith("https://")]
112+
http_domain = [dom.replace("http://","") for dom in alive_data if dom.startswith("http://")]
113+
DB.update_protocol("http", http_domain)
114+
DB.update_protocol("https", https_domain)
115+
except Exception as e:
116+
error_msg = "Httprobe: " + str(e)
117+
scan_logger.error(error_msg, exc_info=True)
118+
final_error.append(error_msg)
119+
120+
# Bypass first run and avoid huge host on slack webhook
106121
if not len(new_subs) == len(final_list):
107122
if not len(new_subs) == 0:
108123
meta_data['new_count'] = len(new_subs)
109-
meta_data['subdomains'] = new_subs
124+
if not len(new_subs) > 200:
125+
meta_data['subdomains'] = new_subs
110126

111127
# Add Errors
112128
if len(set(final_error) - {""}) > 0:
@@ -120,7 +136,12 @@ def sub_job(domain):
120136
scan_logger.info(json.dumps(meta_data, indent=4))
121137
return meta_data
122138

123-
def get_subdomains(domain):
139+
def get_subdomains(domain, protocol):
124140
DB = SubDomainData(domain)
125-
subs = DB.read_domains()
141+
if protocol == "http":
142+
subs = DB.read_domains_protocol("http")
143+
elif protocol == "https":
144+
subs = DB.read_domains_protocol("https")
145+
else:
146+
subs = DB.read_domains()
126147
return '\n'.join(subs)

0 commit comments

Comments
 (0)