Knockpy is a portable and modular python3 tool designed to quickly enumerate subdomains on a target domain through passive reconnaissance and dictionary scan.
python3 knockpy.py domain.com
git clone https://github.com/guelfoweb/knock.git
cd knock
pip3 install -r requirements.txt
python3 knockpy.py <DOMAIN>
git clone https://github.com/guelfoweb/knock.git
cd knock
python3 setup.py install
knockpy <DOMAIN>
Knockpy image hosted at DockerHub Page and automatically updated with RAUDI
docker run -it --rm secsi/knockpy <domain>
usage: knockpy [-h] [-v] [--no-local] [--no-remote] [--no-scan] [--no-http]
[--no-http-code CODE [CODE ...]] [--dns DNS] [-w WORDLIST]
[-o FOLDER] [-t SEC] [-th NUM] [--silent [{False,json,json-pretty,csv}]]
domain
--------------------------------------------------------------------------------
* SCAN
full scan: knockpy domain.com
quick scan: knockpy domain.com --no-local
faster scan: knockpy domain.com --no-local --no-http
ignore code: knockpy domain.com --no-http-code 404 500 530
silent mode: knockpy domain.com --silent
* SUBDOMAINS
show recon: knockpy domain.com --no-local --no-scan
* REPORT
show report: knockpy --report knockpy_report/domain.com_yyyy_mm_dd_hh_mm_ss.json
plot report: knockpy --plot knockpy_report/domain.com_yyyy_mm_dd_hh_mm_ss.json
csv report: knockpy --csv knockpy_report/domain.com_yyyy_mm_dd_hh_mm_ss.json
--------------------------------------------------------------------------------
positional arguments:
domain target to scan
optional arguments:
-h, --help show this help message and exit
-v, --version show program's version number and exit
--no-local local wordlist ignore
--no-remote remote wordlist ignore
--no-scan scanning ignore, show wordlist and exit
--no-http http requests ignore
--no-http-code CODE [CODE ...]
http code list to ignore
--dns DNS use custom DNS ex. 8.8.8.8
-w WORDLIST wordlist file to import
-o FOLDER report folder to store json results
-t SEC timeout in seconds
-th NUM threads num
--silent [{False,json,json-pretty,csv}]
silent or quiet mode, default: False
$ knockpy domain.com
- Scan type: dns + http(s) requests
- Wordlist: local + remote
Knockpy uses by default a internal file wordlist.txt and a remote list obtained by scanning other sources (passive recon) through plugins. To use a custom dictionary you can use the -w
option and specify the path to your local dictionary. Also, you can write a new plugin to populate the wordlist with subdomains obtained from external services. Take a look at the ones in the remote folder and use them as an example. Remember that some plugins, like Virustotal or Shodan, need apikey to work.
The domain target can be passed via STDIN.
echo "domain.com" | knockpy
To ignore http(s) responses with specific code, you can use the --no-http-code
followed by the code list 404 500 530
. With the --no-ip
option you can ignore ip list 192.168.1.100 192.168.101 192.168.1.102
$ knockpy domain.com --no-local
- Scan type: dns + http(s) requests
- Wordlist: remote
Only test subdomains obtained through passive reconnaissance using plugins. This scanning mode will be faster because it excludes the local dictionary.
$ knockpy domain.com --no-scan --no-local
- Scan type: none
- Wordlist: remote list
Print passive-only wordlist and exit. No scan will be performed.
$ knockpy domain.com --dns 8.8.8.8
By default it uses the pre-configured DNS on your system (ex. /etc/resolv.conf
).
$ knockpy domain.com --silent
Hide terminal output and save json report in the output folder. Using --silent
with the --no-scan
option hides the banner and shows the list of subdomains to the terminal.
$ knockpy domain.com --silent json
Hide terminal output and print final results in json format.
$ knockpy domain.com --silent json-pretty
Hide terminal output and print final results in intented json.
$ knockpy domain.com --silent csv
Hide terminal output and print final results in csv format.
Note that at each scan the report will be automatically saved.
$ knockpy domain.com -o /path/to/new/folder
All scans are saved in the default folder knockpy_report
. Alternatively, you can use the -o /path/folder
to define the new folder path or disable autosave using -o false
.
At each scan the report will be automatically saved in json format inside the file with the name domain.com_yyyy_mm_dd_hh_mm_ss.json
. If you don't like autosave you can disable using -o false
.
Report example domain.com_yyyy_mm_dd_hh_mm_ss.json
:
{
"sub-1.domain.com": {
"domain": "host.domain.ext",
"alias": ["sub-1.domain.com"],
"ipaddr": [
"123.123.123.123"
],
"code": 200,
"server": "Microsoft-IIS/8.5"
},
...................................
-- cut --
...................................
"sub-n.domain.com"{
"domain": "",
"alias": [],
"ipaddr": [
"123.123.123.124"
],
"code": 500,
"server": "nginx/1.15.6 "
},
"_meta": {
"name": "knockpy",
"version": "5.4.1",
"time_start": 1616353591.2510355,
"time_end": 1616353930.6632543,
"domain": "domain.com",
"wordlist": 2120
}
}
_meta
is a reserved key that contains the basic information of the scan.
$ knockpy --report knockpy_report/domain.com_yyyy_mm_dd_hh_mm_ss.json
Print the report in the terminal in a human format.
$ knockpy --csv knockpy_report/domain.com_yyyy_mm_dd_hh_mm_ss.json
Save the existing report in csv file.
$ knockpy --plot knockpy_report/domain.com_yyyy_mm_dd_hh_mm_ss.json
- Plot relationships.
Plot needs these libraries:
- matplotlib
- networkx
- PyQt5
Importing knockpy as a module (dependence) in your python script is quite simple. Naturally, the package must be installed on your system.
from knockpy import knockpy
The command-line parameters can be managed with the following dictionary.
params = {
"no_local": False, # [bool] local wordlist ignore
"no_remote": False, # [bool] remote wordlist ignore
"no_scan": False, # [bool] scanning ignore, show wordlist
"no_http": False, # [bool] http requests ignore
"no_http_code": [], # [list] http code list to ignore
"no_ip": [], # [list] ip address to ignore
"dns": "", # [str] use custom DNS ex. 8.8.8.8
"timeout": 3, # [int] timeout in seconds
"threads": 30, # [int] threads num
"useragent": "", # [str] use a custom user agent
"wordlist": "" # [str] path to custom wordlist
}
You can choose pass only the keys you want to change and keep the others with the default values. Eg:
params = {
"no_local": True,
"no_scan": True
}
Then you can call the function knockpy.Scanning.start()
passing as values the domain and the dictionary assigned to the variable params to get the results in json format.
results = knockpy.Scanning.start("domain.com", params)
The plugins are situated in remote
folder. If you want to write your own plugin it's important to pay attention to some precautions:
- if apikey is required, use
api_
before the plugin name:
api_service.py
- the function name must be
get
and take as parameterdomain
:
def get(domain):
foo
- the function must return a possibly unique list of subdomains:
['sub1.domain.com', 'sub2.domain.com', ...]
- to parse/scrape the results it is recommended to use the standard modules such as:
requests, json, bs4, re
Here is an example of how a plugin should be structured. You can find other examples in the remote folder.
import requests
import json
def get(domain):
# servicename -> JSON: key -> subdomain
url = "https://servicename.com/search/?q={domain}".format(domain=domain)
resp = requests.get(url, timeout=5).text
resp = json.loads(resp)
result = []
for item in resp['data']:
subdomain = item['subdomain']
if subdomain not in result:
result.append(subdomain)
return result
$ knockpy domain.com --plugin-test
In this example, the output shows errors 'error': True
in three plugins because they need the API key.
{
'api_shodan.py': {
'time': '00:00:03',
'match': 0,
'error': True
},
'certspotter.py': {
'time': '00:00:00',
'match': 9,
'error': False
},
'rapiddns.py': {
'time': '00:00:00',
'match': 44,
'error': False
},
'hackertarget.py': {
'time': '00:00:00',
'match': 9,
'error': False
},
'crtsh.py': {
'time': '00:00:19',
'match': 10,
'error': False
},
'api_censys.py': {
'time': '00:00:03',
'match': 0,
'error': True
},
'webarchive.py': {
'time': '00:00:04',
'match': 4,
'error': False
},
'api_virustotal.py': {
'time': '00:00:03',
'match': 0,
'error': True
},
'alienvault.py': {
'time': '00:00:01',
'match': 11,
'error': False
},
'_results': {
'time': '00:00:37',
'plugins': {
'count': 9,
'list': ['api_shodan.py', 'certspotter.py', 'rapiddns.py', 'hackertarget.py', ...],
'error': ['api_shodan.py', 'api_censys.py', 'api_virustotal.py']
},
'subdomains': {
'count': 52,
'list': ['admin', 'cloud', 'www', 'mail', 'calendar', 'contact', 'ftp', .....]
}
}
}
Knockpy is currently under development by @guelfoweb and it's released under the GPL 3 license.