diff --git a/.env b/.env new file mode 100644 index 0000000..7728939 --- /dev/null +++ b/.env @@ -0,0 +1 @@ +API_KEY = '' \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..90bee2f --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,41 @@ +# Borrowed initially from https://github.com/lyft/cartography +default_language_version: + # force all unspecified python hooks to run python3 + python: python3 +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.0.1 + hooks: + - id: check-executables-have-shebangs + - id: check-merge-conflict + - id: check-vcs-permalinks + # Disabling this as it is giving false positives for sam templates + # - id: check-yaml + # args: ['--unsafe'] # Just check the syntax + - id: debug-statements + - id: end-of-file-fixer + - id: trailing-whitespace +- repo: https://github.com/PyCQA/flake8 + rev: 3.9.2 + hooks: + - id: flake8 +- repo: https://github.com/pre-commit/mirrors-autopep8 + rev: v1.5.7 + hooks: + - id: autopep8 + # disable a few rewrites which will cause autopep8 to reflow + args: [--in-place, '--ignore=E265,E501,W504'] +- repo: https://github.com/asottile/reorder_python_imports + rev: v2.6.0 + hooks: + - id: reorder-python-imports + args: [--py3-plus] +- repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.0.0 + hooks: + - id: mypy + exclude: ^pb/ + additional_dependencies: + - types-requests + - types-PyYAML + - types-python-dateutil diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..3ecb8fc --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "[python]": { + "editor.defaultFormatter": "ms-python.autopep8" + }, + "python.formatting.provider": "none" +} diff --git a/Dockerfile b/Dockerfile index bf05302..ab82eaa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,4 +24,6 @@ RUN apt update && apt upgrade -y RUN apt install nmap -y RUN pip install -r requirements.txt -CMD [ "python", "./app.py" ] \ No newline at end of file +ENV OPENAI_API_KEY='' + +CMD [ "sh", "-c","python ./app.py ${OPENAI_API_KEY}" ] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..40015cf --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +lint: + pre-commit run --all-files --show-diff-on-failure diff --git a/__pycache__/app.cpython-310.pyc b/__pycache__/app.cpython-310.pyc index 5d58bea..4bb8aec 100644 Binary files a/__pycache__/app.cpython-310.pyc and b/__pycache__/app.cpython-310.pyc differ diff --git a/__pycache__/test_app.cpython-310-pytest-7.3.2.pyc b/__pycache__/test_app.cpython-310-pytest-7.3.2.pyc new file mode 100644 index 0000000..505f04f Binary files /dev/null and b/__pycache__/test_app.cpython-310-pytest-7.3.2.pyc differ diff --git a/app.py b/app.py index e3bff8e..d500b8b 100644 --- a/app.py +++ b/app.py @@ -9,12 +9,15 @@ import nmap import openai + +from dotenv import load_dotenv from flask import Flask from flask import render_template from flask_restful import Api from flask_restful import Resource -openai.api_key = "__API__KEY__" +load_dotenv() +openai.api_key = os.getenv('API_KEY') model_engine = "text-davinci-003" app = Flask(__name__) diff --git a/package/LICENSE b/package/LICENSE index 5244ccf..705963e 100644 --- a/package/LICENSE +++ b/package/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2023 morpheuslord - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +MIT License + +Copyright (c) 2023 morpheuslord + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/package/MANIFEST.in b/package/MANIFEST.in index d167d3c..1a64c4c 100644 --- a/package/MANIFEST.in +++ b/package/MANIFEST.in @@ -1,2 +1,2 @@ -include nmap_api/*.py +include nmap_api/*.py include nmap_api/*.txt \ No newline at end of file diff --git a/package/README.md b/package/README.md index fc85def..7f97cd9 100644 --- a/package/README.md +++ b/package/README.md @@ -1,118 +1,227 @@ - -# Nmap API - -Uses python3.10, Debian, python-Nmap, and flask framework to create a Nmap API that can do scans with a good speed online and is easy to deploy. - -This is a implementation for our college PCL project which is still under development and constantly updating. - - -## API Reference - -#### Get all items - -```text - GET /api/p1/{auth_key}/{target} - GET /api/p2/{auth_key}/{target} - GET /api/p3/{auth_key}/{target} - GET /api/p4/{auth_key}/{target} - GET /api/p5/{auth_key}/{target} -``` - -| Parameter | Type | Description | -| :-------- | :------- | :------------------------- | -| `auth_key` | `string` | **Required**. The API auth key gebe | -| `target`| `string`| **Required**. The target Hostname and IP| - -#### Get item - -```text - GET /api/p1/ - GET /api/p2/ - GET /api/p3/ - GET /api/p4/ - GET /api/p5/ -``` - -| Parameter | Return data | Description | Nmap Command | -| :-------- | :------- | :-------------------------------- | :---------| -| `p1` | `json` | Effective Scan | `-Pn -sV -T4 -O -F`| -| `p2` | `json` | Simple Scan | `-Pn -T4 -A -v`| -| `p3` | `json` | Low Power Scan | `-Pn -sS -sU -T4 -A -v`| -| `p4` | `json` | Partial Intense Scan | `-Pn -p- -T4 -A -v`| -| `p5` | `json` | Complete Intense Scan | `-Pn -sS -sU -T4 -A -PE -PP -PY -g 53 --script=vuln`| - - -#### Auth and User management - -```text - GET /register/// -``` -| Parameter | Type | Description | -| :-------- | :------- | :------------------------- | -|`ID`|`Int`|user ID| -|`Passwd`| `String`| User Passwd| -|`Unique_Key`| `String`| User Unique_Key| - -## Improvements -Added GPT functionality with chunking module. -The methodology is based on how `Langchain GPT embeddings` operate. Basically the operation goes like this: - -```text -Data -> Chunks_generator ─┐ ┌─> AI_Loop -> Data_Extraction -> Return_Dat - (GPT3 - 1500 TOKENS) ├─> Chunk1 ─┤ - (GPT4 - 3500 TOKENS) ├─> Chunk2 ─┤ - ├─> Chunk3 ─┤ - └─> Chunk N ─┘ -``` - -AI code: -```python -def AI(analyze: str) -> dict[str, any]: - # Prompt about what the query is all about - prompt = f""" - Do a vulnerability analysis report on the following JSON data and - follow the following rules: - 1) Calculate the criticality score. - 2) Return all the open ports within the open_ports list. - 3) Return all the closed ports within the closed_ports list. - 4) Return all the filtered ports within the filtered_ports list. - - output format: {{ - "open_ports": [], - "closed_ports": [], - "filtered_ports": [], - "criticality_score": "" - }} - - data = {analize} - """ - try: - # A structure for the request - completion = openai.Completion.create( - engine=model_engine, - prompt=prompt, - max_tokens=1024, - n=1, - stop=None, - ) - response = completion.choices[0].text - - # Assuming extract_ai_output returns a dictionary - extracted_data = extract_ai_output(response) - except KeyboardInterrupt: - print("Bye") - quit() - - # Store outputs in a dictionary - ai_output = { - "open_ports": extracted_data.get("open_ports"), - "closed_ports": extracted_data.get("closed_ports"), - "filtered_ports": extracted_data.get("filtered_ports"), - "criticality_score": extracted_data.get("criticality_score") - } - - return ai_output -``` - -#### Default User Keys -**Default_Key**: **cff649285012c6caae4d** + +# Nmap API + +Uses python3.10, Debian, python-Nmap, and flask framework to create a Nmap API that can do scans with a good speed online and is easy to deploy. +The API also includes GPT3 functionality for AI generated reports. +This is an implementation for our college PCL project which is still under development and constantly updating. + + +## API Reference + +#### Get all items + +```text + GET /api/p1/{auth_key}/{target} + GET /api/p2/{auth_key}/{target} + GET /api/p3/{auth_key}/{target} + GET /api/p4/{auth_key}/{target} + GET /api/p5/{auth_key}/{target} +``` + +| Parameter | Type | Description | +| :-------- | :------- | :------------------------- | +| `auth_key` | `string` | **Required**. The API auth key gebe | +| `target`| `string`| **Required**. The target Hostname and IP| + +#### Get item + +```text + GET /api/p1/ + GET /api/p2/ + GET /api/p3/ + GET /api/p4/ + GET /api/p5/ +``` + +| Parameter | Return data | Description | Nmap Command | +| :-------- | :------- | :-------------------------------- | :---------| +| `p1` | `json` | Effective Scan | `-Pn -sV -T4 -O -F`| +| `p2` | `json` | Simple Scan | `-Pn -T4 -A -v`| +| `p3` | `json` | Low Power Scan | `-Pn -sS -sU -T4 -A -v`| +| `p4` | `json` | Partial Intense Scan | `-Pn -p- -T4 -A -v`| +| `p5` | `json` | Complete Intense Scan | `-Pn -sS -sU -T4 -A -PE -PP -PY -g 53 --script=vuln`| + + +#### Auth and User management + +```text + GET /register/// +``` +| Parameter | Type | Description | +| :-------- | :------- | :------------------------- | +|`ID`|`Int`|user ID| +|`Passwd`| `String`| User Passwd| +|`Unique_Key`| `String`| User Unique_Key| + +## Improvements +Added GPT functionality with chunking module. +The methodology is based on how `Langchain GPT embeddings` operate. Basically, the operation goes like this: + +```text +Data -> Chunks_generator ─┐ ┌─> AI_Loop -> Data_Extraction -> Return_Dat + (GPT3 - 1500 TOKENS) ├─> Chunk1 ─┤ + (GPT4 - 3500 TOKENS) ├─> Chunk2 ─┤ + ├─> Chunk3 ─┤ + └─> Chunk N ─┘ +``` +this is how to works: +- **Step 1:** + - The JSON is done scanning or the text is extracted and converted into a string +- **Step 2:** + - The long string is converted into individual tokens of words and characters for example `[]{};word` == `'[',']','{','}',';','word'` +- **Step 3:** + - The long list of tokens is divided into groups of lists according to how many `tokens` we want. + - for our use case we have a prompt and the data extracted and for simplicity, we went with the chunks of `500 tokens` + the prompt tokens. +- **Step 4:** + - Step 4 can be achieved in 3 ways `a) Langchain`, `b) OpenAI functions Feature`, `c) The OpenAI API calls` + - From our tests, the first option `Langchain LLM` did not work as it is not built for such processes + - The second option `OpenAI functions feature` needed support and more context. + - The Third was the best as we can provide the rules and output format for it to give an output. +- **Step 5:** + - The final step is to run the loop and `regex` the output data and return them as an output. + - The reason for using regex is that `AI is unpredictable` so we need to take measures to keep our data usable. + - The prompt is used as an output format making sure the AI gives that output no matter what so we can easily regex that output. + + +AI code: +```python +def AI(analyze: str) -> dict[str, any]: + # Prompt about what the query is all about + prompt = f""" + Do a vulnerability analysis report on the following JSON data and + follow the following rules: + 1) Calculate the criticality score. + 2) Return all the open ports within the open_ports list. + 3) Return all the closed ports within the closed_ports list. + 4) Return all the filtered ports within the filtered_ports list. + + output format: {{ + "open_ports": [], + "closed_ports": [], + "filtered_ports": [], + "criticality_score": "" + }} + + data = {analize} + """ + try: + # A structure for the request + completion = openai.Completion.create( + engine=model_engine, + prompt=prompt, + max_tokens=1024, + n=1, + stop=None, + ) + response = completion.choices[0].text + + # Assuming extract_ai_output returns a dictionary + extracted_data = extract_ai_output(response) + except KeyboardInterrupt: + print("Bye") + quit() + + # Store outputs in a dictionary + ai_output = { + "open_ports": extracted_data.get("open_ports"), + "closed_ports": extracted_data.get("closed_ports"), + "filtered_ports": extracted_data.get("filtered_ports"), + "criticality_score": extracted_data.get("criticality_score") + } + + return ai_output +``` + +The Prompt, Regex and extraction: +```python + prompt = f""" + Do a vulnerability analysis report on the following JSON data provided. + It's the data extracted from my network scanner. + follow the following rules for analysis: + 1) Calculate the criticality score based on the service or CVE. + 2) Return all the open ports within the open_ports list. + 3) Return all the closed ports within the closed_ports list. + 4) Return all the filtered ports within the filtered_ports list. + 6) Keep the highest possible accuracy. + 7) Do not provide unwanted explanations. + 8) Only provide details in the output_format provided. + + output_format: {{ + "open_ports": [], + "closed_ports": [], + "filtered_ports": [], + "criticality_score": "" + }} + + data = {analize} + """ +``` + +The above-mentioned prompt as a distinct output format will return this output no matter the instance. These are the following things needed to be addressed: +- The prompt must be detailed. +- The prompt must explain all sorts of use cases and inputs. +- The prompt must be guided with rules to follow. +- The number of tokens must be monitored and taken care of. + +This is the regex for it: +```python +def extract_ai_output(ai_output: str) -> dict[str, Any]: + result = { + "open_ports": [], + "closed_ports": [], + "filtered_ports": [], + "criticality_score": "" + } + + # Match and extract ports + open_ports_match = re.search(r'"open_ports": \[([^\]]*)\]', ai_output) + closed_ports_match = re.search(r'"closed_ports": \[([^\]]*)\]', ai_output) + filtered_ports_match = re.search( + r'"filtered_ports": \[([^\]]*)\]', ai_output) + + # If found, convert string of ports to list + if open_ports_match: + result["open_ports"] = list( + map(cast(Callable[[Any], str], int), + open_ports_match.group(1).split(','))) + if closed_ports_match: + result["closed_ports"] = list( + map(cast(Callable[[Any], str], int), + closed_ports_match.group(1).split(','))) + if filtered_ports_match: + result["filtered_ports"] = list( + map(cast(Callable[[Any], str], int), + filtered_ports_match.group(1).split(','))) + + # Match and extract criticality score + criticality_score_match = re.search( + r'"criticality_score": "([^"]*)"', ai_output) + if criticality_score_match: + result["criticality_score"] = criticality_score_match.group(1) + + return result +``` +The regex makes sure all the data is extracted and returned properly within the proper type we wanted. +This also helps with the data management and removal of unwanted information. + +API Key must be mentioned +```python +openai.api_key = '__API__KEY__' +``` + +### Package +The package is a simple extension for future usage or upgrades it can be installed by running: +```bash +cd package && pip install . +``` +The Usage can be implemented like this: +```python +from nmap_api import app + +app.openai.api_key = '__API__KEY__' +app.start_api() + +``` + +#### Default User Keys +**Default_Key**: **cff649285012c6caae4d** diff --git a/package/nmap_api/app.py b/package/nmap_api/app.py index c75e3a2..894b96f 100644 --- a/package/nmap_api/app.py +++ b/package/nmap_api/app.py @@ -1,211 +1,211 @@ -import json -import re -from typing import Any -from typing import Callable -from typing import cast - -import nmap -import openai -from flask import Flask -from flask_restful import Api -from flask_restful import Resource - -openai.api_key = "__API__KEY__" -model_engine = "text-davinci-003" - -app = Flask(__name__) -api = Api(app) - -nm = nmap.PortScanner() - - -def to_int(s: str) -> int: - return int(s) - - -def sanitize(input_string: str) -> str: - if not re.match("^[a-zA-Z0-9]*$", input_string): - raise ValueError("Invalid characters in string") - else: - return input_string - - -def chunk_output( - scan_output: str, max_token_size: int -) -> list[dict[str, Any]]: - scan_output_dict = json.loads(scan_output) - output_chunks = [] - current_chunk = {} - current_token_count = 0 - - # Convert JSON to AI usable chunks - for ip, scan_data in scan_output_dict.items(): - new_data_token_count = len(json.dumps({ip: scan_data}).split()) - - if current_token_count + new_data_token_count <= max_token_size: - current_chunk[ip] = scan_data - current_token_count += new_data_token_count - else: - output_chunks.append(current_chunk) - current_chunk = {ip: scan_data} - current_token_count = new_data_token_count - # The Chunks list that is returned - if current_chunk: - output_chunks.append(current_chunk) - - return output_chunks - - -def AI(analize: str) -> dict[str, Any]: - # Prompt about what the query is all about - prompt = f""" - Do a vulnerability analysis report on the following JSON data and - follow the following rules: - 1) Calculate the criticality score. - 2) Return all the open ports within the open_ports list. - 3) Return all the closed ports within the closed_ports list. - 4) Return all the filtered ports within the filtered_ports list. - - output format: {{ - "open_ports": [], - "closed_ports": [], - "filtered_ports": [], - "criticality_score": "" - }} - - data = {analize} - """ - try: - # A structure for the request - completion = openai.Completion.create( - engine=model_engine, - prompt=prompt, - max_tokens=1024, - n=1, - stop=None, - ) - response = completion.choices[0]['text'] - - # Assuming extract_ai_output returns a dictionary - extracted_data = extract_ai_output(response) - except KeyboardInterrupt: - print("Bye") - quit() - - # Store outputs in a dictionary - ai_output = { - "open_ports": extracted_data.get("open_ports"), - "closed_ports": extracted_data.get("closed_ports"), - "filtered_ports": extracted_data.get("filtered_ports"), - "criticality_score": extracted_data.get("criticality_score") - } - - return ai_output - - -def extract_ai_output(ai_output: str) -> dict[str, Any]: - result = { - "open_ports": [], - "closed_ports": [], - "filtered_ports": [], - "criticality_score": "" - } - - # Match and extract ports - open_ports_match = re.search(r'"open_ports": \[([^\]]*)\]', ai_output) - closed_ports_match = re.search(r'"closed_ports": \[([^\]]*)\]', ai_output) - filtered_ports_match = re.search( - r'"filtered_ports": \[([^\]]*)\]', ai_output) - - # If found, convert string of ports to list - if open_ports_match: - result["open_ports"] = list( - map(cast(Callable[[Any], str], int), - open_ports_match.group(1).split(','))) - if closed_ports_match: - result["closed_ports"] = list( - map(cast(Callable[[Any], str], int), - closed_ports_match.group(1).split(','))) - if filtered_ports_match: - result["filtered_ports"] = list( - map(cast(Callable[[Any], str], int), - filtered_ports_match.group(1).split(','))) - - # Match and extract criticality score - criticality_score_match = re.search( - r'"criticality_score": "([^"]*)"', ai_output) - if criticality_score_match: - result["criticality_score"] = criticality_score_match.group(1) - - return result - - -def profile(url: str, argument: str) -> dict[str, Any]: - ip = url - # Nmap Execution command - nm.scan('{}'.format(ip), arguments='{}'.format(argument)) - scan_data = nm.analyse_nmap_xml_scan() - analize = scan_data["scan"] - chunk_data = str(chunk_output(analize, 500)) - all_outputs = [] - for chunks in chunk_data: - string_chunks = str(chunks) - data = AI(string_chunks) - all_outputs.append(data) - return json.dumps(all_outputs) - - -# Effective Scan -class p1(Resource): - def get(self, url): - argument = '-Pn -sV -T4 -O -F' - scan = profile(url, argument) - return scan - - -# Simple Scan -class p2(Resource): - def get(self, url): - argument = '-Pn -T4 -A -v' - scan = profile(url, argument) - return scan - - -# Low Power Scan -class p3(Resource): - def get(self, url): - argument = '-Pn -sS -sU -T4 -A -v' - scan = profile(url, argument) - return scan - - -# partial Intense Scan -class p4(Resource): - def get(self, url): - argument = '-Pn -p- -T4 -A -v' - scan = profile(url, argument) - return scan - - -# Complete Intense scan -class p5(Resource): - def get(self, url): - argument = '-Pn -sS -sU -T4 -A -PE -PP -PY -g 53 --script=vuln' - scan = profile(url, argument) - return scan - - -api.add_resource( - p1, "/api/p1/") -api.add_resource( - p2, "/api/p2/") -api.add_resource( - p3, "/api/p3/") -api.add_resource( - p4, "/api/p4/") -api.add_resource( - p5, "/api/p5/") - - -def start_api(): - app.run(host="0.0.0.0", port="80") +import json +import re +from typing import Any +from typing import Callable +from typing import cast + +import nmap +import openai +from flask import Flask +from flask_restful import Api +from flask_restful import Resource + +openai.api_key = "__API__KEY__" +model_engine = "text-davinci-003" + +app = Flask(__name__) +api = Api(app) + +nm = nmap.PortScanner() + + +def to_int(s: str) -> int: + return int(s) + + +def sanitize(input_string: str) -> str: + if not re.match("^[a-zA-Z0-9]*$", input_string): + raise ValueError("Invalid characters in string") + else: + return input_string + + +def chunk_output( + scan_output: str, max_token_size: int +) -> list[dict[str, Any]]: + scan_output_dict = json.loads(scan_output) + output_chunks = [] + current_chunk = {} + current_token_count = 0 + + # Convert JSON to AI usable chunks + for ip, scan_data in scan_output_dict.items(): + new_data_token_count = len(json.dumps({ip: scan_data}).split()) + + if current_token_count + new_data_token_count <= max_token_size: + current_chunk[ip] = scan_data + current_token_count += new_data_token_count + else: + output_chunks.append(current_chunk) + current_chunk = {ip: scan_data} + current_token_count = new_data_token_count + # The Chunks list that is returned + if current_chunk: + output_chunks.append(current_chunk) + + return output_chunks + + +def AI(analize: str) -> dict[str, Any]: + # Prompt about what the query is all about + prompt = f""" + Do a vulnerability analysis report on the following JSON data and + follow the following rules: + 1) Calculate the criticality score. + 2) Return all the open ports within the open_ports list. + 3) Return all the closed ports within the closed_ports list. + 4) Return all the filtered ports within the filtered_ports list. + + output format: {{ + "open_ports": [], + "closed_ports": [], + "filtered_ports": [], + "criticality_score": "" + }} + + data = {analize} + """ + try: + # A structure for the request + completion = openai.Completion.create( + engine=model_engine, + prompt=prompt, + max_tokens=1024, + n=1, + stop=None, + ) + response = completion.choices[0]['text'] + + # Assuming extract_ai_output returns a dictionary + extracted_data = extract_ai_output(response) + except KeyboardInterrupt: + print("Bye") + quit() + + # Store outputs in a dictionary + ai_output = { + "open_ports": extracted_data.get("open_ports"), + "closed_ports": extracted_data.get("closed_ports"), + "filtered_ports": extracted_data.get("filtered_ports"), + "criticality_score": extracted_data.get("criticality_score") + } + + return ai_output + + +def extract_ai_output(ai_output: str) -> dict[str, Any]: + result = { + "open_ports": [], + "closed_ports": [], + "filtered_ports": [], + "criticality_score": "" + } + + # Match and extract ports + open_ports_match = re.search(r'"open_ports": \[([^\]]*)\]', ai_output) + closed_ports_match = re.search(r'"closed_ports": \[([^\]]*)\]', ai_output) + filtered_ports_match = re.search( + r'"filtered_ports": \[([^\]]*)\]', ai_output) + + # If found, convert string of ports to list + if open_ports_match: + result["open_ports"] = list( + map(cast(Callable[[Any], str], int), + open_ports_match.group(1).split(','))) + if closed_ports_match: + result["closed_ports"] = list( + map(cast(Callable[[Any], str], int), + closed_ports_match.group(1).split(','))) + if filtered_ports_match: + result["filtered_ports"] = list( + map(cast(Callable[[Any], str], int), + filtered_ports_match.group(1).split(','))) + + # Match and extract criticality score + criticality_score_match = re.search( + r'"criticality_score": "([^"]*)"', ai_output) + if criticality_score_match: + result["criticality_score"] = criticality_score_match.group(1) + + return result + + +def profile(url: str, argument: str) -> dict[str, Any]: + ip = url + # Nmap Execution command + nm.scan('{}'.format(ip), arguments='{}'.format(argument)) + scan_data = nm.analyse_nmap_xml_scan() + analize = scan_data["scan"] + chunk_data = str(chunk_output(analize, 500)) + all_outputs = [] + for chunks in chunk_data: + string_chunks = str(chunks) + data = AI(string_chunks) + all_outputs.append(data) + return json.dumps(all_outputs) + + +# Effective Scan +class p1(Resource): + def get(self, url): + argument = '-Pn -sV -T4 -O -F' + scan = profile(url, argument) + return scan + + +# Simple Scan +class p2(Resource): + def get(self, url): + argument = '-Pn -T4 -A -v' + scan = profile(url, argument) + return scan + + +# Low Power Scan +class p3(Resource): + def get(self, url): + argument = '-Pn -sS -sU -T4 -A -v' + scan = profile(url, argument) + return scan + + +# partial Intense Scan +class p4(Resource): + def get(self, url): + argument = '-Pn -p- -T4 -A -v' + scan = profile(url, argument) + return scan + + +# Complete Intense scan +class p5(Resource): + def get(self, url): + argument = '-Pn -sS -sU -T4 -A -PE -PP -PY -g 53 --script=vuln' + scan = profile(url, argument) + return scan + + +api.add_resource( + p1, "/api/p1/") +api.add_resource( + p2, "/api/p2/") +api.add_resource( + p3, "/api/p3/") +api.add_resource( + p4, "/api/p4/") +api.add_resource( + p5, "/api/p5/") + + +def start_api(): + app.run(host="0.0.0.0", port="80") diff --git a/package/nmap_api/requirements.txt b/package/nmap_api/requirements.txt index 16ed133..46b4814 100644 --- a/package/nmap_api/requirements.txt +++ b/package/nmap_api/requirements.txt @@ -1,30 +1,30 @@ -aiohttp==3.8.4 -aiosignal==1.3.1 -aniso8601==9.0.1 -async-timeout==4.0.2 -attrs==22.2.0 -autopep8==2.0.2 -certifi==2022.12.7 -charset-normalizer==3.1.0 -click==8.1.3 -colorama==0.4.6 -Flask==2.2.3 -Flask-RESTful==0.3.9 -frozenlist==1.3.3 -idna==3.4 -itsdangerous==2.1.2 -Jinja2==3.1.2 -lxml==4.9.2 -MarkupSafe==2.1.2 -multidict==6.0.4 -openai==0.27.4 -pycodestyle==2.10.0 -python-nmap==0.7.1 -pytz==2023.3 -requests==2.28.2 -six==1.16.0 -tomli==2.0.1 -tqdm==4.65.0 -urllib3==1.26.15 -Werkzeug==2.2.3 +aiohttp==3.8.4 +aiosignal==1.3.1 +aniso8601==9.0.1 +async-timeout==4.0.2 +attrs==22.2.0 +autopep8==2.0.2 +certifi==2022.12.7 +charset-normalizer==3.1.0 +click==8.1.3 +colorama==0.4.6 +Flask==2.2.3 +Flask-RESTful==0.3.9 +frozenlist==1.3.3 +idna==3.4 +itsdangerous==2.1.2 +Jinja2==3.1.2 +lxml==4.9.2 +MarkupSafe==2.1.2 +multidict==6.0.4 +openai==0.27.4 +pycodestyle==2.10.0 +python-nmap==0.7.1 +pytz==2023.3 +requests==2.28.2 +six==1.16.0 +tomli==2.0.1 +tqdm==4.65.0 +urllib3==1.26.15 +Werkzeug==2.2.3 yarl==1.8.2 \ No newline at end of file diff --git a/package/pyproject.toml b/package/pyproject.toml index b97ef93..d754819 100644 --- a/package/pyproject.toml +++ b/package/pyproject.toml @@ -1,6 +1,6 @@ -[build-system] -requires = [ - "setuptools>=54", - "wheel" -] +[build-system] +requires = [ + "setuptools>=54", + "wheel" +] build-backend = "setuptools.build_meta" \ No newline at end of file diff --git a/package/setup.cfg b/package/setup.cfg index e355fe0..3c75a9f 100644 --- a/package/setup.cfg +++ b/package/setup.cfg @@ -1,18 +1,18 @@ -[metadata] -name = Nmap_API -version = 0.1.1 -author = Chiranjeevi G -author_email = morpheuslord@protonmail.com -description = Nmap API vuln analysis with python and ChatGPT -long_description = file: README.md -long_description_content_type = text/markdown -url = https://github.com/morpheuslord/Nmap-API -classifiers = - Programming Language :: Python :: 3 - License :: OSI Approved :: MIT License - Operating System :: OS Independent - -[options] -packages = find: -python_requires = >=3.10 -include_package_data = True +[metadata] +name = Nmap_API +version = 0.1.1 +author = Chiranjeevi G +author_email = morpheuslord@protonmail.com +description = Nmap API vuln analysis with python and ChatGPT +long_description = file: README.md +long_description_content_type = text/markdown +url = https://github.com/morpheuslord/Nmap-API +classifiers = + Programming Language :: Python :: 3 + License :: OSI Approved :: MIT License + Operating System :: OS Independent + +[options] +packages = find: +python_requires = >=3.10 +include_package_data = True diff --git a/package/setup.py b/package/setup.py index c92edc5..3e47b95 100644 --- a/package/setup.py +++ b/package/setup.py @@ -1,73 +1,73 @@ -from setuptools import setup, find_packages -import codecs -import os - -here = os.path.abspath(os.path.dirname(__file__)) - -with codecs.open(os.path.join(here, "README.md"), encoding="utf-8") as fh: - long_description = "\n" + fh.read() - -VERSION = '0.1.1' -DESCRIPTION = 'Python Project for Nmap-API with GPT integration' -LONG_DESCRIPTION = """ -Uses python3.10, Debian, python-Nmap, and flask framework -to create a Nmap API that can do scans with a good speed -online and is easy to deploy. This is a implementation -for our college PCL project which is still under -development and constantly updating. -""" - -# Setting up -setup( - name="Nmap_API", - version=VERSION, - author="Chiranjeevi G", - author_email="morpheuslord@protonmail.com", - description=DESCRIPTION, - long_description_content_type="text/markdown", - long_description=long_description, - packages=find_packages(), - package_data={ - 'nmap_api': ['nmap_api/auth_keys.db'], - }, - install_requires=['aiohttp==3.8.4', - 'aiosignal==1.3.1', - 'aniso8601==9.0.1', - 'async-timeout==4.0.2', - 'attrs==22.2.0', - 'autopep8==2.0.2', - 'certifi==2022.12.7', - 'charset-normalizer==3.1.0', - 'click==8.1.3', - 'colorama==0.4.6', - 'Flask==2.2.3', - 'Flask-RESTful==0.3.9', - 'frozenlist==1.3.3', - 'idna==3.4', - 'itsdangerous==2.1.2', - 'Jinja2==3.1.2', - 'lxml==4.9.2', - 'MarkupSafe==2.1.2', - 'multidict==6.0.4', - 'openai==0.27.4', - 'pycodestyle==2.10.0', - 'python-nmap==0.7.1', - 'pytz==2023.3', - 'requests==2.28.2', - 'six==1.16.0', - 'tomli==2.0.1', - 'tqdm==4.65.0', - 'urllib3==1.26.15', - 'Werkzeug==2.2.3', - 'yarl==1.8.2'], - keywords=['python', 'GPT', 'vulnerability', - 'ai', 'vulnerability-assessment', 'network-scanning'], - classifiers=[ - "Development Status :: 1 - Planning", - "Intended Audience :: Developers", - "Programming Language :: Python :: 3", - "Operating System :: Unix", - "Operating System :: MacOS :: MacOS X", - "Operating System :: Microsoft :: Windows", - ] -) +from setuptools import setup, find_packages +import codecs +import os + +here = os.path.abspath(os.path.dirname(__file__)) + +with codecs.open(os.path.join(here, "README.md"), encoding="utf-8") as fh: + long_description = "\n" + fh.read() + +VERSION = '0.1.1' +DESCRIPTION = 'Python Project for Nmap-API with GPT integration' +LONG_DESCRIPTION = """ +Uses python3.10, Debian, python-Nmap, and flask framework +to create a Nmap API that can do scans with a good speed +online and is easy to deploy. This is a implementation +for our college PCL project which is still under +development and constantly updating. +""" + +# Setting up +setup( + name="Nmap_API", + version=VERSION, + author="Chiranjeevi G", + author_email="morpheuslord@protonmail.com", + description=DESCRIPTION, + long_description_content_type="text/markdown", + long_description=long_description, + packages=find_packages(), + package_data={ + 'nmap_api': ['nmap_api/auth_keys.db'], + }, + install_requires=['aiohttp==3.8.4', + 'aiosignal==1.3.1', + 'aniso8601==9.0.1', + 'async-timeout==4.0.2', + 'attrs==22.2.0', + 'autopep8==2.0.2', + 'certifi==2022.12.7', + 'charset-normalizer==3.1.0', + 'click==8.1.3', + 'colorama==0.4.6', + 'Flask==2.2.3', + 'Flask-RESTful==0.3.9', + 'frozenlist==1.3.3', + 'idna==3.4', + 'itsdangerous==2.1.2', + 'Jinja2==3.1.2', + 'lxml==4.9.2', + 'MarkupSafe==2.1.2', + 'multidict==6.0.4', + 'openai==0.27.4', + 'pycodestyle==2.10.0', + 'python-nmap==0.7.1', + 'pytz==2023.3', + 'requests==2.28.2', + 'six==1.16.0', + 'tomli==2.0.1', + 'tqdm==4.65.0', + 'urllib3==1.26.15', + 'Werkzeug==2.2.3', + 'yarl==1.8.2'], + keywords=['python', 'GPT', 'vulnerability', + 'ai', 'vulnerability-assessment', 'network-scanning'], + classifiers=[ + "Development Status :: 1 - Planning", + "Intended Audience :: Developers", + "Programming Language :: Python :: 3", + "Operating System :: Unix", + "Operating System :: MacOS :: MacOS X", + "Operating System :: Microsoft :: Windows", + ] +) diff --git a/setuo.cfg b/setuo.cfg new file mode 100644 index 0000000..4fae008 --- /dev/null +++ b/setuo.cfg @@ -0,0 +1,25 @@ +[flake8] +format = pylint +max-line-length = 120 + +[pep8] +max-line-length = 120 + +[mypy] +disable_error_code = import +disallow_any_generics = false +disallow_untyped_decorators = true +implicit_reexport = false +show_error_codes = true +warn_redundant_casts = true +warn_unused_configs = true +warn_unused_ignores = true +# required for `warn_unused_configs = true` +incremental = true +check_untyped_defs = true +disallow_incomplete_defs = true +disallow_untyped_calls = true +disallow_untyped_defs = true +strict_equality = true +no_implicit_optional = true +warn_unreachable = true diff --git a/static/index.js b/static/index.js index b4a08e2..26b35d4 100644 --- a/static/index.js +++ b/static/index.js @@ -12,7 +12,7 @@ $(document).ready(function(){ }); }); -var width = $(window).width(); +var width = $(window).width(); window.onscroll = function(){ if ((width >= 900)){ diff --git a/templates/404.html b/templates/404.html index 94390d3..cfd45a4 100644 --- a/templates/404.html +++ b/templates/404.html @@ -3,9 +3,9 @@ or any file you want--> {% block title %}Page Not Found{% endblock %} {% block body %} - +

