一个分布式 nmap/masscan 扫描框架,包括扫描调度、引擎池化、后续扫描端口差异比对以及用于自动化的 API 客户端
This project has been forked and will be maintained here:
https://github.com/opsdisk/scantron
Scantron is a distributed nmap and masscan scanner comprised of two components. The first is a console node that consists of a web front end used for scheduling scans and storing scan targets and results. The second component is an engine that pulls scan jobs from the console and conducts the actual scanning. A majority of the application's logic is purposely placed on the console to make the engine(s) as "dumb" as possible. All scan target files and scan results reside on the console and are shared through a network file share (NFS) leveraging SSH tunnels. The engines call back to the console periodically using a REST API to check for scan tasks and provide scan status updates. There is also an option to generate nmap scan diffs emailed to you using the pyndiff library.
Checkout the Python Scantron API client for interacting with the Scantron API and driving automated workflows.
Scantron is coded for Python3.6+ exclusively and leverages Django for the web front-end, Django REST Framework as the API endpoint, PostgreSQL as the database, a Redis job queue for tasks, Postfix for email scan alerts, and comes complete with Ubuntu-focused Ansible playbooks for smooth deployments. Scantron has been tested on Ubuntu 18.04 and may be compatible with other operating systems. Scantron's inspiration comes from:
Scantron relies heavily on utilizing SSH port forwards (-R / -L) as an umbilical cord to the engines. Either an SSH
connection from console --> engine or engine --> console is acceptable and may be required depending on different
firewall rules, but tweaking the port forwards and autossh commands will be necessary. If you are unfamiliar with these
concepts, there are some great overviews and tutorials out there:
Scantron is not engineered to be quickly deployed to a server to scan for a few minutes, then torn down and destroyed.
It's better suited for having a set of static scanners (e.g., "internal-scanner", "external-scanner") with a relatively
static set of assets to scan.
A Scantron API client is also available for
creating, retrieving, updating, or deleting sites, scan commands, scans, etc.
Engine: If you plan on compiling masscan on an engine, you'll need at least 1024 MB of memory. It fails to build with
only 512 MB. If you do not want to build masscan, set install_masscan_on_engine to False in
ansible-playbooks/group_vars/all.yml
Console: 512 MB of memory was the smallest amount successfully tested, however, if you plan on processing large scan
files (using the scripts found in console/scan_results: masscan_json_to_csv.py, nmap_to_csv.py or
xml_to_json_nmap_results.py), you'll need more memory.
This is your local box, preferably Linux. Ansible >= 2.4.0.0 is the minimum version required for utilizing ufw comments.
Clone the project and execute initial_setup.sh.
# Clone scantron project.
git clone https://github.com/rackerlabs/scantron.git
cd scantron
./initial_setup.sh # Run as non-root user.
Installation requires a general knowledge of Python, pip, and Ansible. Every attempt to make the deployment as simple as possible has been made.
If the console server is actually a RFC1918 IP and not the public IP (because of NAT), the NAT'd RFC1918 IP
(e.g., 10.1.1.2) will have to be added to the ALLOWED_HOSTS in
ansible-playbooks/roles/console/templates/production.py.j2
This is common in AWS and GCP environments.
Per : For the Ansible workload to work on IBM Cloud, edit the file /boot/grub/menu.lst
by changing
# groot=LABEL...
to
# groot=(hd0)
Edit the hosts in this file:
ansible-playbooks/hosts.iniThe recommendation is to deploy the console first.
Edit any variables in ansible-playbooks/group_vars/all.yml before running playbook. Note the time zone variables:
timezone_server - Set this to be the timezone you want the server to be in, usually UTC.timezone_django - Set this to be your local timezone. It makes dealing with dates, times, and scheduling easier.If you plan on utilizing the same API key across all engines (not recommended, but easier for automated deployments),
change utilize_static_api_token_across_engines to True. This prevents you from having to log into each engine and
update engine_config.json with the corresponding API key. The group_vars/static_api_key will be created by the
the console ansible playbook. The Ansible engine playbook will autofill the engine_config.json.j2 template with the
API key found in group_vars/static_api_key.
WARNING: The engine_config.json.j2 will generate a random scan_engine (e.g., engine-847623), so if you deploy
more than 1 engine, you won't run into complications with engine name collisions. You will, however, need to add create
the user on the console, since the console returns scheduled jobs to the engine based off the engine's name!
Rename console/scantron_secrets.json.empty to console/scantron_secrets.json (should be done for you by
initial_setup.sh)
Update all the values console/scantron_secrets.json if you do not like ones generated using initial_setup.sh. Only
the production values are used.
All Scantron Django passwords have a minimum password length of 12.
For the "SECRET_KEY", per Django's documentation: The secret key must be a large random value and it must be kept secret.
The scantron operating system user password is not really leveraged and is populated by providing a salted hash of a
random password generated using Python's passlib library. If you want to change the password, you will have to
generate a hash for the desired password and update the temp_user_pass variable in
scantron/ansible-playbooks/roles/add_users/vars/main.yml.
pip3 install passlib
python3 -c "from passlib.hash import sha512_crypt; import getpass; print(sha512_crypt.encrypt(getpass.getpass()))"
Ensure you have a SSH key (or username/password) to access the console box, specified by --private-key in the Ansible
command. User must also have password-less sudo privileges.
cd ansible-playbooks
# non-root user with password-less sudo capabilities.
ansible-playbook console.yml -u ubuntu --become --private-key=
# root user.
ansible-playbook console.yml -u root --private-key=
cd into the console directory scantron/console and run the following to change the admin (or whatever user needs
their password changed) user password.
python3 manage.py changepassword admin
Edit any variables in these files before running playbook:
ansible-playbooks/group_vars/all.ymlansible-playbooks/roles/engine/vars/main.ymlEnsure you have a SSH key (or username/password) to access the engine box, specified by --private-key in the Ansible
command. The user must also have password-less sudo privileges. If you are creating the boxes on AWS, then the
user is ubuntu for Ubuntu distros and the user already has password-less sudo capabilities. If you need to add
password-less sudo capability to a user, create a /etc/sudoder.d/ file, where `` is the actual
user, and populate it with:
ALL=(ALL) NOPASSWD: ALL
SSH-ing in as root will also work for the Ansible deployment, but is not generally recommended.
cd ansible-playbooks
# non-root user with password-less sudo capabilities.
ansible-playbook engine.yml -u ubuntu --become --private-key=
# root user.
ansible-playbook engine.yml -u root --private-key=
A Scantron engine is synonymous with a user.
engines users
Users / engines are added through the webapp, so once a user / engine is added, an API token is automatically generated for that user / engine. The user's / engine's password is not necessary for Scantron to function since all user / engine authentication is done using the API token. The username and password can be used to login to the webapp to test API functionality. More API testing information can be found in the Test Engine API section of this README.
This is done automatically for one engine through Ansible. You may have to add additional lines and update SSH keys for each engine if they are different. These commands are for the console connecting to the engines.
In this example:
# console --> engine 1
su - autossh -s /bin/bash -c 'autossh -M 0 -f -N -o "StrictHostKeyChecking no" -o "ServerAliveInterval 60" \
-o "ServerAliveCountMax 3" -p 22 -R 4430:127.0.0.1:443 -R 2049:127.0.0.1:2049 \
-i /home/scantron/console/autossh.key [email protected]'
# console --> engine 2
su - autossh -s /bin/bash -c 'autossh -M 0 -f -N -o "StrictHostKeyChecking no" -o "ServerAliveInterval 60" \
-o "ServerAliveCountMax 3" -p 22 -R 4430:127.0.0.1:443 -R 2049:127.0.0.1:2049 \
-i /home/scantron/console/autossh.key [email protected]'
If the console cannot SSH to an engine, then the autossh command will be run on the engine and the port forwards will be
local (-L) instead of remote (-R).
# console standalone_engine_binary.txt
echo -e "MD5 `md5sum engine`" >> standalone_engine_binary.txt
echo -e "SHA-256 `sha256sum engine`" >> standalone_engine_binary.txt
rm -rf __pycache__ build dist engine.spec .venv
Update all the engines' engine_config.json files with their respective api_token for the engine by logging in as
admin and browsing to https:///scantron-admin/authtoken/token to see the corresponding API token for each
user / engine.
Enable scantron-engine service at startup.
systemctl daemon-reload # Required if scantron-engine.service changed.
systemctl enable scantron-engine
Disable scantron-engine service at startup.
systemctl disable scantron-engine
Scantron service troubleshooting commands.
systemctl status scantron-engine
systemctl start scantron-engine
systemctl stop scantron-engine
systemctl restart scantron-engine
Use screen to avoid the script dying after disconnecting through SSH.
screen -S engine1 # Create a screen session and name it engine1, if using screen.
cd engine
source .venv/bin/activate
# Option 1: Python virtual environment
python engine.py -c engine_config.json
# Option 2: Stand alone binary
./engine -c engine_config.json
CTRL + a + d # Break out of screen session, if using screen.
screen -ls # View screen job, if using screen.
screen -r engine1 # Resume named screen session, if using screen.
Verify SSH connecti
暂无开放 Issues,或尚未同步最近议题。