update code based docs #1

This commit is contained in:
Ali Razmjoo 2018-02-24 12:21:30 +03:30
parent 101224efe4
commit 48fdd9a5fc
10 changed files with 484 additions and 90 deletions

View File

@ -19,11 +19,15 @@ from core import compatible
def create_connection(language):
'''
"""
a function to create sqlite3 connections to db, it retries 100 times if connection returned an error
:param language: language
:return: sqlite3 connection if success otherwise False
'''
Args:
language: language
Returns:
sqlite3 connection if success otherwise False
"""
try:
# retries
for i in range(0, 100):
@ -38,13 +42,17 @@ def create_connection(language):
def send_submit_query(query, language):
'''
"""
a function to send submit based queries to db (such as insert and update or delete), it retries 100 times if
connection returned an error.
:param query: query to execute
:param language: language
:return: True if submitted success otherwise False
'''
Args:
query: query to execute
language: language
Returns:
True if submitted success otherwise False
"""
conn = create_connection(language)
if not conn:
return False
@ -65,12 +73,16 @@ def send_submit_query(query, language):
def send_read_query(query, language):
'''
"""
a function to send read based queries to db (such as select), it retries 100 times if connection returned an error.
:param query: query to execute
:param language: language
:return: return executed query otherwise False
'''
Args:
query: query to execute
language: language
Returns:
return executed query otherwise False
"""
conn = create_connection(language)
if not conn:
return False
@ -89,24 +101,28 @@ def send_read_query(query, language):
def submit_report_to_db(date, scan_id, report_filename, events_num, verbose, api_flag, report_type, graph_flag,
category, profile, scan_method, language, scan_cmd, ports):
'''
"""
this function created to submit the generated reports into db, the files are not stored in db, just the path!
:param date: date and time
:param scan_id: scan hash id
:param report_filename: report full path and filename
:param events_num: length of events in the report
:param verbose: verbose level used to generated the report
:param api_flag: 0 (False) if scan run from CLI and 1 (True) if scan run from API
:param report_type: could be TEXT, JSON or HTML
:param graph_flag: name of the graph used (if it's HTML type)
:param category: category of the modules used in scan (vuln, scan, brute)
:param profile: profiles used in scan
:param scan_method: modules used in scan
:param language: scan report language
:param scan_cmd: scan command line if run in CLI otherwise messages(language, 158)
:param ports: selected port otherwise None
:return: return True if submitted otherwise False
'''
Args:
date: date and time
scan_id: scan hash id
report_filename: report full path and filename
events_num: length of events in the report
verbose: verbose level used to generated the report
api_flag: 0 (False) if scan run from CLI and 1 (True) if scan run from API
report_type: could be TEXT, JSON or HTML
graph_flag: name of the graph used (if it's HTML type)
category: category of the modules used in scan (vuln, scan, brute)
profile: profiles used in scan
scan_method: modules used in scan
language: scan report language
scan_cmd: scan command line if run in CLI otherwise messages(language, 158)
ports: selected port otherwise None
Returns:
return True if submitted otherwise False
"""
info(messages(language, 169))
return send_submit_query("""
INSERT INTO reports (
@ -125,25 +141,33 @@ def submit_report_to_db(date, scan_id, report_filename, events_num, verbose, api
def remove_old_logs(host, type, scan_id, language):
'''
"""
this function remove old events (and duplicated) from database based on host, module, scan_id
:param host: host
:param type: module name
:param scan_id: scan id hash
:param language: language
:return: True if success otherwise False
'''
Args:
host: host
type: module name
scan_id: scan id hash
language: language
Returns:
True if success otherwise False
"""
return send_submit_query("""delete from hosts_log where host="{0}" and type="{1}" and scan_id!="{2}" """
.format(host, type, scan_id), language)
def submit_logs_to_db(language, log):
'''
"""
this function created to submit new events into database
:param language: language
:param log: log event in JSON type
:return: True if success otherwise False
'''
Args:
language: language
log: log event in JSON type
Returns:
True if success otherwise False
"""
if type(log) == str:
log = json.loads(log)
return send_submit_query("""
@ -162,13 +186,17 @@ def submit_logs_to_db(language, log):
def __select_results(language, page):
'''
"""
this function created to crawl into submitted results, it shows last 10 results submitted in the database.
you may change the page (default 1) to go to next/previous page.
:param language: language
:param page: page number
:return: list of events in array and JSON type, otherwise an error in JSON type.
'''
Args:
language: language
page: page number
Returns:
list of events in array and JSON type, otherwise an error in JSON type.
"""
page = int(page * 10 if page > 0 else page * -10) - 10
selected = []
try:
@ -198,12 +226,16 @@ def __select_results(language, page):
def __get_result(language, id):
'''
"""
this function created to download results by the result ID.
:param language: language
:param id: result id
:return: result file content (TEXT, HTML, JSON) if success otherwise and error in JSON type.
'''
Args:
language: language
id: result id
Returns:
result file content (TEXT, HTML, JSON) if success otherwise and error in JSON type.
"""
try:
try:
filename = send_read_query("""select report_filename from reports where id=\"{0}\";""".format(id),
@ -216,12 +248,16 @@ def __get_result(language, id):
def __last_host_logs(language, page):
'''
"""
this function created to select the last 10 events from the database. you can goto next page by changing page value.
:param language: language
:param page: page number
:return: an array of events in JSON type if success otherwise an error in JSON type
'''
Args:
language: language
page: page number
Returns:
an array of events in JSON type if success otherwise an error in JSON type
"""
page = int(page * 10 if page > 0 else page * -10) - 10
data_structure = {
"host": "",
@ -277,12 +313,16 @@ def __last_host_logs(language, page):
def __logs_by_scan_id(scan_id, language):
'''
"""
select all events by scan id hash
:param scan_id: scan id hash
:param language: language
:return: an array with JSON events or an empty array
'''
Args:
scan_id: scan id hash
language: language
Returns:
an array with JSON events or an empty array
"""
try:
logs = []
for log in send_read_query(
@ -305,12 +345,16 @@ def __logs_by_scan_id(scan_id, language):
def __logs_to_report_json(host, language):
'''
"""
select all reports of a host
:param host: the host to search
:param language: language
:return: an array with JSON events or an empty array
'''
Args:
host: the host to search
language: language
Returns:
an array with JSON events or an empty array
"""
try:
logs = []
for log in send_read_query(
@ -333,12 +377,16 @@ def __logs_to_report_json(host, language):
def __logs_to_report_html(host, language):
'''
"""
generate HTML report with d3_tree_v2_graph for a host
:param host: the host
:param language: language
:return: HTML report
'''
Args:
host: the host
language: language
Returns:
HTML report
"""
try:
logs = []
for log in send_read_query(
@ -377,13 +425,17 @@ def __logs_to_report_html(host, language):
def __search_logs(language, page, query):
'''
"""
search in events (host, date, port, module, category, description, username, password, scan_id, scan_cmd)
:param language: language
:param page: page number
:param query: query to search
:return: an array with JSON structure of founded events or an empty array
'''
Args:
language: language
page: page number
query: query to search
Returns:
an array with JSON structure of founded events or an empty array
"""
page = int(page * 10 if page > 0 else page * -10) - 10
data_structure = {
"host": "",

View File

@ -5,6 +5,15 @@ from core.attack import __go_for_attacks
def __scan(config):
"""
call for attacks with separated config and parse ARGS
Args:
config: config in JSON
Returns:
True if success otherwise False
"""
# Setting Variables
targets = config["targets"]
check_ranges = config["check_ranges"]
@ -28,7 +37,7 @@ def __scan(config):
profile = config["profile"]
backup_ports = config["backup_ports"]
__go_for_attacks(targets, check_ranges, check_subdomains, log_in_file, time_sleep, language, verbose_level, retries,
socks_proxy, users, passwds, timeout_sec, thread_number, ports, ping_flag, methods_args,
backup_ports, scan_method, thread_number_host, graph_flag, profile, True)
return True
return __go_for_attacks(targets, check_ranges, check_subdomains, log_in_file, time_sleep, language, verbose_level,
retries,
socks_proxy, users, passwds, timeout_sec, thread_number, ports, ping_flag, methods_args,
backup_ports, scan_method, thread_number_host, graph_flag, profile, True)

View File

@ -12,6 +12,16 @@ from flask import abort
def __structure(status="", msg=""):
"""
basic JSON message structure
Args:
status: status (ok, failed)
msg: the message content
Returns:
a JSON message
"""
return {
"status": status,
"msg": msg
@ -19,6 +29,16 @@ def __structure(status="", msg=""):
def __get_value(flask_request, _key):
"""
get a value from GET, POST or CCOKIES
Args:
flask_request: the flask request
_key: the value name to find
Returns:
the value content if found otherwise None
"""
try:
key = flask_request.args[_key]
except:
@ -30,11 +50,21 @@ def __get_value(flask_request, _key):
except:
key = None
if key is not None:
key = key.replace("\"", "").replace("'", "")
# fix it later
key = key.replace("\\\"", "\"").replace("\\\'", "\'")
return key
def __remove_non_api_keys(config):
"""
a function to remove non-api keys while loading ARGV
Args:
config: all keys in JSON
Returns:
removed non-api keys in all keys in JSON
"""
non_api_keys = ["start_api", "api_host", "api_port", "api_debug_mode", "api_access_key", "api_client_white_list",
"api_client_white_list_ips", "api_access_log", "api_access_log", "api_access_log_filename",
"show_version", "check_update", "help_menu_flag", "targets_list", "users_list", "passwds_list",
@ -47,12 +77,28 @@ def __remove_non_api_keys(config):
def __is_login(app, flask_request):
"""
check if session is valid
Args:
app: flask app
flask_request: flask request
Returns:
True if session is valid otherwise False
"""
if app.config["OWASP_NETTACKER_CONFIG"]["api_access_key"] == __get_value(flask_request, "key"):
return True
return False
def __mime_types():
"""
contains all mime types for HTTP request
Returns:
all mime types in json
"""
return {
".aac": "audio/aac",
".abw": "application/x-abiword",
@ -126,10 +172,25 @@ def __mime_types():
def root_dir():
"""
find the root directory for web static files
Returns:
root path for static files
"""
return os.path.join(os.path.join(os.path.dirname(os.path.dirname(__file__)), "web"), "static")
def get_file(filename):
"""
open the requested file in HTTP requests
Args:
filename: path and the filename
Returns:
content of the file or abort(404)
"""
try:
src = os.path.join(root_dir(), filename)
return open(src, 'rb').read()
@ -138,11 +199,30 @@ def get_file(filename):
def __api_key_check(app, flask_request, language):
"""
check the validity of API key
Args:
app: the flask app
flask_request: the flask request
language: language
Returns:
200 HTTP code if it's valid otherwise 401 error
"""
if app.config["OWASP_NETTACKER_CONFIG"]["api_access_key"] != __get_value(flask_request, "key"):
abort(401, messages(language, 160))
return
def __languages():
"""
define list of languages with country flag for API
Returns:
HTML code for each language with its country flag
"""
languages = [lang for lang in messages(-1, 0)]
res = ""
flags = {
@ -174,6 +254,12 @@ def __languages():
def __graphs():
"""
all available graphs for API
Returns:
HTML content or available graphs
"""
res = """<label><input id="" type="radio" name="graph_flag" value="" class="radio"><a
class="label label-default">None</a></label>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"""
for graph in load_all_graphs():
@ -183,6 +269,12 @@ def __graphs():
def __profiles():
"""
all available profiles for API
Returns:
HTML content or available profiles
"""
profiles = _builder(_profiles(), default_profiles())
res = ""
for profile in profiles:
@ -192,6 +284,12 @@ def __profiles():
def __scan_methods():
"""
all available modules for API
Returns:
HTML content or available modules
"""
methods = load_all_modules()
methods.remove("all")
res = ""
@ -204,6 +302,17 @@ def __scan_methods():
def __rules(config, defaults, language):
"""
Load ARGS from API requests and apply the rules
Args:
config: all user config
defaults: default config
language: language
Returns:
config with applied rules
"""
# Check Ranges
config["check_ranges"] = True if config["check_ranges"] is not False else False
# Check Subdomains

View File

@ -47,40 +47,101 @@ app.config.from_object(__name__)
def __language(app=app):
"""
find the language in config
Args:
app: flask app
Returns:
the language in string
"""
return app.config["OWASP_NETTACKER_CONFIG"]["language"]
@app.errorhandler(400)
def error_400(error):
"""
handle the 400 HTTP error
Args:
error: the flask error
Returns:
400 JSON error
"""
return jsonify(__structure(status="error", msg=error.description)), 400
@app.errorhandler(401)
def error_401(error):
"""
handle the 401 HTTP error
Args:
error: the flask error
Returns:
401 JSON error
"""
return jsonify(__structure(status="error", msg=error.description)), 401
@app.errorhandler(403)
def error_403(error):
"""
handle the 403 HTTP error
Args:
error: the flask error
Returns:
403 JSON error
"""
return jsonify(__structure(status="error", msg=error.description)), 403
@app.errorhandler(404)
def error_404(error):
"""
handle the 404 HTTP error
Args:
error: the flask error
Returns:
404 JSON error
"""
return jsonify(__structure(status="error",
msg=messages(app.config["OWASP_NETTACKER_CONFIG"]["language"], 162))), 404
@app.before_request
def limit_remote_addr():
"""
check if IP filtering applied and API address is in whitelist
Returns:
None if it's in whitelist otherwise abort(403)
"""
# IP Limitation
if app.config["OWASP_NETTACKER_CONFIG"]["api_client_white_list"]:
if flask_request.remote_addr not in app.config["OWASP_NETTACKER_CONFIG"]["api_client_white_list_ips"]:
abort(403, messages(__language(), 161))
return
@app.after_request
def access_log(response):
"""
if access log enabled, its writing the logs
Args:
response: the flask response
Returns:
the flask response
"""
if app.config["OWASP_NETTACKER_CONFIG"]["api_access_log"]:
r_log = open(app.config["OWASP_NETTACKER_CONFIG"]["api_access_log_filename"], "ab")
# if you need to log POST data
@ -99,6 +160,15 @@ def access_log(response):
@app.route("/", defaults={"path": ""})
@app.route("/<path:path>")
def get_statics(path):
"""
getting static files and return content mime types
Args:
path: path and filename
Returns:
file content and content type if file found otherwise abort(404)
"""
static_types = __mime_types()
return Response(get_file(os.path.join(root_dir(), path)),
mimetype=static_types.get(os.path.splitext(path)[1], "text/html"))
@ -106,6 +176,12 @@ def get_statics(path):
@app.route("/", methods=["GET", "POST"])
def index():
"""
index page for WebUI
Returns:
rendered HTML page
"""
filename = _builder(_core_config(), _core_default_config())["log_in_file"]
return render_template("index.html", scan_method=__scan_methods(), profile=__profiles(),
graphs=__graphs(), languages=__languages(), filename=filename,
@ -114,6 +190,12 @@ def index():
@app.route("/new/scan", methods=["GET", "POST"])
def new_scan():
"""
new scan through the API
Returns:
a JSON message with scan details if success otherwise a JSON error
"""
_start_scan_config = {}
__api_key_check(app, flask_request, __language())
for key in _core_default_config():
@ -134,12 +216,24 @@ def new_scan():
@app.route("/session/check", methods=["GET"])
def __session_check():
"""
check the session if it's valid
Returns:
a JSON message if it's valid otherwise abort(401)
"""
__api_key_check(app, flask_request, __language())
return jsonify(__structure(status="ok", msg=messages(__language(), 165))), 200
@app.route("/session/set", methods=["GET"])
def __session_set():
"""
set session on the browser
Returns:
200 HTTP response if session is valid and a set-cookie in the response if success otherwise abort(403)
"""
__api_key_check(app, flask_request, __language())
res = make_response(jsonify(__structure(status="ok", msg=messages(__language(), 165))))
res.set_cookie("key", value=app.config["OWASP_NETTACKER_CONFIG"]["api_access_key"])
@ -148,6 +242,12 @@ def __session_set():
@app.route("/session/kill", methods=["GET"])
def __session_kill():
"""
unset session on the browser
Returns:
a 200 HTTP response with set-cookie to "expired" to unset the cookie on the browser
"""
res = make_response(jsonify(__structure(status="ok", msg=messages(__language(), 166))))
res.set_cookie("key", value="expired")
return res
@ -155,6 +255,12 @@ def __session_kill():
@app.route("/results/get_list", methods=["GET"])
def __get_results():
"""
get list of scan's results through the API
Returns:
an array of JSON scan's results if success otherwise abort(403)
"""
__api_key_check(app, flask_request, __language())
try:
page = int(__get_value(flask_request, "page"))
@ -165,6 +271,12 @@ def __get_results():
@app.route("/results/get", methods=["GET"])
def __get_result_content():
"""
get a result HTML/TEXT/JSON content
Returns:
content of the scan result
"""
__api_key_check(app, flask_request, __language())
try:
id = int(__get_value(flask_request, "id"))
@ -175,6 +287,12 @@ def __get_result_content():
@app.route("/logs/get_list", methods=["GET"])
def __get_last_host_logs():
"""
get list of logs through the API
Returns:
an array of JSON logs if success otherwise abort(403)
"""
__api_key_check(app, flask_request, __language())
try:
page = int(__get_value(flask_request, "page"))
@ -185,6 +303,12 @@ def __get_last_host_logs():
@app.route("/logs/get_html", methods=["GET"])
def __get_logs_html():
"""
get host's logs through the API in HTML type
Returns:
HTML report
"""
__api_key_check(app, flask_request, __language())
try:
host = __get_value(flask_request, "host")
@ -195,6 +319,12 @@ def __get_logs_html():
@app.route("/logs/get_json", methods=["GET"])
def __get_logs():
"""
get host's logs through the API in JSON type
Returns:
an array with JSON events
"""
__api_key_check(app, flask_request, __language())
try:
host = __get_value(flask_request, "host")
@ -205,6 +335,12 @@ def __get_logs():
@app.route("/logs/search", methods=["GET"])
def ___go_for_search_logs():
"""
search in all events
Returns:
an array with JSON events
"""
__api_key_check(app, flask_request, __language())
try:
page = int(__get_value(flask_request, "page"))
@ -219,6 +355,20 @@ def ___go_for_search_logs():
def __process_it(api_host, api_port, api_debug_mode, api_access_key, api_client_white_list,
api_client_white_list_ips, api_access_log, api_access_log_filename, language):
"""
a function to run flask in a subprocess to make kill signal in a better way!
Args:
api_host: host/IP to bind address
api_port: bind port
api_debug_mode: debug mode flag
api_access_key: API access key
api_client_white_list: clients while list flag
api_client_white_list_ips: clients white list IPs
api_access_log: access log flag
api_access_log_filename: access log filename
language: language
"""
app.config["OWASP_NETTACKER_CONFIG"] = {
"api_access_key": api_access_key,
"api_client_white_list": api_client_white_list,
@ -232,6 +382,20 @@ def __process_it(api_host, api_port, api_debug_mode, api_access_key, api_client_
def _start_api(api_host, api_port, api_debug_mode, api_access_key, api_client_white_list,
api_client_white_list_ips, api_access_log, api_access_log_filename, language):
"""
entry point to run the API through the flask
Args:
api_host: host/IP to bind address
api_port: bind port
api_debug_mode: debug mode
api_access_key: API access key
api_client_white_list: clients while list flag
api_client_white_list_ips: clients white list IPs
api_access_log: access log flag
api_access_log_filename: access log filename
language: language
"""
# Starting the API
write_to_api_console(messages(language, 156).format(api_access_key))
p = multiprocessing.Process(target=__process_it,

10
api/readme.md Normal file
View File

@ -0,0 +1,10 @@
OWASP Nettacker API Files
=========================
OWASP Nettacker API files are stored in here.
* `__database.py` contains database interaction functions
* `engine.py` is entry point of API and main functions
* `api_core.py` has core functions
* `__start_scan.py` run new scans
* `database.sqlite3` an empty API database for sample, its copy to `~/.owasp-nettacker/database.sqlite3` and stores data i there.

22
core/readme.md Normal file
View File

@ -0,0 +1,22 @@
OWASP Nettacker core functions
==============================
OWASP Nettacker core functions are stored in here.
* `_die.py` exit functions
* `_time.py` time functions
* `alert.py` user alerts and printing functions
* `args_loader.py` ARGV commands and apply rules
* `attack.py` start new attacks and multi-processing managements
* `color.py` color founds for windows and linux/mac.
* `compatible.py` compatibility functions
* `config.py` user configs (could be modify by user)
* `config_builder.py` core static configs (same as user configs but should not be change by users)
* `get_input.py` get inputs from users functions
* `ip.py` IPv4 and IPv6 functions
* `load_modules` load modules, requirements, paths functions
* `log.py` log the scans and generate reports
* `parse.py` parse the ARGV and pass it
* `targets.py` process, calculate and count targets
* `update.py` updates functions of the framework
* `wizard.py` wizard mode for the framework

14
lib/readme.md Normal file
View File

@ -0,0 +1,14 @@
OWASP Nettacker Libraries and Modules
=====================================
OWASP Nettacker modules and libraries are located in here
* `argparse` argparse fixed library for unicode
* `brute` contains brute force types modules
* `graph` graph modules of the framework
* `html_log` HTML log contents
* `icmp` ICMP library
* `language` contains messages in several languages
* `scan` contains scan types modules
* `vuln` contains vulnerability types modules
* `socks_resolver` resolve address by socks proxy

View File

@ -1 +1,7 @@
Script files are located in here
OWASP Nettacker Scripts
=======================
Script files are located in here.
* `__travis_test__.py` test the framework through the TravisCI
* `nettacker` run OWASP Nettacker through the terminal
* `nettacker.bat` run OWASP Nettacker throough the Windows CMD

View File

@ -8,11 +8,15 @@ from setuptools import find_packages
def package_files(directory):
'''
"""
This function was created to crawl the directory and find files (none python files) using os.walk
:param directory: path to crawl
:return: list of package files in an array
'''
Args:
directory: path to crawl
Returns:
list of package files in an array
"""
paths = []
for (path, directories, filenames) in os.walk(directory):
for filename in filenames:

View File

@ -1 +1,5 @@
Web UI files are located in here
OWASP Nettacker WebUI
=====================
Web UI files are located in here.
* `static` static files for web UI