Oops! Looks like the page doesn't exist anymore

To go to the Home Page

- + -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/templates/add.html b/templates/add.html index d97cb6b..fab2867 100644 --- a/templates/add.html +++ b/templates/add.html @@ -16,4 +16,4 @@

Add User To Database

-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/templates/base.html b/templates/base.html index 43051da..b013399 100644 --- a/templates/base.html +++ b/templates/base.html @@ -232,21 +232,21 @@ color: #fff; text-decoration: none; } - + .made-with-love a:hover { text-decoration: underline; } - + ::-webkit-scrollbar { width: 6px; - } + } ::-webkit-scrollbar-track { - -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); - } - + -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); + } + ::-webkit-scrollbar-thumb { - -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); + -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); } table{ @@ -311,7 +311,7 @@ .container td, .container th { padding-bottom: 2%; padding-top: 2%; - padding-left:2%; + padding-left:2%; } .container tr:nth-child(odd) { @@ -555,13 +555,13 @@ height:5px; } ::-webkit-scrollbar-track { - background: #f1f1f1; + background: #f1f1f1; } ::-webkit-scrollbar-thumb { - background: #000; + background: #000; } ::-webkit-scrollbar-thumb:hover { - background: #555; + background: #555; } @-webkit-keyframes Gradient { 0% {background-position: 0% 50%} diff --git a/templates/del.html b/templates/del.html index 8a7a80d..38ae237 100644 --- a/templates/del.html +++ b/templates/del.html @@ -15,4 +15,4 @@

