Import upstream version 1.9.0
Kali Janitor
1 year, 4 months ago
0 | [flake8] | |
1 | ignore = W391, E722, E303, E701, W291, E222, E241, E225, E115, E117, E122, E123, E124, E501, E261, E127, E265, F401, W292, W293, W605, E231, E221, E222, F841, E128, W504, E202, F811, E251, E226, E203, E262, E225, E305, E302, E305 | |
2 | exclude= report-collection⏎ |
0 | # Created by .ignore support plugin (hsz.mobi) | |
1 | ### Python template | |
2 | # Byte-compiled / optimized / DLL files | |
3 | __pycache__/ | |
4 | *.py[cod] | |
5 | *$py.class | |
6 | ||
7 | # C extensions | |
8 | *.so | |
9 | ||
10 | # Distribution / packaging | |
11 | .Python | |
12 | build/ | |
13 | develop-eggs/ | |
14 | dist/ | |
15 | downloads/ | |
16 | eggs/ | |
17 | .eggs/ | |
18 | lib/ | |
19 | lib64/ | |
20 | parts/ | |
21 | sdist/ | |
22 | var/ | |
23 | wheels/ | |
24 | pip-wheel-metadata/ | |
25 | share/python-wheels/ | |
26 | *.egg-info/ | |
27 | .installed.cfg | |
28 | *.egg | |
29 | MANIFEST | |
30 | ||
31 | # PyInstaller | |
32 | # Usually these files are written by a python script from a template | |
33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. | |
34 | *.manifest | |
35 | *.spec | |
36 | ||
37 | # Installer logs | |
38 | pip-log.txt | |
39 | pip-delete-this-directory.txt | |
40 | ||
41 | # Unit test / coverage reports | |
42 | htmlcov/ | |
43 | .tox/ | |
44 | .nox/ | |
45 | .coverage | |
46 | .coverage.* | |
47 | .cache | |
48 | nosetests.xml | |
49 | coverage.xml | |
50 | *.cover | |
51 | .hypothesis/ | |
52 | .pytest_cache/ | |
53 | ||
54 | # Translations | |
55 | *.mo | |
56 | *.pot | |
57 | ||
58 | # Django stuff: | |
59 | *.log | |
60 | local_settings.py | |
61 | db.sqlite3 | |
62 | db.sqlite3-journal | |
63 | ||
64 | # Flask stuff: | |
65 | instance/ | |
66 | .webassets-cache | |
67 | ||
68 | # Scrapy stuff: | |
69 | .scrapy | |
70 | ||
71 | # Sphinx documentation | |
72 | docs/_build/ | |
73 | ||
74 | # PyBuilder | |
75 | target/ | |
76 | ||
77 | # Jupyter Notebook | |
78 | .ipynb_checkpoints | |
79 | ||
80 | # IPython | |
81 | profile_default/ | |
82 | ipython_config.py | |
83 | ||
84 | # pyenv | |
85 | .python-version | |
86 | ||
87 | # pipenv | |
88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. | |
89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies | |
90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not | |
91 | # install all needed dependencies. | |
92 | #Pipfile.lock | |
93 | ||
94 | # celery beat schedule file | |
95 | celerybeat-schedule | |
96 | ||
97 | # SageMath parsed files | |
98 | *.sage.py | |
99 | ||
100 | # Environments | |
101 | .env | |
102 | .venv | |
103 | env/ | |
104 | venv/ | |
105 | ENV/ | |
106 | env.bak/ | |
107 | venv.bak/ | |
108 | ||
109 | # Spyder project settings | |
110 | .spyderproject | |
111 | .spyproject | |
112 | ||
113 | # Rope project settings | |
114 | .ropeproject | |
115 | ||
116 | # mkdocs documentation | |
117 | /site | |
118 | ||
119 | # mypy | |
120 | .mypy_cache/ | |
121 | .dmypy.json | |
122 | dmypy.json | |
123 | ||
124 | # Pyre type checker | |
125 | .pyre/ | |
126 | ||
127 | .idea | |
128 | /report-collection/ | |
129 | ||
130 | #project settings | |
131 | *.project⏎ |
0 | .get_secrets: | |
1 | script: | |
2 | - export VAULT_TOKEN="$(vault write -field=token auth/jwt/login role=python-sast-readonly jwt=$CI_JOB_JWT)"; if [ -z "$VAULT_TOKEN" ]; then exit 1; fi | |
3 | - if [ -z "$DEVSECOPS_WORKSPACE" ]; then export DEVSECOPS_WORKSPACE="$(vault kv get -field=DEVSECOPS_WORKSPACE secrets/gitlab/SAST)"; fi; if [ -z "$DEVSECOPS_WORKSPACE" ]; then exit 1; fi | |
4 | - if [ -z "$FARADAY_PASSWORD" ]; then export FARADAY_PASSWORD="$(vault kv get -field=FARADAY_PASSWORD secrets/gitlab/SAST)"; fi; if [ -z "$FARADAY_PASSWORD" ]; then exit 1; fi | |
5 | - if [ -z "$FARADAY_URL" ]; then export FARADAY_URL="$(vault kv get -field=FARADAY_URL secrets/gitlab/SAST)"; fi; if [ -z "$FARADAY_URL" ]; then exit 1; fi | |
6 | - if [ -z "$FARADAY_USER" ]; then export FARADAY_USER="$(vault kv get -field=FARADAY_USER secrets/gitlab/SAST)"; fi; if [ -z "$FARADAY_USER" ]; then exit 1; fi |
0 | variables: | |
1 | VAULT_ROLE: 'python-sast-readonly' | |
2 | VAULT_ADDR: 'https://tluav-lb.faradaysec.com' | |
3 | VAULT_SECRET_PATH: 'gitlab/SAST' | |
4 | ||
5 | ||
6 | include: | |
7 | - local: .gitlab/ci/fetch-secrets.yml | |
8 | ||
9 | stages: | |
10 | - SAST | |
11 | - pre_testing | |
12 | - testing | |
13 | - post_testing | |
14 | - publish | |
15 | ||
16 | before_script: | |
17 | - apt-get update -qy | |
18 | - pip install pip -U | |
19 | ||
20 | workflow: | |
21 | rules: | |
22 | - if: $CI_MERGE_REQUEST_ID | |
23 | when: never | |
24 | - when: always | |
25 | ||
26 | .install_faraday_venv: &install_faraday_venv | |
27 | - pip3 install virtualenv | |
28 | - virtualenv -p python3 faraday_venv | |
29 | - source faraday_venv/bin/activate | |
30 | - pip3 install pytest pytest-xdist pytest-cov | |
31 | - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/faradaysec/faraday.git | |
32 | - cd faraday | |
33 | - pip3 install $PIP_FLAGS . | |
34 | - pip uninstall faraday-plugins -y # we need to install fardaysec for marshmallow schemas, we remove plugins from pypi | |
35 | - cd .. | |
36 | ||
37 | .clone_reports: &clone_reports | |
38 | - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/faradaysec/support/report-collection.git | |
39 | - cd report-collection | |
40 | - (git branch -a | grep $CI_COMMIT_BRANCH) && export REPORT_REF=$CI_COMMIT_BRANCH || export REPORT_REF=master | |
41 | - git checkout $REPORT_REF | |
42 | - cd .. | |
43 | ||
44 | bandit: | |
45 | stage: SAST | |
46 | image: python:3 | |
47 | tags: | |
48 | - faradaytests | |
49 | script: | |
50 | - pip3 install bandit | |
51 | - mkdir /results | |
52 | - "bandit -r ${CI_PROJECT_DIR} -o /results/output.xml -f xml --skip B410,B320,B310,B314,B404,B405,B324,B603,B104,B110,B112,B101" | |
53 | after_script: | |
54 | - curl -fsSL https://apt.releases.hashicorp.com/gpg | apt-key add - | |
55 | - apt update | |
56 | - apt-get install software-properties-common -y | |
57 | - apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com focal main" | |
58 | - apt update | |
59 | - apt install vault -y | |
60 | - setcap cap_ipc_lock= /usr/bin/vault | |
61 | - !reference [ .get_secrets, script ] | |
62 | - pip3 install faraday-cli | |
63 | - if [[ $(grep -c testcase /results/output.xml) -gt 0 ]]; then (faraday-cli auth -f $FARADAY_URL -u $FARADAY_USER -p $FARADAY_PASSWORD && faraday-cli tool report /results/output.xml -w $DEVSECOPS_WORKSPACE --tag-vuln $CI_PROJECT_NAME --tag-vuln $CI_COMMIT_REF_NAME); else (echo 'no vulns dettected' && exit 0); fi | |
64 | rules: | |
65 | - when: on_success | |
66 | ||
67 | flake8: | |
68 | image: python:3 | |
69 | stage: pre_testing | |
70 | before_script: | |
71 | - pip install flake8 | |
72 | # Help flake8 to find the Python files without .py extension. | |
73 | - find . -name '*.py' >> files.txt | |
74 | - sort -u files.txt | tee files.processed | |
75 | script: | |
76 | - python -m flake8 --statistics --count $(cat files.processed) --verbose | |
77 | after_script: | |
78 | - wc -l files.processed | |
79 | ||
80 | .test_base: | |
81 | stage: testing | |
82 | coverage: '/TOTAL\s+\d+\s+\d+\s+(\d+%)/' | |
83 | script: | |
84 | - *clone_reports | |
85 | - *install_faraday_venv | |
86 | - pip3 install $PIP_FLAGS . | |
87 | - pytest tests --capture=sys -v --cov=faraday_plugins --color=yes --disable-warnings $PYTEST_FLAGS | |
88 | ||
89 | tests: | |
90 | extends: .test_base | |
91 | image: python:3 | |
92 | ||
93 | test_performance: | |
94 | extends: .test_base | |
95 | image: python:3 | |
96 | stage: post_testing | |
97 | allow_failure: true | |
98 | variables: | |
99 | PYTEST_FLAGS: --performance | |
100 | rules: | |
101 | - if: '$CI_COMMIT_BRANCH == "dev"' | |
102 | when: on_success | |
103 | ||
104 | publish_pypi: | |
105 | image: python:3 | |
106 | stage: publish | |
107 | script: | |
108 | - apt-get update -qy | |
109 | - apt-get install twine -y | |
110 | - python setup.py sdist bdist_wheel | |
111 | - twine upload -u $PYPI_USER -p $PYPI_PASS dist/* --verbose | |
112 | rules: | |
113 | - if: '$CI_COMMIT_TAG' | |
114 | when: on_success | |
115 |
0 | default_stages: [commit] | |
1 | repos: | |
2 | - repo: https://github.com/pre-commit/pre-commit-hooks | |
3 | rev: v3.1.0 | |
4 | hooks: | |
5 | - id: trailing-whitespace | |
6 | - id: end-of-file-fixer | |
7 | - id: check-json | |
8 | - id: check-yaml | |
9 | args: [ --unsafe ] | |
10 | - id: debug-statements | |
11 | - repo: https://gitlab.com/pycqa/flake8 | |
12 | rev: 3.8.3 | |
13 | hooks: | |
14 | - id: flake8 | |
15 | additional_dependencies: [flake8-typing-imports==1.9.0] | |
16 | - repo: https://github.com/ikamensh/flynt/ | |
17 | rev: '0.56' | |
18 | hooks: | |
19 | - id: flynt | |
20 | args: [ -df ] | |
21 | - repo: https://github.com/asottile/pyupgrade | |
22 | rev: v2.29.0 | |
23 | hooks: | |
24 | - id: pyupgrade | |
25 | args: [ --py3-plus , --py36-plus] |
0 | add a default value to plugin_version⏎ |
0 | Add --output-file parameter to faraday-plugins process command⏎ |
0 | Bug fix: Arachni Plugin 'NoneType' object has no attribute 'find' |
0 | Bug fix: Openvas Plugin - Import xml from OpenVas doesnt work |
0 | Bug fix: QualysWebApp Plugin, error in get info OPERATING_SYSTEM |
0 | Fix Hydra plugin to resolve ip address⏎ |
0 | Update the fields of the nuclei output used to create a vuln⏎ |
0 | Add new plugin base class, for multi line json⏎ |
0 | Fix missing ip in some arachni reports⏎ |
0 | Change the way we detect json reports when they are lists of dictionaries⏎ |
0 | ADD microsoft baseline security analyzer plugin |
0 | Add Ignore information vulnerabilities option |
0 | Faraday CSV Plugin do not consider ignore_info |
0 | Use background for description and detail for data en Burp plugin. |
0 | - add attribute "command" for the pluggins of each command | |
1 | - adding test in test_command | |
2 | - change some regex in self._command_regex⏎ |
0 | [FIX] add hostnames if host is already cached |
0 | FIX unused import, innecesary list compression and unused variables⏎ |
0 | FIX metasploit report when the web-site-id is null⏎ |
0 | ADD cve, cvss3_base_score, cvss3_vector, exploit_available when import nessus and change the structure of external_id to NESSUS-XXX⏎ |
0 | ADD more data like attack, params, uri, method, WASC, CWE and format externail_id⏎ |
0 | Add vuln details for Certificate Mismatch and move unique details to data, now vulns can be grupped |
0 | ADD more data to plugins arachni and w3af⏎ |
0 | ADD cvss_base, cpe, threat, severity into references⏎ |
0 | cwe, capec, references, tags, impact, resolution, easeofresolution |
0 | [FIX] Fix improt of CSV with big fields |
0 | Adding support for running nuclei through command / faraday-cli |
0 | Add CVE to plugins | |
1 | - acunetix | |
2 | - appscan | |
3 | - burp | |
4 | - metasploit | |
5 | - nessus | |
6 | - netsparker | |
7 | - nexpose | |
8 | - nikto | |
9 | - nipper | |
10 | - nmap | |
11 | - openscap | |
12 | - qualysguard | |
13 | - retina | |
14 | - shodan |
0 | Fix errors while creating hosts with wrong regex⏎ |
0 | Add severity to shodan's plugins using cvss⏎ |
0 | Change qualysguard's plugin severity_dict to refer level 2 severities as low |
0 | Now Appscan plugin saves line and highlight of the vulns in desc and data |
0 | Now the faraday_csv custom_fields regex match any no whitespace character. |
0 | Now Openvas's plugin set severity to Critical when cvss >= 9.0 |
0 | Add hostname_resolution parameter within plugins |
0 | Change hostname_restolution to dont_resolve_hostname for process-report and now test dosent resovle hostname |
0 | Now QualysWebApp's plugin will diferenciate vulns from differents urlpaths |
0 | Now faraday_csv's plugin uses ignore_info parameter |
0 | Add cve and data fields to desc for avoid duplications |
0 | Add CWE to PluginBase. The plugins that have this implemented are the following: | |
1 | "Acunetix", | |
2 | "Acunetix_Json", | |
3 | "AppSpider", | |
4 | "Appscan", | |
5 | "Arachni", | |
6 | "Burp", | |
7 | "Checkmarx", | |
8 | "Metasploit", | |
9 | "Nessus", | |
10 | "Netsparker", | |
11 | "NetsparkerCloud", | |
12 | "Openvas", | |
13 | "QualysWebapp", | |
14 | "W3af", | |
15 | "Wapiti", | |
16 | "Zap", | |
17 | "Zap_Json", | |
18 | "nuclei", | |
19 | "nuclei_legacy" |
0 | Now the nexts pluggins extracts cvss from reports: | |
1 | ||
2 | - Acunetix | |
3 | - Acunetix_Json | |
4 | - Appscan | |
5 | - Nessus | |
6 | - Netsparker | |
7 | - NexposeFull | |
8 | - Nipper | |
9 | - Nmap | |
10 | - Openvas | |
11 | - QualysWebapp | |
12 | - Qualysguard | |
13 | - Retina | |
14 | - shodan | |
15 | - whitesource |
0 | Add command support for the wpscan plugin |
0 | [FIX] - Asset duplicated on same file with multiple entries for Appscan_csv plugin.⏎ |
0 | [FIX] Change import dateutil to from dateutil.parser import parse | |
1 | for compatibility issues with python 3.10 |
0 | [FIX] Add case for Netsparker plugins, when the url has a number inside a parenthesis. |
0 | fix bug when grype report has no arifact/metadata |
0 | [FIX] Remove cvss_vector from refs in nexpose_full |
0 | [FIX] Now plugins check if ref field is already a dictionary |
0 | [MOD] Improve grype plugin for dockers images and change report_belong_to method for | |
1 | json plugins to check if json_keys is a list, in that case iterate the list and try if | |
2 | any of them create a match. |
0 | [FIX] Nuclei's plugin check if the cwe is null and add retrocompability for newer versions for wpscan plugin |
0 | [Add] Now nexpose_full plugin use severity from reports |
0 | [FIX] Now plugins check if the ref is empty |
0 | Metadata-Version: 2.1 | |
1 | Name: faraday-plugins | |
2 | Version: 1.9.0 | |
3 | Summary: Faraday plugins package | |
4 | Home-page: | |
5 | Author: Faradaysec | |
6 | Author-email: [email protected] | |
7 | License: GNU General Public License v3 | |
8 | License-File: COPYING |
0 | 1.8.1 [Nov 28th, 2022]: | |
1 | --- | |
2 | * [FIX] Nuclei's plugin check if the cwe is null and add retrocompability for newer versions for wpscan plugin | |
3 | * [ADD] Add cvss2/3 and cwe to faraday_csv plugin | |
4 | * [Add] Now nexpose_full plugin use severity from reports | |
5 | * [FIX] Now plugins check if the ref is empty | |
6 | ||
7 | 1.8.0: | |
8 | --- | |
9 | * [Add] Add invicti plugin | |
10 | * [Add] Add nessus_sc plugin | |
11 | * [FIX] Remove cvss_vector from refs in nexpose_full | |
12 | * Add new identifier_tag to nikto plugin | |
13 | * [FIX] Now plugins check if ref field is already a dictionary | |
14 | * [MOD] Improve grype plugin for dockers images and change report_belong_to method for | |
15 | json plugins to check if json_keys is a list, in that case iterate the list and try if | |
16 | any of them create a match. | |
17 | ||
18 | 1.7.0 [Sep 5th, 2022]: | |
19 | --- | |
20 | * Add CWE to PluginBase. The plugins that have this implemented are the following: | |
21 | "Acunetix", | |
22 | "Acunetix_Json", | |
23 | "AppSpider", | |
24 | "Appscan", | |
25 | "Arachni", | |
26 | "Burp", | |
27 | "Checkmarx", | |
28 | "Metasploit", | |
29 | "Nessus", | |
30 | "Netsparker", | |
31 | "NetsparkerCloud", | |
32 | "Openvas", | |
33 | "QualysWebapp", | |
34 | "W3af", | |
35 | "Wapiti", | |
36 | "Zap", | |
37 | "Zap_Json", | |
38 | "nuclei", | |
39 | "nuclei_legacy" | |
40 | * Now the nexts pluggins extracts cvss from reports: | |
41 | ||
42 | - Acunetix | |
43 | - Acunetix_Json | |
44 | - Appscan | |
45 | - Nessus | |
46 | - Netsparker | |
47 | - NexposeFull | |
48 | - Nipper | |
49 | - Nmap | |
50 | - Openvas | |
51 | - QualysWebapp | |
52 | - Qualysguard | |
53 | - Retina | |
54 | - shodan | |
55 | - whitesource | |
56 | * Add arguments for add tags for vulns, services and host. | |
57 | ||
58 | Add test for tags and ignore_info | |
59 | * Add trivy's json plugin | |
60 | * Add command support for the wpscan plugin | |
61 | * [MOD] Now refs field is a list of dictionary with the format: | |
62 | {'name': string, 'type': string}, | |
63 | * Fix for acunetix_json when host is ip | |
64 | * [FIX] - Asset duplicated on same file with multiple entries for Appscan_csv plugin. | |
65 | * [FIX] Change import dateutil to from dateutil.parser import parse | |
66 | for compatibility issues with python 3.10 | |
67 | * [FIX] Add case for Netsparker plugins, when the url has a number inside a parenthesis. | |
68 | * Add *args **kwargs to syhunt plugin | |
69 | * fix bug when grype report has no arifact/metadata | |
70 | * [MOD] Now prowler plugin returns CAF Epic as policy violation and | |
71 | remove [check#] from tittle | |
72 | ||
73 | 1.6.8 [Jul 25th, 2022]: | |
74 | --- | |
75 | * Add appscan csv | |
76 | * Now faraday_csv's plugin uses ignore_info parameter | |
77 | * Add syhunt plugin | |
78 | * Add cve and data fields to desc for avoid duplications | |
79 | * Now nuclei resolve hostname if the field ip is None | |
80 | ||
81 | 1.6.7 [Jun 2nd, 2022]: | |
82 | --- | |
83 | * Change hostname_restolution to dont_resolve_hostname for process-report and now test dosent resovle hostname | |
84 | * Now QualysWebApp's plugin will diferenciate vulns from differents urlpaths | |
85 | ||
86 | 1.6.6 [May 20th, 2022]: | |
87 | --- | |
88 | * Add hostname_resolution parameter within plugins | |
89 | * Fix openvas external ID | |
90 | ||
91 | 1.6.5 [Apr 28th, 2022]: | |
92 | --- | |
93 | * Now Openvas's plugin set severity to Critical when cvss >= 9.0 | |
94 | ||
95 | 1.6.4 [Apr 21th, 2022]: | |
96 | --- | |
97 | * Add location as params in burp's plugin | |
98 | * Now the faraday_csv custom_fields regex match any no whitespace character. | |
99 | ||
100 | 1.6.3 [Apr 19th, 2022]: | |
101 | --- | |
102 | * Add Zap Json plugin. | |
103 | ||
104 | 1.6.2 [Apr 4th, 2022]: | |
105 | --- | |
106 | * Now Appscan plugin saves line and highlight of the vulns in desc and data | |
107 | ||
108 | 1.6.1 [Mar 18th, 2022]: | |
109 | --- | |
110 | * Add references tu burp plugin | |
111 | * Move item.detail from data to desc | |
112 | * update open status | |
113 | ||
114 | 1.6.0 [Feb 3rd, 2022]: | |
115 | --- | |
116 | * Add packaging to requierments in setup.py | |
117 | * Add severity to shodan's plugins using cvss | |
118 | * check if cve exist on cve-id field | |
119 | * Fix Fortify's plugin | |
120 | * Change qualysguard's plugin severity_dict to refer level 2 severities as low | |
121 | ||
122 | 1.5.10 [Jan 13th, 2022]: | |
123 | --- | |
124 | * support cve,cwe,cvss and metadata | |
125 | ||
126 | 1.5.9 [Dec 27th, 2021]: | |
127 | --- | |
128 | * Add cve in faraday_csv plugin | |
129 | * ADD Grype plugin | |
130 | ||
131 | 1.5.8 [Dec 13th, 2021]: | |
132 | --- | |
133 | * Add CVE to plugins | |
134 | - acunetix | |
135 | - appscan | |
136 | - burp | |
137 | - metasploit | |
138 | - nessus | |
139 | - netsparker | |
140 | - nexpose | |
141 | - nikto | |
142 | - nipper | |
143 | - nmap | |
144 | - openscap | |
145 | - qualysguard | |
146 | - retina | |
147 | - shodan | |
148 | * Add support for Sslyze 5.0 resports | |
149 | * Fix errors while creating hosts with wrong regex | |
150 | * ADD masscan support to nmap plugin | |
151 | * Fix bug in openvas plugin | |
152 | ||
153 | 1.5.7 [Nov 19th, 2021]: | |
154 | --- | |
155 | * FIX extrainfo of netsparker plugin | |
156 | * Add nuclei_legacy plugin | |
157 | ||
158 | 1.5.6 [Nov 10th, 2021]: | |
159 | --- | |
160 | * FIX issue with acunetix plugin | |
161 | ||
162 | * FIX typo in nikto plugin | |
163 | ||
164 | 1.5.5 [Oct 21st, 2021]: | |
165 | --- | |
166 | * Merge PR from github | |
167 | ||
168 | 1.5.4 [Oct 19th, 2021]: | |
169 | --- | |
170 | * Update nuclei parser | |
171 | ||
172 | 1.5.3 [Sep 7th, 2021]: | |
173 | --- | |
174 | * Adding support for running nuclei through command / faraday-cli | |
175 | * Fix missing references in nuclei | |
176 | ||
177 | 1.5.2 [Aug 9th, 2021]: | |
178 | --- | |
179 | * add new structure acunetix | |
180 | ||
181 | 1.5.1 [Jul 27th, 2021]: | |
182 | --- | |
183 | * cwe, capec, references, tags, impact, resolution, easeofresolution | |
184 | * add os openvas | |
185 | * [FIX] Fix improt of CSV with big fields | |
186 | * Fix sslyze json bug with port | |
187 | * Only show report name in command data | |
188 | ||
189 | 1.5.0 [Jun 28th, 2021]: | |
190 | --- | |
191 | * Add Nipper Plugin | |
192 | * add shodan plugin | |
193 | * fix acunetix url parser | |
194 | * FIX netsparker multi-host | |
195 | * Add vuln details for Certificate Mismatch and move unique details to data, now vulns can be grupped | |
196 | * ADD more data to plugins arachni and w3af | |
197 | * Use run_date in UTC | |
198 | * ADD cvss_base, cpe, threat, severity into references | |
199 | ||
200 | 1.4.6 [May 14th, 2021]: | |
201 | --- | |
202 | * - add attribute "command" for the pluggins of each command | |
203 | - adding test in test_command | |
204 | - change some regex in self._command_regex | |
205 | * [FIX] add hostnames if host is already cached | |
206 | * Add Naabu plugin | |
207 | * Add Sonarqube plugin | |
208 | * Add version and change list_plugins style | |
209 | * FIX unused import, innecesary list compression and unused variables | |
210 | * FIX metasploit report when the web-site-id is null | |
211 | * Fix port stats in nmap | |
212 | * fixup ssylze | |
213 | sacar unknown de version= | |
214 | * ADD remedy into resolution | |
215 | * Support for nuclei 2.3.0 | |
216 | * ADD cve, cvss3_base_score, cvss3_vector, exploit_available when import nessus and change the structure of external_id to NESSUS-XXX | |
217 | * ADD more data like attack, params, uri, method, WASC, CWE and format externail_id | |
218 | ||
219 | 1.4.5 [Apr 15th, 2021]: | |
220 | --- | |
221 | * Add Bandit plugin | |
222 | * Use background for description and detail for data en Burp plugin. | |
223 | * Rewrite Appscan Plugin | |
224 | * Parse Nmap vulners script data | |
225 | ||
226 | 1.4.4 [Mar 30th, 2021]: | |
227 | --- | |
228 | * Faraday CSV Plugin do not consider ignore_info | |
229 | ||
230 | 1.4.3 [Mar 17th, 2021]: | |
231 | --- | |
232 | * Add Ignore information vulnerabilities option | |
233 | ||
234 | 1.4.2 [Mar 10th, 2021]: | |
235 | --- | |
236 | * Fix bug with sslyze output file | |
237 | * FIX change id sslyze for JSON/XML | |
238 | ||
239 | 1.4.1 [Feb 26th, 2021]: | |
240 | --- | |
241 | * ADD microsoft baseline security analyzer plugin | |
242 | * ADD nextnet plugin | |
243 | * ADD openscap plugin | |
244 | * FIX old versions of Nessus plugins bugs | |
245 | ||
246 | 1.4.0 [Dec 23rd, 2020]: | |
247 | --- | |
248 | * Update the fields of the nuclei output used to create a vuln | |
249 | ||
250 | 1.4.0b2 [Dec 15th, 2020]: | |
251 | --- | |
252 | * Fix nuclei plugin bug when url is None | |
253 | ||
254 | 1.4.0b1 [Dec 14th, 2020]: | |
255 | --- | |
256 | * Add new plugin base class, for multi line json | |
257 | * New ncrack plugin | |
258 | * New nuclei plugin | |
259 | * New sslyze json plugin | |
260 | * New WhatWeb plugin | |
261 | * Fix missing ip in some arachni reports | |
262 | * Fix change name vuln in Netsparker plugin | |
263 | * Fix whois plugin, command whois IP not parse data | |
264 | * Change the way we detect json reports when they are lists of dictionaries | |
265 | ||
266 | 1.3.0 [Sep 2nd, 2020]: | |
267 | --- | |
268 | * ADD plugin AppSpider | |
269 | * Add tests to faraday-plugins cli | |
270 | * add a default value to plugin_version | |
271 | * Add --output-file parameter to faraday-plugins process command | |
272 | * Add plugins prowler | |
273 | * Add plugins ssl labs | |
274 | * Add support for tenable io | |
275 | * delete old deprecated methods | |
276 | * Bug fix: Arachni Plugin 'NoneType' object has no attribute 'find' | |
277 | * Bug fix: Openvas Plugin - Import xml from OpenVas doesnt work | |
278 | * Bug fix: QualysWebApp Plugin, error in get info OPERATING_SYSTEM | |
279 | * Fix Hydra plugin to resolve ip address | |
280 | * Fix Nessus mod severity HIGH for Low | |
281 | * Bug Fix: Detect plugins AWS Prowler | |
282 | * Fix broken xml on nmap plugin | |
283 | * Add new rdpscan plugin | |
284 | * UPDATE xml report to appscan | |
285 | * Update Readme | |
286 | * Fix how ZAP genereate vulns | |
287 |
0 | with import <nixpkgs> {}; | |
1 | pkgs.python38Packages.buildPythonPackage rec { | |
2 | name = "env"; | |
3 | ||
4 | env = buildEnv { name = name; paths = buildInputs; }; | |
5 | ||
6 | buildInputs = [ | |
7 | (python38.buildEnv.override { | |
8 | ignoreCollisions = true; | |
9 | extraLibs = with python38Packages; [ | |
10 | requests | |
11 | click | |
12 | simplejson | |
13 | requests | |
14 | lxml | |
15 | html2text | |
16 | beautifulsoup4 | |
17 | pytz | |
18 | python-dateutil | |
19 | colorama | |
20 | ]; | |
21 | }) | |
22 | ]; | |
23 | } |
0 | ## Write you own plugins | |
1 | ||
2 | > XML report plugin | |
3 | ||
4 | ```python | |
5 | class XXXPLugin(PluginXMLFormat): | |
6 | ||
7 | def __init__(self, *args, **kwargs): | |
8 | super().__init__(*args, **kwargs) | |
9 | # Tags to be compared with the xml mail tag, can be a list or a string | |
10 | self.identifier_tag = ["tag1", "tag2"] | |
11 | self.id = 'SOME_PLUGIN_ID' # Can't be repeated | |
12 | self.name = 'Some plugin name' | |
13 | self.plugin_version = 'X.X' | |
14 | # The extension is optional, only if its different than xml | |
15 | self.extension = ".xxx" | |
16 | ``` | |
17 | ||
18 | > JSON report plugin | |
19 | ||
20 | ```python | |
21 | class XXXPLugin(PluginJsonFormat): | |
22 | ||
23 | def __init__(self, *args, **kwargs): | |
24 | super().__init__(*args, **kwargs) | |
25 | # keys of the json that identify the report | |
26 | # you don't need to put all the keys, just some of them | |
27 | # it must be a set and will be compared as a subset of the json report keys | |
28 | self.json_keys = {"target_url", "effective_url", "interesting_findings"} | |
29 | self.id = 'SOME_PLUGIN_ID' # Can't be repeated | |
30 | self.name = 'Some plugin name' | |
31 | self.plugin_version = 'X.X' | |
32 | # The extension is optional, only if its different than json | |
33 | self.extension = ".xxx" | |
34 | ``` |
52 | 52 | click.echo(tabulate( |
53 | 53 | plugins_data, |
54 | 54 | headers="keys", |
55 | tablefmt="simple", | |
55 | tablefmt="github", | |
56 | 56 | )) |
57 | 57 | click.echo(click.style(f"Loaded Plugins: {len(plugins_data)}", fg="cyan")) |
58 | 58 |
400 | 400 | ports = int(ports[0]) |
401 | 401 | elif isinstance(ports, str): |
402 | 402 | ports = int(ports) |
403 | ||
403 | if not protocol: | |
404 | protocol = "tcp" | |
404 | 405 | if status not in VALID_SERVICE_STATUS: |
405 | 406 | status = 'open' |
406 | 407 | if tags is None: |
493 | 494 | def createAndAddVulnToService(self, host_id, service_id, name, desc="", |
494 | 495 | ref=None, severity="", resolution="", data="", external_id=None, run_date=None, |
495 | 496 | custom_fields=None, policyviolations=None, impact=None, status="", |
496 | confirmed=False, easeofresolution=None, tags=None, cve=None, cwe=None,cvss2=None, | |
497 | confirmed=False, easeofresolution=None, tags=None, cve=None, cwe=None, cvss2=None, | |
497 | 498 | cvss3=None): |
498 | 499 | ref = self.modify_refs_struct(ref) |
499 | 500 | if status == "": |
738 | 739 | def __init__(self, *args, **kwargs): |
739 | 740 | super().__init__(*args, **kwargs) |
740 | 741 | self.json_keys = set() |
742 | self.filter_keys = set() | |
741 | 743 | self.extension = ".json" |
742 | 744 | |
743 | 745 | def report_belongs_to(self, file_json_keys=None, **kwargs): |
745 | 747 | if super().report_belongs_to(**kwargs): |
746 | 748 | if file_json_keys is None: |
747 | 749 | file_json_keys = set() |
750 | if self.filter_keys & file_json_keys: | |
751 | return match | |
748 | 752 | if isinstance(self.json_keys, list): |
749 | 753 | for jk in self.json_keys: |
750 | 754 | match = jk.issubset(file_json_keys) |
0 | from typing import List | |
1 | import re | |
2 | ||
3 | from faraday_plugins.plugins.plugins_utils import CVE_regex | |
4 | ||
5 | CVE_WITH_P_regex = re.compile(r'\(CVE-\d{4}-\d{4,7}\)') | |
6 | ||
7 | ||
8 | class Service: | |
9 | def __init__(self, node): | |
10 | self.node = node | |
11 | ||
12 | @property | |
13 | def name(self): | |
14 | return self.node.get("name", "") | |
15 | ||
16 | @property | |
17 | def port(self): | |
18 | return self.node.get("port", "") | |
19 | ||
20 | @property | |
21 | def protocol(self): | |
22 | return self.node.get("transport", "") | |
23 | ||
24 | @property | |
25 | def status(self) -> str: | |
26 | return self.node.get("status", "") | |
27 | ||
28 | ||
29 | class Host: | |
30 | def __init__(self, node): | |
31 | self.node = node | |
32 | ||
33 | @property | |
34 | def host_id(self) -> str: | |
35 | return self.node.get("id", "") | |
36 | ||
37 | @property | |
38 | def hostname(self) -> str: | |
39 | return self.node.get("hostname", "") | |
40 | ||
41 | @property | |
42 | def name(self) -> str: | |
43 | return self.node.get("ip", "") | |
44 | ||
45 | @property | |
46 | def os(self) -> str: | |
47 | return self.node.get("os_name", "") | |
48 | ||
49 | @property | |
50 | def services(self) -> List[Service]: | |
51 | return [Service(ser) for ser in self.node.get("services", "")] | |
52 | ||
53 | ||
54 | class Vulneravility: | |
55 | def __init__(self, node): | |
56 | self.node = node | |
57 | ||
58 | @property | |
59 | def external_id(self) -> str: | |
60 | return "Pentera-"+self.node.get("id", "") | |
61 | ||
62 | @property | |
63 | def name(self) -> str: | |
64 | return CVE_WITH_P_regex.sub("", self.node.get("name", "")).strip() | |
65 | ||
66 | @property | |
67 | def description(self) -> str: | |
68 | desc = self.node.get("summary", "") | |
69 | if not desc: | |
70 | desc = self.name | |
71 | return desc | |
72 | ||
73 | @property | |
74 | def found_on(self) -> str: | |
75 | return self.node.get("found_on", "") | |
76 | ||
77 | @property | |
78 | def host(self) -> str: | |
79 | return self.node.get("target", "") | |
80 | ||
81 | @property | |
82 | def host_id(self) -> str: | |
83 | return self.node.get("target_id", "") | |
84 | ||
85 | @property | |
86 | def port(self) -> str: | |
87 | return self.node.get("port", "") | |
88 | ||
89 | @property | |
90 | def protocol(self) -> str: | |
91 | return self.node.get("protocol", "") | |
92 | ||
93 | @property | |
94 | def severity(self) -> float: | |
95 | return float(self.node.get("severity", 0)) | |
96 | ||
97 | @property | |
98 | def data(self) -> str: | |
99 | return self.node.get("insight", "") | |
100 | ||
101 | @property | |
102 | def resolution(self) -> str: | |
103 | return self.node.get("remediation", "") | |
104 | ||
105 | @property | |
106 | def cve(self) -> str: | |
107 | return CVE_regex.sub("", self.node.get("name", "")).strip() | |
108 | class Achievment: | |
109 | def __init__(self, node): | |
110 | self.node = node | |
111 | ||
112 | ||
113 | class Meta: | |
114 | def __init__(self, node): | |
115 | self.node = node | |
116 | ||
117 | ||
118 | class PenteraJsonParser: | |
119 | def __init__(self, node): | |
120 | self.node = node | |
121 | ||
122 | @property | |
123 | def meta(self) -> Meta: | |
124 | return Meta(self.node.get('meta', {})) | |
125 | ||
126 | @property | |
127 | def achievements(self) -> List[Achievment]: | |
128 | return [Achievment(i) for i in self.node.get('Achievement', [])] | |
129 | ||
130 | @property | |
131 | def vulneravilities(self) -> List[Vulneravility]: | |
132 | return [Vulneravility(i) for i in self.node.get('vulnerabilities', [])] | |
133 | ||
134 | @property | |
135 | def hosts(self) -> List[Host]: | |
136 | return [Host(i) for i in self.node.get('hosts')] |
0 | """ | |
1 | Faraday Penetration Test IDE | |
2 | Copyright (C) 2013 Infobyte LLC (http://www.infobytesec.com/) | |
3 | See the file 'doc/LICENSE' for the license information | |
4 | ||
5 | """ |
0 | """ | |
1 | Faraday Penetration Test IDE | |
2 | Copyright (C) 2013 Infobyte LLC (http://www.infobytesec.com/) | |
3 | See the file 'doc/LICENSE' for the license information | |
4 | """ | |
5 | from json import loads | |
6 | ||
7 | from faraday_plugins.plugins.plugin import PluginJsonFormat | |
8 | from faraday_plugins.plugins.repo.pentera.DTO import PenteraJsonParser | |
9 | ||
10 | __author__ = "Gonzalo Martinez" | |
11 | __copyright__ = "Copyright (c) 2013, Infobyte LLC" | |
12 | __credits__ = ["Gonzalo Martinez"] | |
13 | __license__ = "" | |
14 | __version__ = "1.0.0" | |
15 | __maintainer__ = "Gonzalo Martinez" | |
16 | __email__ = "[email protected]" | |
17 | __status__ = "Development" | |
18 | ||
19 | ||
20 | ||
21 | ||
22 | ||
23 | class PenteraJsonPlugin(PluginJsonFormat): | |
24 | ||
25 | def __init__(self, *arg, **kwargs): | |
26 | super().__init__(*arg, **kwargs) | |
27 | self.id = "Pentera_Json" | |
28 | self.name = "Pentera Json Output Plugin" | |
29 | self.plugin_version = "1.0.0" | |
30 | self.version = "2.11.1" | |
31 | self.framework_version = "1.0.0" | |
32 | self.options = None | |
33 | self._temp_file_extension = "json" | |
34 | self.json_keys = {'vulnerabilities', 'hosts'} | |
35 | ||
36 | @staticmethod | |
37 | def pentera_to_severity_level(pentera_score): | |
38 | pentera_ranges = [(0.0, 0.01, 'info'), | |
39 | (0.01, 2.5, 'low'), | |
40 | (2.5, 4.5, 'med'), | |
41 | (5, 7.49, 'high'), | |
42 | (7.5, 10.1, 'critical')] | |
43 | for (lower, upper, severity) in pentera_ranges: | |
44 | if lower <= pentera_score < upper: | |
45 | return severity | |
46 | ||
47 | def parseOutputString(self, output): | |
48 | """ | |
49 | This method will discard the output the shell sends, it will read it | |
50 | from the json where it expects it to be present. | |
51 | """ | |
52 | ||
53 | parser = PenteraJsonParser(loads(output)) | |
54 | host_dict = {} | |
55 | ||
56 | for host in parser.hosts: | |
57 | host_id = self.createAndAddHost( | |
58 | name=host.name, | |
59 | os=host.os, | |
60 | hostnames=[host.hostname] | |
61 | ) | |
62 | host_dict[host.host_id] = {} | |
63 | for service in host.services: | |
64 | service_id = self.createAndAddServiceToHost( | |
65 | host_id=host_id, | |
66 | name=service.name, | |
67 | protocol=service.protocol, | |
68 | ports=service.port, | |
69 | status=service.status | |
70 | ) | |
71 | host_dict[host.host_id][service.port] = [host_id, service_id] | |
72 | for vuln in parser.vulneravilities: | |
73 | try: | |
74 | self.createAndAddVulnToService( | |
75 | host_id=host_dict[vuln.host_id][vuln.port][0], | |
76 | service_id=host_dict[vuln.host_id][vuln.port][1], | |
77 | name=vuln.name, | |
78 | desc=vuln.description, | |
79 | severity=self.pentera_to_severity_level(vuln.severity), | |
80 | resolution=vuln.resolution, | |
81 | data=vuln.data, | |
82 | external_id=vuln.external_id, | |
83 | cve=vuln.cve | |
84 | ) | |
85 | except KeyError: | |
86 | if "host" in vuln.found_on.lower(): | |
87 | host = vuln.found_on.lower().replace("host:", "").strip().split(",")[0] | |
88 | else: | |
89 | host = "NOT-PROVIDED" | |
90 | host_id = self.createAndAddHost( | |
91 | name=host, | |
92 | ) | |
93 | self.createAndAddVulnToHost( | |
94 | host_id=host_id, | |
95 | name=vuln.name, | |
96 | desc=vuln.description, | |
97 | severity=self.pentera_to_severity_level(vuln.severity), | |
98 | resolution=vuln.resolution, | |
99 | data=vuln.data, | |
100 | external_id=vuln.external_id, | |
101 | cve=vuln.cve | |
102 | ) | |
103 | ||
104 | ||
105 | def createPlugin(*args, **kwargs): | |
106 | return PenteraJsonPlugin(*args, **kwargs) |
29 | 29 | self.plugin_version = "0.1" |
30 | 30 | self.version = "3.4.5" |
31 | 31 | self.json_keys = {"vulnerabilities"} |
32 | self.filter_keys = {"host"} | |
32 | 33 | |
33 | 34 | def parseOutputString(self, output): |
34 | 35 | parser = json.loads(output) |
0 | Metadata-Version: 2.1 | |
1 | Name: faraday-plugins | |
2 | Version: 1.9.0 | |
3 | Summary: Faraday plugins package | |
4 | Home-page: | |
5 | Author: Faradaysec | |
6 | Author-email: [email protected] | |
7 | License: GNU General Public License v3 | |
8 | License-File: COPYING |
0 | COPYING | |
1 | MANIFEST.in | |
2 | README.md | |
3 | setup.py | |
4 | faraday_plugins/__init__.py | |
5 | faraday_plugins/__main__.py | |
6 | faraday_plugins/commands.py | |
7 | faraday_plugins.egg-info/PKG-INFO | |
8 | faraday_plugins.egg-info/SOURCES.txt | |
9 | faraday_plugins.egg-info/dependency_links.txt | |
10 | faraday_plugins.egg-info/entry_points.txt | |
11 | faraday_plugins.egg-info/requires.txt | |
12 | faraday_plugins.egg-info/top_level.txt | |
13 | faraday_plugins/plugins/__init__.py | |
14 | faraday_plugins/plugins/manager.py | |
15 | faraday_plugins/plugins/plugin.py | |
16 | faraday_plugins/plugins/plugins_utils.py | |
17 | faraday_plugins/plugins/port_mapper.txt | |
18 | faraday_plugins/plugins/repo/__init__.py | |
19 | faraday_plugins/plugins/repo/acunetix/DTO.py | |
20 | faraday_plugins/plugins/repo/acunetix/__init__.py | |
21 | faraday_plugins/plugins/repo/acunetix/plugin.py | |
22 | faraday_plugins/plugins/repo/acunetix_json/DTO.py | |
23 | faraday_plugins/plugins/repo/acunetix_json/__init__.py | |
24 | faraday_plugins/plugins/repo/acunetix_json/plugin.py | |
25 | faraday_plugins/plugins/repo/amap/__init__.py | |
26 | faraday_plugins/plugins/repo/amap/plugin.py | |
27 | faraday_plugins/plugins/repo/appscan/__init__.py | |
28 | faraday_plugins/plugins/repo/appscan/plugin.py | |
29 | faraday_plugins/plugins/repo/appscan_csv/__init__.py | |
30 | faraday_plugins/plugins/repo/appscan_csv/plugin.py | |
31 | faraday_plugins/plugins/repo/appspider/__init__.py | |
32 | faraday_plugins/plugins/repo/appspider/plugin.py | |
33 | faraday_plugins/plugins/repo/arachni/__init__.py | |
34 | faraday_plugins/plugins/repo/arachni/plugin.py | |
35 | faraday_plugins/plugins/repo/arp_scan/__init__.py | |
36 | faraday_plugins/plugins/repo/arp_scan/plugin.py | |
37 | faraday_plugins/plugins/repo/bandit/__init__.py | |
38 | faraday_plugins/plugins/repo/bandit/plugin.py | |
39 | faraday_plugins/plugins/repo/beef/__init__.py | |
40 | faraday_plugins/plugins/repo/beef/plugin.py | |
41 | faraday_plugins/plugins/repo/brutexss/__init__.py | |
42 | faraday_plugins/plugins/repo/brutexss/plugin.py | |
43 | faraday_plugins/plugins/repo/burp/__init__.py | |
44 | faraday_plugins/plugins/repo/burp/plugin.py | |
45 | faraday_plugins/plugins/repo/checkmarx/__init__.py | |
46 | faraday_plugins/plugins/repo/checkmarx/plugin.py | |
47 | faraday_plugins/plugins/repo/cobalt/__init__.py | |
48 | faraday_plugins/plugins/repo/cobalt/plugin.py | |
49 | faraday_plugins/plugins/repo/dig/__init__.py | |
50 | faraday_plugins/plugins/repo/dig/plugin.py | |
51 | faraday_plugins/plugins/repo/dirb/__init__.py | |
52 | faraday_plugins/plugins/repo/dirb/plugin.py | |
53 | faraday_plugins/plugins/repo/dirsearch/__init__.py | |
54 | faraday_plugins/plugins/repo/dirsearch/plugin.py | |
55 | faraday_plugins/plugins/repo/dnsenum/__init__.py | |
56 | faraday_plugins/plugins/repo/dnsenum/plugin.py | |
57 | faraday_plugins/plugins/repo/dnsmap/__init__.py | |
58 | faraday_plugins/plugins/repo/dnsmap/plugin.py | |
59 | faraday_plugins/plugins/repo/dnsrecon/__init__.py | |
60 | faraday_plugins/plugins/repo/dnsrecon/plugin.py | |
61 | faraday_plugins/plugins/repo/dnswalk/__init__.py | |
62 | faraday_plugins/plugins/repo/dnswalk/plugin.py | |
63 | faraday_plugins/plugins/repo/faraday_csv/__init__.py | |
64 | faraday_plugins/plugins/repo/faraday_csv/plugin.py | |
65 | faraday_plugins/plugins/repo/fierce/__init__.py | |
66 | faraday_plugins/plugins/repo/fierce/plugin.py | |
67 | faraday_plugins/plugins/repo/fortify/__init__.py | |
68 | faraday_plugins/plugins/repo/fortify/plugin.py | |
69 | faraday_plugins/plugins/repo/ftp/__init__.py | |
70 | faraday_plugins/plugins/repo/ftp/plugin.py | |
71 | faraday_plugins/plugins/repo/goohost/__init__.py | |
72 | faraday_plugins/plugins/repo/goohost/plugin.py | |
73 | faraday_plugins/plugins/repo/grype/__init__.py | |
74 | faraday_plugins/plugins/repo/grype/plugin.py | |
75 | faraday_plugins/plugins/repo/hping3/__init__.py | |
76 | faraday_plugins/plugins/repo/hping3/plugin.py | |
77 | faraday_plugins/plugins/repo/hydra/__init__.py | |
78 | faraday_plugins/plugins/repo/hydra/plugin.py | |
79 | faraday_plugins/plugins/repo/impact/__init__.py | |
80 | faraday_plugins/plugins/repo/impact/plugin.py | |
81 | faraday_plugins/plugins/repo/invicti/DTO.py | |
82 | faraday_plugins/plugins/repo/invicti/__init__.py | |
83 | faraday_plugins/plugins/repo/invicti/plugin.py | |
84 | faraday_plugins/plugins/repo/ip360/__init__.py | |
85 | faraday_plugins/plugins/repo/ip360/plugin.py | |
86 | faraday_plugins/plugins/repo/junit/__init__.py | |
87 | faraday_plugins/plugins/repo/junit/plugin.py | |
88 | faraday_plugins/plugins/repo/lynis/__init__.py | |
89 | faraday_plugins/plugins/repo/lynis/plugin.py | |
90 | faraday_plugins/plugins/repo/maltego/__init__.py | |
91 | faraday_plugins/plugins/repo/maltego/plugin.py | |
92 | faraday_plugins/plugins/repo/mbsa/__init__.py | |
93 | faraday_plugins/plugins/repo/mbsa/plugin.py | |
94 | faraday_plugins/plugins/repo/medusa/__init__.py | |
95 | faraday_plugins/plugins/repo/medusa/plugin.py | |
96 | faraday_plugins/plugins/repo/metasploit/__init__.py | |
97 | faraday_plugins/plugins/repo/metasploit/plugin.py | |
98 | faraday_plugins/plugins/repo/naabu/__init__.py | |
99 | faraday_plugins/plugins/repo/naabu/plugin.py | |
100 | faraday_plugins/plugins/repo/ncrack/__init__.py | |
101 | faraday_plugins/plugins/repo/ncrack/plugin.py | |
102 | faraday_plugins/plugins/repo/ndiff/__init__.py | |
103 | faraday_plugins/plugins/repo/ndiff/plugin.py | |
104 | faraday_plugins/plugins/repo/nessus/DTO.py | |
105 | faraday_plugins/plugins/repo/nessus/__init__.py | |
106 | faraday_plugins/plugins/repo/nessus/plugin.py | |
107 | faraday_plugins/plugins/repo/nessus_sc/__init__.py | |
108 | faraday_plugins/plugins/repo/nessus_sc/plugin.py | |
109 | faraday_plugins/plugins/repo/netdiscover/__init__.py | |
110 | faraday_plugins/plugins/repo/netdiscover/plugin.py | |
111 | faraday_plugins/plugins/repo/netsparker/__init__.py | |
112 | faraday_plugins/plugins/repo/netsparker/plugin.py | |
113 | faraday_plugins/plugins/repo/netsparkercloud/__init__.py | |
114 | faraday_plugins/plugins/repo/netsparkercloud/plugin.py | |
115 | faraday_plugins/plugins/repo/nexpose_full/__init__.py | |
116 | faraday_plugins/plugins/repo/nexpose_full/plugin.py | |
117 | faraday_plugins/plugins/repo/nextnet/__init__.py | |
118 | faraday_plugins/plugins/repo/nextnet/plugin.py | |
119 | faraday_plugins/plugins/repo/nikto/__init__.py | |
120 | faraday_plugins/plugins/repo/nikto/plugin.py | |
121 | faraday_plugins/plugins/repo/nipper/__init__.py | |
122 | faraday_plugins/plugins/repo/nipper/plugin.py | |
123 | faraday_plugins/plugins/repo/nmap/__init__.py | |
124 | faraday_plugins/plugins/repo/nmap/plugin.py | |
125 | faraday_plugins/plugins/repo/nuclei/__init__.py | |
126 | faraday_plugins/plugins/repo/nuclei/plugin.py | |
127 | faraday_plugins/plugins/repo/nuclei_legacy/__init__.py | |
128 | faraday_plugins/plugins/repo/nuclei_legacy/plugin.py | |
129 | faraday_plugins/plugins/repo/openscap/__init__.py | |
130 | faraday_plugins/plugins/repo/openscap/plugin.py | |
131 | faraday_plugins/plugins/repo/openvas/__init__.py | |
132 | faraday_plugins/plugins/repo/openvas/plugin.py | |
133 | faraday_plugins/plugins/repo/pasteanalyzer/__init__.py | |
134 | faraday_plugins/plugins/repo/pasteanalyzer/plugin.py | |
135 | faraday_plugins/plugins/repo/peepingtom/__init__.py | |
136 | faraday_plugins/plugins/repo/peepingtom/plugin.py | |
137 | faraday_plugins/plugins/repo/pentera/DTO.py | |
138 | faraday_plugins/plugins/repo/pentera/__init__.py | |
139 | faraday_plugins/plugins/repo/pentera/plugin.py | |
140 | faraday_plugins/plugins/repo/ping/__init__.py | |
141 | faraday_plugins/plugins/repo/ping/plugin.py | |
142 | faraday_plugins/plugins/repo/propecia/__init__.py | |
143 | faraday_plugins/plugins/repo/propecia/plugin.py | |
144 | faraday_plugins/plugins/repo/prowler/__init__.py | |
145 | faraday_plugins/plugins/repo/prowler/plugin.py | |
146 | faraday_plugins/plugins/repo/qualysguard/__init__.py | |
147 | faraday_plugins/plugins/repo/qualysguard/plugin.py | |
148 | faraday_plugins/plugins/repo/qualyswebapp/__init__.py | |
149 | faraday_plugins/plugins/repo/qualyswebapp/plugin.py | |
150 | faraday_plugins/plugins/repo/rdpscan/__init__.py | |
151 | faraday_plugins/plugins/repo/rdpscan/plugin.py | |
152 | faraday_plugins/plugins/repo/reconng/__init__.py | |
153 | faraday_plugins/plugins/repo/reconng/plugin.py | |
154 | faraday_plugins/plugins/repo/retina/__init__.py | |
155 | faraday_plugins/plugins/repo/retina/plugin.py | |
156 | faraday_plugins/plugins/repo/reverseraider/__init__.py | |
157 | faraday_plugins/plugins/repo/reverseraider/plugin.py | |
158 | faraday_plugins/plugins/repo/shodan/__init__.py | |
159 | faraday_plugins/plugins/repo/shodan/plugin.py | |
160 | faraday_plugins/plugins/repo/skipfish/__init__.py | |
161 | faraday_plugins/plugins/repo/skipfish/plugin.py | |
162 | faraday_plugins/plugins/repo/sonarqubeapi/__init__.py | |
163 | faraday_plugins/plugins/repo/sonarqubeapi/plugin.py | |
164 | faraday_plugins/plugins/repo/sourceclear/__init__.py | |
165 | faraday_plugins/plugins/repo/sourceclear/plugin.py | |
166 | faraday_plugins/plugins/repo/sshdefaultscan/__init__.py | |
167 | faraday_plugins/plugins/repo/sshdefaultscan/plugin.py | |
168 | faraday_plugins/plugins/repo/ssl_labs/__init__.py | |
169 | faraday_plugins/plugins/repo/ssl_labs/plugin.py | |
170 | faraday_plugins/plugins/repo/sslyze/__init__.py | |
171 | faraday_plugins/plugins/repo/sslyze/plugin.py | |
172 | faraday_plugins/plugins/repo/sslyzejson/__init__.py | |
173 | faraday_plugins/plugins/repo/sslyzejson/plugin.py | |
174 | faraday_plugins/plugins/repo/syhunt/__init__.py | |
175 | faraday_plugins/plugins/repo/syhunt/plugin.py | |
176 | faraday_plugins/plugins/repo/telnet/__init__.py | |
177 | faraday_plugins/plugins/repo/telnet/plugin.py | |
178 | faraday_plugins/plugins/repo/theharvester/__init__.py | |
179 | faraday_plugins/plugins/repo/theharvester/plugin.py | |
180 | faraday_plugins/plugins/repo/traceroute/__init__.py | |
181 | faraday_plugins/plugins/repo/traceroute/plugin.py | |
182 | faraday_plugins/plugins/repo/trivy_json/DTO.py | |
183 | faraday_plugins/plugins/repo/trivy_json/__init__.py | |
184 | faraday_plugins/plugins/repo/trivy_json/plugin.py | |
185 | faraday_plugins/plugins/repo/w3af/__init__.py | |
186 | faraday_plugins/plugins/repo/w3af/plugin.py | |
187 | faraday_plugins/plugins/repo/wapiti/__init__.py | |
188 | faraday_plugins/plugins/repo/wapiti/plugin.py | |
189 | faraday_plugins/plugins/repo/wcscan/__init__.py | |
190 | faraday_plugins/plugins/repo/wcscan/plugin.py | |
191 | faraday_plugins/plugins/repo/webfuzzer/__init__.py | |
192 | faraday_plugins/plugins/repo/webfuzzer/plugin.py | |
193 | faraday_plugins/plugins/repo/webinspect/__init__.py | |
194 | faraday_plugins/plugins/repo/webinspect/plugin.py | |
195 | faraday_plugins/plugins/repo/wfuzz/__init__.py | |
196 | faraday_plugins/plugins/repo/wfuzz/plugin.py | |
197 | faraday_plugins/plugins/repo/whatweb/__init__.py | |
198 | faraday_plugins/plugins/repo/whatweb/plugin.py | |
199 | faraday_plugins/plugins/repo/whitesource/__init__.py | |
200 | faraday_plugins/plugins/repo/whitesource/plugin.py | |
201 | faraday_plugins/plugins/repo/whois/__init__.py | |
202 | faraday_plugins/plugins/repo/whois/plugin.py | |
203 | faraday_plugins/plugins/repo/wpscan/__init__.py | |
204 | faraday_plugins/plugins/repo/wpscan/plugin.py | |
205 | faraday_plugins/plugins/repo/x1/__init__.py | |
206 | faraday_plugins/plugins/repo/x1/plugin.py | |
207 | faraday_plugins/plugins/repo/xsssniper/__init__.py | |
208 | faraday_plugins/plugins/repo/xsssniper/plugin.py | |
209 | faraday_plugins/plugins/repo/zap/__init__.py | |
210 | faraday_plugins/plugins/repo/zap/plugin.py | |
211 | faraday_plugins/plugins/repo/zap_json/DTO.py | |
212 | faraday_plugins/plugins/repo/zap_json/__init__.py | |
213 | faraday_plugins/plugins/repo/zap_json/plugin.py⏎ |
0 | Click | |
1 | beautifulsoup4 | |
2 | colorama | |
3 | html2text | |
4 | lxml | |
5 | packaging | |
6 | python-dateutil | |
7 | pytz | |
8 | requests | |
9 | simplejson | |
10 | tabulate |
0 | faraday_plugins |
0 | { | |
1 | "commands": [ | |
2 | {"plugin_id": "ping", "command": "ping -c4 faradaysec.com", "command_result": "ping"}, | |
3 | {"plugin_id": "whois", "command": "whois fradaysec.com", "command_result": "whois"}, | |
4 | {"plugin_id": "nmap", "command": "nmap fradaysec.com", "command_result": "nmap"}, | |
5 | {"plugin_id": "skipfish", "command": "skipfish http://fradaysec.com", "command_result": "skipfish"}, | |
6 | {"plugin_id": "sslyze_json", "command": "sslyze www.google.com --json_out=x.json", "command_result": "sslyze"}, | |
7 | {"plugin_id": "Amap", "command": "amap www.google.com", "command_result": "amap"}, | |
8 | {"plugin_id": "arp-scan", "command": "arp-scan www.google.com", "command_result": "arp-scan"}, | |
9 | {"plugin_id": "Beef", "command": "beef www.google.com", "command_result": "beef"}, | |
10 | {"plugin_id": "brutexss", "command": "brutexss www.google.com", "command_result": "brutexss"}, | |
11 | {"plugin_id": "dig", "command": "dig www.google.com", "command_result": "dig"}, | |
12 | {"plugin_id": "dirsearch", "command": "python3 dirsearch.py -u https://target", "command_result": "python3 dirsearch.py"}, | |
13 | ||
14 | {"plugin_id": "Dnsenum", "command": "dnsenum www.google.com", "command_result": "Dnsenum"}, | |
15 | {"plugin_id": "Dnsmap", "command": "dnsmap www.google.com", "command_result": "Dnsmap"}, | |
16 | {"plugin_id": "Dnsrecon", "command": "dnsrecon www.google.com", "command_result": "Dnsrecon"}, | |
17 | {"plugin_id": "Dnswalk", "command": "dnswalk www.google.com", "command_result": "Dnswalk"}, | |
18 | {"plugin_id": "Fierce", "command": "fierce www.google.com", "command_result": "Fierce"}, | |
19 | {"plugin_id": "ftp", "command": "ftp www.google.com", "command_result": "ftp"}, | |
20 | {"plugin_id": "Goohost", "command": "goohost.sh www.google.com", "command_result": "goohost.sh"}, | |
21 | {"plugin_id": "Hping3", "command": "hping3 www.google.com", "command_result": "Hping3"}, | |
22 | {"plugin_id": "Hydra", "command": "hydra www.google.com", "command_result": "Hydra"}, | |
23 | {"plugin_id": "Lynis", "command": "lynis www.google.com", "command_result": "Lynis"}, | |
24 | {"plugin_id": "Medusa", "command": "medusa www.google.com", "command_result": "Medusa"}, | |
25 | {"plugin_id": "Ndiff", "command": "ndiff www.google.com", "command_result": "Ndiff"}, | |
26 | {"plugin_id": "Netdiscover", "command": "netdiscover www.google.com", "command_result": "Netdiscover"}, | |
27 | {"plugin_id": "nextnet", "command": "nextnet www.google.com", "command_result": "nextnet"}, | |
28 | {"plugin_id": "Nikto", "command": "nikto www.google.com", "command_result": "Nikto"}, | |
29 | {"plugin_id": "Nmap", "command": "nmap www.google.com", "command_result": "Nmap"}, | |
30 | {"plugin_id": "pasteAnalyzer", "command": "pasteAnalyzer www.google.com", "command_result": "pasteAnalyzer"}, | |
31 | {"plugin_id": "peepingtom", "command": "./peepingtom.py www.google.com", "command_result": "./peepingtom.py"}, | |
32 | {"plugin_id": "propecia", "command": "propecia www.google.com", "command_result": "propecia"}, | |
33 | {"plugin_id": "rdpscan", "command": "rdpscan www.google.com", "command_result": "rdpscan"}, | |
34 | {"plugin_id": "Reverseraider", "command": "./reverseraider www.google.com", "command_result": "./reverseraider"}, | |
35 | {"plugin_id": "Skipfish", "command": "skipfish www.google.com", "command_result": "Skipfish"}, | |
36 | {"plugin_id": "sshdefaultscan", "command": "./sshdefaultscan.py www.google.com", "command_result": "./sshdefaultscan.py"}, | |
37 | {"plugin_id": "Telnet", "command": "telnet www.google.com", "command_result": "telnet"}, | |
38 | {"plugin_id": "Theharvester", "command": "./theHarvester.py www.google.com", "command_result": "./theharvester.py"}, | |
39 | {"plugin_id": "Traceroute", "command": "traceroute www.google.com", "command_result": "Traceroute"}, | |
40 | {"plugin_id": "W3af", "command": "w3af www.google.com", "command_result": "W3af"}, | |
41 | {"plugin_id": "Wapiti", "command": "wapiti www.google.com", "command_result": "Wapiti"}, | |
42 | {"plugin_id": "Wcscan", "command": "wcscan www.google.com", "command_result": "Wcscan"}, | |
43 | {"plugin_id": "Webfuzzer", "command": "webfuzzer www.google.com", "command_result": "Webfuzzer"}, | |
44 | {"plugin_id": "Wfuzz", "command": "wfuzz www.google.com", "command_result": "Wfuzz"}, | |
45 | {"plugin_id": "whois", "command": "whois www.google.com", "command_result": "whois"}, | |
46 | {"plugin_id": "X1", "command": "./x1 www.google.com", "command_result": "./x1"}, | |
47 | {"plugin_id": "xsssniper", "command": "xsssniper www.google.com", "command_result": "xsssniper"}, | |
48 | {"plugin_id": "dirb", "command": "dirb google.com", "command_result": "dirb"}, | |
49 | {"plugin_id": "Arachni", "command": "arachni www.google.com", "command_result": "Arachni"} | |
50 | ] | |
51 | } |
0 | import pytest | |
1 | ||
2 | ||
3 | def pytest_addoption(parser): | |
4 | parser.addoption( | |
5 | "--performance", action="store_true", default=False, help="run performance tests" | |
6 | ) | |
7 | ||
8 | ||
9 | def pytest_configure(config): | |
10 | config.addinivalue_line("markers", "performance: mark test as performance") | |
11 | ||
12 | ||
13 | def pytest_collection_modifyitems(config, items): | |
14 | if config.getoption("--performance"): | |
15 | # --performance given in cli: do not skip performance tests | |
16 | return | |
17 | performance = pytest.mark.skip(reason="need --performance option to run") | |
18 | for item in items: | |
19 | if "performance" in item.keywords: | |
20 | item.add_marker(performance)⏎ |
0 | #!/usr/bin/env python | |
1 | import hashlib | |
2 | import os | |
3 | import shutil | |
4 | import json | |
5 | import click | |
6 | import colorama | |
7 | from faraday_plugins.plugins.manager import PluginsManager, ReportAnalyzer | |
8 | from faraday_plugins.plugins.plugin import PluginBase | |
9 | ||
10 | colorama.init(autoreset=True) | |
11 | ||
12 | BLACK_LIST = [ | |
13 | 'LICENSE', | |
14 | 'README.md', | |
15 | '.gitignore', | |
16 | '.gitkeep', | |
17 | 'faraday_plugins_tests', | |
18 | ] | |
19 | ||
20 | REPORT_COLLECTION_DIR = '../report-collection' | |
21 | FARADAY_PLUGINS_TESTS_DIR = 'faraday_plugins_tests' | |
22 | REPORTS_CHECKSUM = [] | |
23 | ||
24 | def list_report_files(): | |
25 | report_filenames = os.walk(os.path.join(REPORT_COLLECTION_DIR)) | |
26 | for root, directory, filenames in report_filenames: | |
27 | if '.git' in directory or FARADAY_PLUGINS_TESTS_DIR in root: | |
28 | continue | |
29 | for filename in filenames: | |
30 | if filename in BLACK_LIST: | |
31 | continue | |
32 | if '.git' in root: | |
33 | continue | |
34 | yield os.path.join(root, filename) | |
35 | ||
36 | ||
37 | @click.command() | |
38 | @click.option('--force', is_flag=True) | |
39 | @click.option('--debug', is_flag=False) | |
40 | def generate_reports_tests(force, debug): | |
41 | generated_summaries = 0 | |
42 | analysed_reports = 0 | |
43 | click.echo(f"{colorama.Fore.GREEN}Generate Faraday Plugins Tests Summary") | |
44 | plugins_manager = PluginsManager(hostname_resolution=False) | |
45 | analyzer = ReportAnalyzer(plugins_manager) | |
46 | for report_file_path in list_report_files(): | |
47 | if debug: | |
48 | click.echo(f"File: {report_file_path}") | |
49 | plugin: PluginBase = analyzer.get_plugin(report_file_path) | |
50 | if not plugin: | |
51 | click.echo(f"{colorama.Fore.YELLOW}Plugin for file: ({report_file_path}) not found") | |
52 | else: | |
53 | with open(report_file_path, 'rb') as f: | |
54 | m = hashlib.md5(f.read()) | |
55 | file_checksum = m.hexdigest() | |
56 | if file_checksum not in REPORTS_CHECKSUM: | |
57 | REPORTS_CHECKSUM.append(file_checksum) | |
58 | else: | |
59 | click.echo(f"{colorama.Fore.YELLOW}Ignore duplicated file: ({report_file_path})") | |
60 | continue | |
61 | analysed_reports += 1 | |
62 | report_file_name = os.path.basename(report_file_path) | |
63 | plugin_name = plugin.id | |
64 | plugin_path = os.path.join(REPORT_COLLECTION_DIR, FARADAY_PLUGINS_TESTS_DIR, plugin_name) | |
65 | if not os.path.isdir(plugin_path): | |
66 | os.mkdir(plugin_path) | |
67 | dst_report_file_path = os.path.join(plugin_path, report_file_name) | |
68 | summary_needed = False | |
69 | summary_file = f"{os.path.splitext(dst_report_file_path)[0]}_summary.json" | |
70 | if not os.path.isfile(dst_report_file_path) or force: | |
71 | summary_needed = True | |
72 | shutil.copyfile(report_file_path, dst_report_file_path) | |
73 | if not os.path.isfile(summary_file) or force: | |
74 | summary_needed = True | |
75 | if summary_needed: | |
76 | try: | |
77 | plugin.processReport(report_file_path) | |
78 | click.echo(f"{colorama.Fore.GREEN}Generate Summary for: {dst_report_file_path} [{plugin}]") | |
79 | summary = plugin.get_summary() | |
80 | with open(summary_file, "w") as f: | |
81 | json.dump(summary, f) | |
82 | generated_summaries += 1 | |
83 | except Exception as e: | |
84 | click.echo(f"{colorama.Fore.RED}Error generating summary for file: {report_file_path} [{plugin}]: [{e}]") | |
85 | click.echo(f"Generated {generated_summaries} summaries of {analysed_reports} reports") | |
86 | ||
87 | ||
88 | if __name__ == "__main__": | |
89 | generate_reports_tests() |
0 | import json | |
1 | import os | |
2 | import re | |
3 | import pytest | |
4 | from click.testing import CliRunner | |
5 | from faraday_plugins.commands import list_plugins, detect_command, process_command, detect_report, process_report | |
6 | ||
7 | ||
8 | def test_list_plugins(): | |
9 | runner = CliRunner() | |
10 | result = runner.invoke(list_plugins) | |
11 | assert result.exit_code == 0 | |
12 | loaded_plugins = re.search(r'Loaded Plugins: (?P<loaded_plugins>\d+)', result.output) | |
13 | assert loaded_plugins | |
14 | assert int(loaded_plugins.groupdict().get('loaded_plugins', 0)) > 0 | |
15 | ||
16 | ||
17 | def test_detect_invalid_command(): | |
18 | runner = CliRunner() | |
19 | result = runner.invoke(detect_command, args=['invalid_command']) | |
20 | assert result.exit_code == 0 | |
21 | assert result.output.strip() == "Failed to detect command: invalid_command" | |
22 | ||
23 | ||
24 | @pytest.mark.skip(reason="issue with docker image") | |
25 | def test_detect_command(): | |
26 | runner = CliRunner() | |
27 | result = runner.invoke(detect_command, args=['ping -c 1 www.google.com']) | |
28 | assert result.exit_code == 0 | |
29 | assert result.output.strip() == "Faraday Plugin: ping" | |
30 | ||
31 | ||
32 | @pytest.mark.skip(reason="issue with docker image") | |
33 | def test_process_command(): | |
34 | runner = CliRunner() | |
35 | result = runner.invoke(process_command, args=['ping -c 1 www.google.com', '--summary']) | |
36 | assert result.exit_code == 0, result.output | |
37 | summary = json.loads(result.output.strip()) | |
38 | assert summary['hosts'] == 1 | |
39 | ||
40 | ||
41 | @pytest.mark.skip(reason="issue with docker image") | |
42 | def test_process_command_ping(): | |
43 | runner = CliRunner() | |
44 | result = runner.invoke(process_command, args=['ping -c 1 www.google.com']) | |
45 | assert result.exit_code == 0, result.output | |
46 | summary = json.loads(result.output.strip()) | |
47 | ||
48 | assert summary['command']["command"] == 'ping' | |
49 | ||
50 | ||
51 | @pytest.mark.skip(reason="issue with docker image") | |
52 | def test_process_command_to_file(): | |
53 | runner = CliRunner() | |
54 | with runner.isolated_filesystem() as file_system: | |
55 | output_file = os.path.join(file_system, "test.json") | |
56 | result = runner.invoke(process_command, args=['ping -c 1 www.google.com', '-o', output_file]) | |
57 | assert result.exit_code == 0, result.output | |
58 | assert os.path.isfile(output_file) | |
59 | with open(output_file) as f: | |
60 | vuln_json = json.load(f) | |
61 | assert len(vuln_json['hosts']) == 1 | |
62 | ||
63 | ||
64 | def test_detect_report(): | |
65 | report_file = os.path.join('./report-collection', 'faraday_plugins_tests', 'Nmap', 'nmap_5.21.xml') | |
66 | runner = CliRunner() | |
67 | result = runner.invoke(detect_report, args=[report_file]) | |
68 | assert result.exit_code == 0 | |
69 | assert "Faraday Plugin: Nmap" == result.output.strip() | |
70 | ||
71 | ||
72 | def test_detect_report_dont_exists(): | |
73 | report_file = os.path.join('./report-collection', 'faraday_plugins_tests', 'Nmap', 'invalid_report.xml') | |
74 | runner = CliRunner() | |
75 | result = runner.invoke(detect_report, args=[report_file]) | |
76 | assert result.exit_code == 0 | |
77 | assert "Don't Exists" in result.output.strip() | |
78 | ||
79 | ||
80 | def test_process_report_summary(): | |
81 | report_file = os.path.join('./report-collection', 'faraday_plugins_tests', 'Nmap', 'nmap_5.21.xml') | |
82 | summary_file = os.path.join('./report-collection', 'faraday_plugins_tests', 'Nmap', 'nmap_5.21_summary.json') | |
83 | runner = CliRunner() | |
84 | result = runner.invoke(process_report, args=[report_file, '--summary']) | |
85 | assert result.exit_code == 0 | |
86 | summary = json.loads(result.output.strip()) | |
87 | with open(summary_file) as f: | |
88 | saved_summary = json.load(f) | |
89 | vuln_hashes = set(summary['vuln_hashes']) | |
90 | saved_vuln_hashes = set(saved_summary.get('vuln_hashes', [])) | |
91 | assert summary['hosts'] == saved_summary['hosts'] | |
92 | assert summary['services'] == saved_summary['services'] | |
93 | assert summary['hosts_vulns'] == saved_summary['hosts_vulns'] | |
94 | assert summary['services_vulns'] == saved_summary['services_vulns'] | |
95 | assert summary['severity_vulns'] == saved_summary['severity_vulns'] | |
96 | assert vuln_hashes == saved_vuln_hashes | |
97 | ||
98 | ||
99 | def test_process_report_ignore_info(): | |
100 | report_file = os.path.join('./report-collection', 'faraday_plugins_tests', 'Nmap', 'nmap_5.21.xml') | |
101 | runner = CliRunner() | |
102 | result = runner.invoke(process_report, args=[report_file, '--summary', '--ignore-info']) | |
103 | assert result.exit_code == 0 | |
104 | summary = json.loads(result.output.strip()) | |
105 | assert summary['hosts'] == 256 | |
106 | assert summary['services'] == 69 | |
107 | assert summary['hosts_vulns'] == 0 | |
108 | assert summary['services_vulns'] == 0 | |
109 | ||
110 | ||
111 | def test_process_report_tags(): | |
112 | report_file = os.path.join('./report-collection', 'faraday_plugins_tests', 'Acunetix', 'acunetix_valid_dummy.xml') | |
113 | runner = CliRunner() | |
114 | args = [report_file, '--vuln-tag=vuln_tag', '--service-tag=service_tag', '--host-tag=host_tag'] | |
115 | result = runner.invoke(process_report, args=args) | |
116 | assert result.exit_code == 0 | |
117 | body = json.loads(result.output.strip()) | |
118 | assert body['hosts'][0]["tags"][0] == "host_tag" | |
119 | assert body['hosts'][0]["services"][0]["tags"][0] == "service_tag" | |
120 | assert body['hosts'][0]["services"][0]["vulnerabilities"][0]["tags"][0] == "vuln_tag" |
0 | import json | |
1 | import pytest | |
2 | from faraday_plugins.plugins.manager import PluginsManager, CommandAnalyzer | |
3 | from faraday_plugins.plugins.plugin import PluginBase | |
4 | ||
5 | ||
6 | plugins_manager = PluginsManager() | |
7 | analyzer = CommandAnalyzer(plugins_manager) | |
8 | ||
9 | COMMANDS_FILE = './tests/commands.json' | |
10 | ||
11 | def list_commands(): | |
12 | with open(COMMANDS_FILE) as f: | |
13 | commands_dict = json.load(f) | |
14 | for command_data in commands_dict["commands"]: | |
15 | yield command_data | |
16 | ||
17 | ||
18 | @pytest.mark.parametrize("command_data", list_commands()) | |
19 | def test_autodetected_on_commands(command_data): | |
20 | plugin_id = command_data["plugin_id"] | |
21 | command_string = command_data["command"] | |
22 | command_result = command_data["command_result"] | |
23 | ||
24 | plugin: PluginBase = analyzer.get_plugin(command_string) | |
25 | assert plugin, command_string | |
26 | assert plugin.id.lower() == plugin_id.lower() | |
27 | assert plugin.command.lower() == command_result.lower() | |
28 |
0 | from faraday_plugins.plugins.plugin import PluginBase | |
1 | ||
2 | ||
3 | def test_get_host_cache_id_with_same_host(): | |
4 | host_1 = {'ip': '127.0.0.1'} | |
5 | host_2 = {'ip': '127.0.0.1', 'description': 'test desc'} | |
6 | cache_id_1 = PluginBase.get_host_cache_id(host_1) | |
7 | cache_id_2 = PluginBase.get_host_cache_id(host_2) | |
8 | ||
9 | assert cache_id_1 == cache_id_2 | |
10 | ||
11 | ||
12 | def test_get_host_cache_id_with_diffent_ip(): | |
13 | host_1 = {'ip': '127.0.0.1'} | |
14 | host_2 = {'ip': '192.168.0.1', 'description': 'test desc'} | |
15 | cache_id_1 = PluginBase.get_host_cache_id(host_1) | |
16 | cache_id_2 = PluginBase.get_host_cache_id(host_2) | |
17 | ||
18 | assert cache_id_1 != cache_id_2 | |
19 | ||
20 | ||
21 | def test_get_host_service_cache_id_same_objects(): | |
22 | host_1 = {'ip': '127.0.0.1'} | |
23 | host_cache_id_1 = PluginBase.get_host_cache_id(host_1) | |
24 | service_1 = {'protocol': 'tcp', 'port': 80} | |
25 | host_2 = {'ip': '127.0.0.1'} | |
26 | host_cache_id_2 = PluginBase.get_host_cache_id(host_2) | |
27 | service_2 = {'protocol': 'tcp', 'port': 80} | |
28 | ||
29 | cache_1 = PluginBase.get_host_service_cache_id(host_cache_id_1, service_1) | |
30 | cache_2 = PluginBase.get_host_service_cache_id(host_cache_id_2, service_2) | |
31 | ||
32 | assert cache_1 == cache_2 | |
33 | ||
34 | ||
35 | def test_get_host_service_cache_id_different_host(): | |
36 | host_1 = {'ip': '127.0.0.1'} | |
37 | host_cache_id_1 = PluginBase.get_host_cache_id(host_1) | |
38 | service_1 = {'protocol': 'tcp', 'port': 80} | |
39 | host_2 = {'ip': '192.168.0.1'} | |
40 | host_cache_id_2 = PluginBase.get_host_cache_id(host_2) | |
41 | service_2 = {'protocol': 'tcp', 'port': 80} | |
42 | ||
43 | cache_1 = PluginBase.get_host_service_cache_id(host_cache_id_1, service_1) | |
44 | cache_2 = PluginBase.get_host_service_cache_id(host_cache_id_2, service_2) | |
45 | ||
46 | assert cache_1 != cache_2 | |
47 | ||
48 | ||
49 | def test_get_host_vuln_cache_id_severity_does_not_affect_duplicate(): | |
50 | host_1 = {'ip': '127.0.0.1'} | |
51 | host_cache_id_1 = PluginBase.get_host_cache_id(host_1) | |
52 | vuln_1 = {'name': 'test', 'desc': 'test', 'severity': 'low'} | |
53 | ||
54 | host_2 = {'ip': '127.0.0.1'} | |
55 | host_cache_id_2 = PluginBase.get_host_cache_id(host_2) | |
56 | vuln_2 = {'name': 'test', 'desc': 'test', 'severity': 'high'} | |
57 | ||
58 | ||
59 | cache_1 = PluginBase.get_host_vuln_cache_id(host_cache_id_1, vuln_1) | |
60 | cache_2 = PluginBase.get_host_vuln_cache_id(host_cache_id_2, vuln_2) | |
61 | ||
62 | assert cache_1 == cache_2 | |
63 | ||
64 | ||
65 | def test_get_host_vuln_cache_id_description_makes_different_cache_ids(): | |
66 | host_1 = {'ip': '127.0.0.1'} | |
67 | host_cache_id_1 = PluginBase.get_host_cache_id(host_1) | |
68 | vuln_1 = {'name': 'test', 'desc': 'test', 'severity': 'low'} | |
69 | ||
70 | host_2 = {'ip': '127.0.0.1'} | |
71 | host_cache_id_2 = PluginBase.get_host_cache_id(host_2) | |
72 | vuln_2 = {'name': 'test', 'new desc': 'test', 'severity': 'high'} | |
73 | ||
74 | ||
75 | cache_1 = PluginBase.get_host_vuln_cache_id(host_cache_id_1, vuln_1) | |
76 | cache_2 = PluginBase.get_host_vuln_cache_id(host_cache_id_2, vuln_2) | |
77 | ||
78 | assert cache_1 != cache_2 | |
79 | ||
80 | ||
81 | def test_get_service_vuln_cache_id_severity_does_not_affect_cache_id(): | |
82 | host_1 = {'ip': '127.0.0.1'} | |
83 | host_cache_id_1 = PluginBase.get_host_cache_id(host_1) | |
84 | service_1 = {'protocol': 'tcp', 'port': 80} | |
85 | ||
86 | host_2 = {'ip': '127.0.0.1'} | |
87 | host_cache_id_2 = PluginBase.get_host_cache_id(host_2) | |
88 | host_2 = {'ip': '127.0.0.1'} | |
89 | host_cache_id_2 = PluginBase.get_host_cache_id(host_2) | |
90 | service_2 = {'protocol': 'tcp', 'port': 80} | |
91 | ||
92 | service_cache_1 = PluginBase.get_host_service_cache_id(host_cache_id_1, service_1) | |
93 | service_cache_2 = PluginBase.get_host_service_cache_id(host_cache_id_2, service_2) | |
94 | ||
95 | vuln_2 = {'name': 'test', 'desc': 'test', 'severity': 'high', 'method': 'GET'} | |
96 | vuln_1 = {'name': 'test', 'desc': 'test', 'severity': 'low', 'method': 'GET'} | |
97 | ||
98 | cache_1 = PluginBase.get_service_vuln_cache_id(host_cache_id_1, service_cache_1, vuln_1) | |
99 | cache_2 = PluginBase.get_service_vuln_cache_id(host_cache_id_2, service_cache_2, vuln_2) | |
100 | ||
101 | assert cache_1 == cache_2 | |
102 | ||
103 | def test_get_service_vuln_cache_id_with_different_service_return_different_id(): | |
104 | host_1 = {'ip': '127.0.0.1'} | |
105 | host_cache_id_1 = PluginBase.get_host_cache_id(host_1) | |
106 | service_1 = {'protocol': 'tcp', 'port': 80} | |
107 | ||
108 | host_2 = {'ip': '127.0.0.1'} | |
109 | host_cache_id_2 = PluginBase.get_host_cache_id(host_2) | |
110 | host_2 = {'ip': '127.0.0.1'} | |
111 | host_cache_id_2 = PluginBase.get_host_cache_id(host_2) | |
112 | service_2 = {'protocol': 'tcp', 'port': 22} | |
113 | ||
114 | service_cache_1 = PluginBase.get_host_service_cache_id(host_cache_id_1, service_1) | |
115 | service_cache_2 = PluginBase.get_host_service_cache_id(host_cache_id_2, service_2) | |
116 | ||
117 | vuln_2 = {'name': 'test', 'desc': 'test', 'severity': 'high', 'method': 'GET'} | |
118 | vuln_1 = {'name': 'test', 'desc': 'test', 'severity': 'low', 'method': 'GET'} | |
119 | ||
120 | cache_1 = PluginBase.get_service_vuln_cache_id(host_cache_id_1, service_cache_1, vuln_1) | |
121 | cache_2 = PluginBase.get_service_vuln_cache_id(host_cache_id_2, service_cache_2, vuln_2) | |
122 | ||
123 | assert cache_1 != cache_2⏎ |
0 | import os | |
1 | import socket | |
2 | import json | |
3 | import pytest | |
4 | from pathlib import Path | |
5 | from faraday_plugins.plugins.manager import PluginsManager, ReportAnalyzer | |
6 | from faraday_plugins.plugins.plugin import PluginBase | |
7 | from faraday.server.api.modules.bulk_create import BulkCreateSchema | |
8 | ||
9 | BLACK_LIST = [ | |
10 | 'LICENSE', | |
11 | 'README.md', | |
12 | '.gitignore', | |
13 | '.gitkeep', | |
14 | 'faraday_plugins_tests', | |
15 | ||
16 | ] | |
17 | ||
18 | plugins_manager = PluginsManager(hostname_resolution=False) | |
19 | analyzer = ReportAnalyzer(plugins_manager) | |
20 | ||
21 | PLUGINS_CACHE = {} | |
22 | REPORTS_JSON_CACHE = {} | |
23 | ||
24 | SKIP_IP_PLUGINS = ['Fortify'] | |
25 | ||
26 | REPORTS_SUMMARY_DIR = './report-collection/faraday_plugins_tests' | |
27 | ||
28 | ||
29 | def get_plugin_from_cache(report_file): | |
30 | plugin = PLUGINS_CACHE.get(report_file) | |
31 | if not plugin: | |
32 | plugin: PluginBase = analyzer.get_plugin(report_file) | |
33 | if plugin: | |
34 | save_plugin_in_cache(report_file, plugin) | |
35 | return plugin | |
36 | ||
37 | ||
38 | def save_plugin_in_cache(report_file, plugin): | |
39 | if report_file not in PLUGINS_CACHE: | |
40 | PLUGINS_CACHE[report_file] = plugin | |
41 | ||
42 | ||
43 | def get_report_json_from_cache(report_file): | |
44 | plugin_json = REPORTS_JSON_CACHE.get(report_file) | |
45 | if not plugin_json: | |
46 | plugin = get_plugin_from_cache(report_file) | |
47 | if plugin: | |
48 | plugin.processReport(Path(report_file)) | |
49 | plugin_json = json.loads(plugin.get_json()) | |
50 | REPORTS_JSON_CACHE[report_file] = plugin_json | |
51 | else: | |
52 | plugin = get_plugin_from_cache(report_file) | |
53 | return plugin, plugin_json | |
54 | ||
55 | ||
56 | def list_report_files(): | |
57 | report_filenames = os.walk(REPORTS_SUMMARY_DIR) | |
58 | for plugin_folder, directory, filenames in report_filenames: | |
59 | if '.git' in directory or 'faraday_plugins_tests' in directory: | |
60 | continue | |
61 | for filename in filenames: | |
62 | if filename in BLACK_LIST: | |
63 | continue | |
64 | if '.git' in plugin_folder: | |
65 | continue | |
66 | if not filename.endswith('_summary.json'): | |
67 | yield Path(plugin_folder).name, os.path.join(plugin_folder, filename) | |
68 | ||
69 | ||
70 | def is_valid_ipv4_address(address): | |
71 | try: | |
72 | socket.inet_pton(socket.AF_INET, address) | |
73 | except AttributeError: # no inet_pton here, sorry | |
74 | try: | |
75 | socket.inet_aton(address) | |
76 | except OSError: | |
77 | return False | |
78 | return address.count('.') == 3 | |
79 | except OSError: # not a valid address | |
80 | return False | |
81 | return True | |
82 | ||
83 | ||
84 | def is_valid_ipv6_address(address): | |
85 | try: | |
86 | socket.inet_pton(socket.AF_INET6, address) | |
87 | except OSError: # not a valid address | |
88 | return False | |
89 | return True | |
90 | ||
91 | ||
92 | def is_valid_ip_address(address): | |
93 | return (is_valid_ipv4_address(address) or is_valid_ipv6_address(address)) | |
94 | ||
95 | def test_reports_collection_exists(): | |
96 | assert os.path.isdir(REPORTS_SUMMARY_DIR) is True, "Please clone the report-collection repo!" | |
97 | ||
98 | @pytest.mark.parametrize("report_filename_and_folder", list_report_files()) | |
99 | def test_autodetected_on_all_report_collection(report_filename_and_folder): | |
100 | plugin_folder = report_filename_and_folder[0] | |
101 | report_filename = report_filename_and_folder[1] | |
102 | plugin: PluginBase = get_plugin_from_cache(report_filename) | |
103 | assert plugin, report_filename | |
104 | assert plugin.id == plugin_folder | |
105 | ||
106 | ||
107 | @pytest.mark.skip(reason="Fail until release") | |
108 | @pytest.mark.parametrize("report_filename_and_folder", list_report_files()) | |
109 | def test_schema_on_all_reports(report_filename_and_folder): | |
110 | report_filename = report_filename_and_folder[1] | |
111 | plugin, plugin_json = get_report_json_from_cache(report_filename) | |
112 | if plugin_json: | |
113 | serializer = BulkCreateSchema() | |
114 | res = serializer.loads(json.dumps(plugin_json)) | |
115 | assert set(res.keys()) == {'hosts', 'command'} | |
116 | ||
117 | ||
118 | ||
119 | ||
120 | @pytest.mark.skip(reason="Skip validate ip format") | |
121 | @pytest.mark.parametrize("report_filename_and_folder", list_report_files()) | |
122 | def test_host_ips_all_reports(report_filename_and_folder): | |
123 | report_filename = report_filename_and_folder[1] | |
124 | plugin, plugin_json = get_report_json_from_cache(report_filename) | |
125 | if plugin_json: | |
126 | if plugin.id not in SKIP_IP_PLUGINS: | |
127 | for host in plugin_json['hosts']: | |
128 | assert is_valid_ip_address(host['ip']) is True | |
129 | ||
130 | ||
131 | @pytest.mark.parametrize("report_filename_and_folder", list_report_files()) | |
132 | def test_summary_reports(report_filename_and_folder): | |
133 | report_filename = report_filename_and_folder[1] | |
134 | plugin, plugin_json = get_report_json_from_cache(report_filename) | |
135 | if plugin_json: | |
136 | summary_file = f"{os.path.splitext(report_filename)[0]}_summary.json" | |
137 | assert os.path.isfile(summary_file) is True | |
138 | with open(summary_file) as f: | |
139 | saved_summary = json.load(f) | |
140 | summary = plugin.get_summary() | |
141 | vuln_hashes = set(summary['vuln_hashes']) | |
142 | saved_vuln_hashes = set(saved_summary.get('vuln_hashes', [])) | |
143 | assert summary['hosts'] == saved_summary['hosts'] | |
144 | assert summary['services'] == saved_summary['services'] | |
145 | assert summary['hosts_vulns'] == saved_summary['hosts_vulns'] | |
146 | assert summary['services_vulns'] == saved_summary['services_vulns'] | |
147 | assert summary['severity_vulns'] == saved_summary['severity_vulns'] | |
148 | assert vuln_hashes == saved_vuln_hashes | |
149 | ||
150 | ||
151 | @pytest.mark.performance | |
152 | @pytest.mark.parametrize("report_filename_and_folder", list_report_files()) | |
153 | def test_detected_tools_on_all_report_collection(report_filename_and_folder, benchmark): | |
154 | report_filename = report_filename_and_folder[1] | |
155 | plugins_manager = PluginsManager() | |
156 | analyzer = ReportAnalyzer(plugins_manager) | |
157 | plugin: PluginBase = analyzer.get_plugin(report_filename) | |
158 | if not plugin: | |
159 | return | |
160 | assert plugin, report_filename | |
161 | benchmark(plugin.processReport, report_filename) | |
162 | plugin_json = json.loads(plugin.get_json()) | |
163 | assert "hosts" in plugin_json | |
164 | assert "command" in plugin_json | |
165 | assert os.path.isfile(report_filename) is True |