Delete User from Database

-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/templates/index.css b/templates/index.css index a378001..33ae2b1 100644 --- a/templates/index.css +++ b/templates/index.css @@ -149,21 +149,21 @@ body,html { color: #fff; text-decoration: none; } - + .made-with-love a:hover { text-decoration: underline; } - + ::-webkit-scrollbar { width: 6px; - } + } ::-webkit-scrollbar-track { - -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); - } - + -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); + } + ::-webkit-scrollbar-thumb { - -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); + -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); } table{ @@ -228,7 +228,7 @@ table{ .container td, .container th { padding-bottom: 2%; padding-top: 2%; - padding-left:2%; + padding-left:2%; } .container tr:nth-child(odd) { @@ -472,13 +472,13 @@ button:focus { height:5px; } ::-webkit-scrollbar-track { - background: #f1f1f1; + background: #f1f1f1; } ::-webkit-scrollbar-thumb { - background: #000; + background: #000; } ::-webkit-scrollbar-thumb:hover { - background: #555; + background: #555; } @-webkit-keyframes Gradient { 0% {background-position: 0% 50%} diff --git a/templates/index.js b/templates/index.js index b4a08e2..26b35d4 100644 --- a/templates/index.js +++ b/templates/index.js @@ -12,7 +12,7 @@ $(document).ready(function(){ }); }); -var width = $(window).width(); +var width = $(window).width(); window.onscroll = function(){ if ((width >= 900)){ diff --git a/templates/results.html b/templates/results.html index 1c54c88..b637816 100644 --- a/templates/results.html +++ b/templates/results.html @@ -1 +1 @@ -
nmap
command_linenmap -oX - -Pn -sV -T4 -O -F 127.0.0.1
scaninfo
tcp
methodsyn
services7,9,13,21-23,25-26,37,53,79-81,88,106,110-111,113,119,135,139,143-144,179,199,389,427,443-445,465,513-515,543-544,548,554,587,631,646,873,990,993,995,1025-1029,1110,1433,1720,1723,1755,1900,2000-2001,2049,2121,2717,3000,3128,3306,3389,3986,4899,5000,5009,5051,5060,5101,5190,5357,5432,5631,5666,5800,5900,6000-6001,6646,7070,8000,8008-8009,8080-8081,8443,8888,9100,9999-10000,32768,49152-49157
scanstats
timestrFri Oct 21 10:58:48 2022
elapsed8.78
uphosts1
downhosts0
totalhosts1
scan
127.0.0.1
hostnames
nametype
kubernetes.docker.internalPTR
addresses
ipv4127.0.0.1
vendor
status
stateup
reasonuser-set
uptime
seconds8067
lastbootFri Oct 21 08:44:21 2022
tcp
135
stateopen
reasonsyn-ack
namemsrpc
productMicrosoft Windows RPC
version
extrainfo
conf10
cpecpe:/o:microsoft:windows
445
stateopen
reasonsyn-ack
namemicrosoft-ds
product
version
extrainfo
conf3
cpe
3306
stateopen
reasonsyn-ack
namemysql
productMySQL
version8.0.30
extrainfo
conf10
cpecpe:/a:mysql:mysql:8.0.30
5000
stateopen
reasonsyn-ack
namehttp
productWerkzeug httpd
version1.0.1
extrainfoPython 3.10.7
conf10
cpecpe:/a:python:python:3.10.7
portused
stateprotoportid
opentcp135
closedtcp7
closedudp37469
osmatch
nameaccuracylineosclass
Microsoft Windows 10 160710069751
typevendorosfamilyosgenaccuracycpe
general purposeMicrosoftWindows10100
  • cpe:/o:microsoft:windows_10:1607
\ No newline at end of file +
nmap
command_linenmap -oX - -Pn -sV -T4 -O -F 127.0.0.1
scaninfo
tcp
methodsyn
services7,9,13,21-23,25-26,37,53,79-81,88,106,110-111,113,119,135,139,143-144,179,199,389,427,443-445,465,513-515,543-544,548,554,587,631,646,873,990,993,995,1025-1029,1110,1433,1720,1723,1755,1900,2000-2001,2049,2121,2717,3000,3128,3306,3389,3986,4899,5000,5009,5051,5060,5101,5190,5357,5432,5631,5666,5800,5900,6000-6001,6646,7070,8000,8008-8009,8080-8081,8443,8888,9100,9999-10000,32768,49152-49157
scanstats
timestrFri Oct 21 10:58:48 2022
elapsed8.78
uphosts1
downhosts0
totalhosts1
scan
127.0.0.1
hostnames
nametype
kubernetes.docker.internalPTR
addresses
ipv4127.0.0.1
vendor
status
stateup
reasonuser-set
uptime
seconds8067
lastbootFri Oct 21 08:44:21 2022
tcp
135
stateopen
reasonsyn-ack
namemsrpc
productMicrosoft Windows RPC
version
extrainfo
conf10
cpecpe:/o:microsoft:windows
445
stateopen
reasonsyn-ack
namemicrosoft-ds
product
version
extrainfo
conf3
cpe
3306
stateopen
reasonsyn-ack
namemysql
productMySQL
version8.0.30
extrainfo
conf10
cpecpe:/a:mysql:mysql:8.0.30
5000
stateopen
reasonsyn-ack
namehttp
productWerkzeug httpd
version1.0.1
extrainfoPython 3.10.7
conf10
cpecpe:/a:python:python:3.10.7
portused
stateprotoportid
opentcp135
closedtcp7
closedudp37469
osmatch
nameaccuracylineosclass
Microsoft Windows 10 160710069751
typevendorosfamilyosgenaccuracycpe
general purposeMicrosoftWindows10100
  • cpe:/o:microsoft:windows_10:1607
diff --git a/templates/results.json b/templates/results.json index 879995e..b725c30 100644 --- a/templates/results.json +++ b/templates/results.json @@ -189,4 +189,4 @@ "@level": "0" } } -} \ No newline at end of file +} diff --git a/templates/scanner.html b/templates/scanner.html index 2d24955..b10b649 100644 --- a/templates/scanner.html +++ b/templates/scanner.html @@ -53,4 +53,4 @@

Scanner Input Section

-{% endblock %} \ No newline at end of file +{% endblock %}