-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 54e1116
Showing
18 changed files
with
1,300 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
/app/cache/* | ||
__pycache__ | ||
test.py | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2024 Ahmad Juhdi | ||
|
||
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
<p align="center"> | ||
<img src="icon.png" alt="app" width="300"> | ||
</p> | ||
|
||
<p align="center"> | ||
<img src="https://badgen.net/badge/Python/≥3.12.2/yellow?icon=pypi" alt="Python Badge" style="max-width: 100%;"> | ||
<img src="https://badgen.net/badge/Learning/Purposes/purple?icon=terminal" alt="Learning Badge" style="max-width: 100%;"> | ||
<img src="https://badgen.net/badge/Under/Development/blue?icon=github" alt="Development Badge" style="max-width: 100%;"> | ||
</p> | ||
|
||
## 📜 Description | ||
|
||
**Delta** is an **Exploit Discovery Tool** designed to search for vulnerabilities based on CVE (Common Vulnerabilities and Exposures) or CWE (Common Weakness Enumeration). Delta is intended for use in security assessments and vulnerability discovery. | ||
|
||
### Key Features: | ||
|
||
- **CVE/CWE Search**: Allows users to perform searches for vulnerabilities based on CVE identifiers or CWE types. | ||
- **Broad Vulnerability Search**: Allows users to search for vulnerabilities across a wide range of software, technologies, and systems beyond CVE and CWE, including server technologies (e.g., Apache, Nginx), desktop applications, network devices, and more. | ||
- **Software and Technology Search**: Enables users to perform searches based on specific software, technologies, or systems, such as databases, content management systems (CMS), development frameworks, and more. | ||
- **Customizable Queries**: Enables users to specify search terms and parameters for tailored vulnerability discovery. | ||
- **Detailed Results**: Provides comprehensive details about discovered vulnerabilities, including descriptions and associated data. | ||
- **User-Friendly CLI**: Provides a command-line interface that formats query results in a clear and easily readable manner, improving the readability and accessibility of vulnerability information. | ||
|
||
### Learning Objectives: | ||
|
||
- **Understanding Vulnerability Discovery**: Learn about the role of CVE and CWE in identifying and understanding software vulnerabilities. | ||
- **Python Programming**: Enhance skills in Python programming, particularly in making API requests and handling JSON data. | ||
- **Application Development**: Understand techniques for developing CLI tools, with a focus on querying and reporting vulnerabilities. | ||
|
||
**Note**: Delta is designed for educational and testing purposes. Ensure to use this application in a responsible and legal manner, following relevant cybersecurity guidelines and ethics. | ||
|
||
## 🛠️ Reference Tools | ||
|
||
- **[SploitScan](https://github.com/xaitax/SploitScan/)** - A powerful vulnerability and exploit discovery tool focusing on scanning and finding vulnerabilities efficiently. | ||
|
||
## 📚 Reference Data | ||
|
||
- **[Nuclei](https://nuclei.projectdiscovery.io)** - A fast and customizable vulnerability scanner based on templates. | ||
- **[ExploitDB](https://www.exploit-db.com)** - A database of exploits and vulnerable software for security researchers and penetration testers. | ||
- **[PoC-in-GitHub](https://github.com/nomi-sec/PoC-in-GitHub)** - A repository that contains proof-of-concept exploits and vulnerabilities. | ||
- **[HackerOne](https://hackerone.com)** - A platform for bug bounty programs and vulnerability reporting. | ||
- **[CISA](https://www.cisa.gov)** - U.S. Cybersecurity and Infrastructure Security Agency, providing cybersecurity alerts and tools. | ||
- **[CVE List](https://github.com/CVEProject/cvelistV5)** - GitHub repository of CVEs (Common Vulnerabilities and Exposures) maintained by the CVE Program. | ||
- **[API First](https://api.first.org)** - API providing real-time threat intelligence, security data, and vulnerability information. | ||
- **[Metasploit](https://www.metasploit.com)** - A powerful open-source penetration testing framework for developing and executing exploit code against remote targets. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
class App: | ||
""" | ||
The App class defines basic configurations and attributes for the application. | ||
Attributes: | ||
version (str): Specifies the current version of the application. | ||
cache_path (str): Defines the default path where cached files will be stored. | ||
""" | ||
version = '1.0.0' | ||
cache_path = 'app/cache' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
import os | ||
import json | ||
import requests | ||
import zipfile | ||
from tqdm import tqdm | ||
|
||
from app.utils.style import Colors | ||
|
||
class GitDownloader: | ||
def __init__(self): | ||
""" | ||
Initializes the GitDownloader class. | ||
Sets up necessary paths for caching and storing ETag information. | ||
Creates the cache directory if it doesn't already exist. | ||
""" | ||
self.app_dir = os.path.join(os.getcwd(), 'app', 'cache') | ||
self.etag_file = os.path.join(self.app_dir, 'etag.json') | ||
self.zip_path = os.path.join(self.app_dir, 'cache.zip') | ||
|
||
# Create cache folder if it doesn't exist | ||
if not os.path.exists(self.app_dir): | ||
os.makedirs(self.app_dir) | ||
|
||
def get_etag(self): | ||
""" | ||
Retrieves the saved ETag for the current URL from the etag.json file, if it exists. | ||
Returns: | ||
str or None: The ETag value if available, otherwise None. | ||
""" | ||
if os.path.exists(self.etag_file): | ||
with open(self.etag_file, 'r') as f: | ||
etag_data = json.load(f) | ||
return etag_data.get(self.url) | ||
return None | ||
|
||
def save_etag(self, etag): | ||
""" | ||
Saves the new ETag for the current URL to etag.json. | ||
Args: | ||
etag (str): The new ETag value to be saved. | ||
""" | ||
etag_data = {} | ||
if os.path.exists(self.etag_file): | ||
with open(self.etag_file, 'r') as f: | ||
etag_data = json.load(f) | ||
|
||
etag_data[self.url] = etag | ||
|
||
with open(self.etag_file, 'w') as f: | ||
json.dump(etag_data, f, indent=4) | ||
|
||
def extract_specific_folder(self, zip_path, target_folder, extract_to): | ||
""" | ||
Extracts only the specified folder from a ZIP archive. | ||
Args: | ||
zip_path (str): Path to the ZIP file. | ||
target_folder (str): The folder inside the ZIP file to be extracted. | ||
extract_to (str): The path to the directory where the files will be extracted. | ||
""" | ||
with zipfile.ZipFile(zip_path, 'r') as z: | ||
for file_info in z.infolist(): | ||
# Check if the file is inside the target folder | ||
if file_info.filename.startswith(target_folder): | ||
# Determine extraction path | ||
extract_path = os.path.join(extract_to, file_info.filename) | ||
|
||
if file_info.is_dir(): | ||
os.makedirs(extract_path, exist_ok=True) | ||
else: | ||
with open(extract_path, 'wb') as f: | ||
f.write(z.read(file_info.filename)) | ||
|
||
def download_and_extract(self, url, name='', target_folder=''): | ||
""" | ||
Main function to download and extract the ZIP file if changes are detected based on the ETag. | ||
Args: | ||
url (str): The URL to download the ZIP file from. | ||
name (str): A friendly name for the download, used in the status messages. | ||
target_folder (str): The folder inside the ZIP file to extract. | ||
The function checks if the remote content has changed by comparing the ETag. | ||
If changes are detected, it downloads and extracts the specified folder from the ZIP file. | ||
""" | ||
self.url = url | ||
etag = self.get_etag() | ||
|
||
# Add ETag to headers if available | ||
headers = {} | ||
if etag: | ||
headers['If-None-Match'] = etag | ||
|
||
# Send request to check for updates | ||
response = requests.get(self.url, headers=headers, stream=True) | ||
|
||
if response.status_code == 304: | ||
# No updates, skipping download | ||
print(f"No updates {Colors.text(name)} found. Skipping download.") | ||
return | ||
elif response.status_code == 200: | ||
# Update found, proceed with download | ||
print(f"Updates {Colors.text(name)} found. Downloading new file...") | ||
|
||
# Total size of the file for progress bar | ||
total_size = int(response.headers.get('content-length', 0)) | ||
|
||
# Download the file with progress bar | ||
with open(self.zip_path, 'wb') as f: | ||
for data in tqdm(response.iter_content(1024), total=total_size // 1024, unit='KB'): | ||
f.write(data) | ||
|
||
# Extract the specific folder from the ZIP | ||
self.extract_specific_folder(self.zip_path, target_folder, self.app_dir) | ||
|
||
# Remove the ZIP file after extraction is done | ||
os.remove(self.zip_path) | ||
|
||
# Save the new ETag | ||
new_etag = response.headers.get('ETag') | ||
if new_etag: | ||
self.save_etag(new_etag) | ||
|
||
print(f"Download and extraction {Colors.text(name)} completed. Files extracted to {self.app_dir}, and the ZIP file has been removed.") | ||
|
||
else: | ||
# Error handling if request fails | ||
print(f"Error: Unable to download {name}. HTTP Status Code: {response.status_code}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import requests | ||
from rich.console import Console | ||
from rich.tree import Tree | ||
|
||
from app.utils.style import Colors | ||
|
||
class Cisa: | ||
def __init__(self): | ||
""" | ||
Initializes the Cisa class with the base URL for the known exploited vulnerabilities JSON feed | ||
from CISA and sets default headers for requests. | ||
""" | ||
self.base_url = ( | ||
"https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json" | ||
) | ||
self.headers = {} | ||
|
||
def search(self, cve_id, title = ''): | ||
""" | ||
Searches for a specific CVE ID or CWE in the CISA known exploited vulnerabilities database. | ||
If a match is found, it displays detailed information about the vulnerability using a rich tree structure. | ||
Args: | ||
cve_id (str): The CVE ID or CWE to search for in the CISA database. | ||
""" | ||
url = self.base_url | ||
response = requests.get(url, headers=self.headers) | ||
|
||
# If the response is successful, process the data | ||
if response.status_code == 200: | ||
vulnerabilities = response.json()['vulnerabilities'] | ||
|
||
# Initialize Rich Console and Tree for structured output | ||
tree = Tree(title) | ||
|
||
# Filter the vulnerabilities that match the given CVE ID or CWE | ||
filtered_vulnerability = [ | ||
vuln for vuln in vulnerabilities | ||
if cve_id in vuln["cveID"] or cve_id in vuln.get("cwes", []) | ||
] | ||
|
||
# Iterate through the filtered vulnerabilities and display detailed information | ||
for cisa in filtered_vulnerability: | ||
data_node = tree.add(f"[green]{cisa["cveID"]}[/green]") # Add CVE ID to the tree | ||
data_node.add(f"Name : {cisa['vendorProject']}") # Vendor name | ||
data_node.add(f"Product : {cisa['product']}") # Product name | ||
data_node.add(f"Vulnerability Name : {cisa['vulnerabilityName']}") # Vulnerability name | ||
data_node.add(f"Date Add : {cisa['dateAdded']}") # Date when vulnerability was added | ||
data_node.add(f"Required Action : {cisa['requiredAction']}") # Required action for mitigation | ||
data_node.add(f"Due Date : {cisa['dueDate']}") # Mitigation due date | ||
|
||
# Highlight known ransomware campaigns | ||
data_node.add(f"Ransomware : {f"[purple]{cisa['knownRansomwareCampaignUse']}[/purple]" if cisa['knownRansomwareCampaignUse'] == 'Known' else f"[yellow]{cisa['knownRansomwareCampaignUse']}[/yellow]"}") | ||
|
||
# If there are CWE references, display them | ||
if cisa.get('cwes'): | ||
reference_node = data_node.add("CWE") # Add a node for CWE references | ||
for ref in cisa['cwes']: | ||
reference_node.add(f"{ref}") # Add each CWE to the tree | ||
|
||
# Add short description of the vulnerability | ||
short_node = data_node.add("Short Description") | ||
short_node.add(cisa['shortDescription']) | ||
|
||
# Add notes or additional information | ||
notes_node = data_node.add("Notes") | ||
notes_node.add(cisa['notes']) | ||
|
||
# If no vulnerabilities were found, notify the user | ||
if not filtered_vulnerability: | ||
tree.add(f"[yellow]CVE or CWE not detected[/yellow]") | ||
|
||
return tree |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import json | ||
import time | ||
import requests | ||
|
||
from rich.tree import Tree | ||
|
||
from app.utils.style import Colors | ||
|
||
class CveGithub: | ||
def __init__(self): | ||
""" | ||
Initializes the CVEList class with the base URL for fetching CVE data | ||
from the CVEProject's GitHub repository and sets default headers for requests. | ||
""" | ||
self.base_url = "https://raw.githubusercontent.com/CVEProject/cvelistV5/main/cves" | ||
self.headers = {} | ||
|
||
def search(self, cve, title = ''): | ||
|
||
""" | ||
Fetches and displays detailed information about a specific CVE from the CVE list. | ||
The data is retrieved from a JSON file hosted in the CVEProject's GitHub repository. | ||
Args: | ||
cve (str): The CVE ID to be searched, e.g., "CVE-2021-12345". | ||
""" | ||
|
||
tree = Tree(title) | ||
try: | ||
# Convert CVE ID to uppercase | ||
cve = cve.upper() | ||
|
||
# Split the CVE ID to extract the year and the numeric part | ||
cve_year = cve.split("-")[1] | ||
|
||
cve_num = int(cve.split("-")[2]) | ||
|
||
# Construct the URL for the CVE JSON file | ||
url = f"{self.base_url}/{cve_year}/{cve_num // 1000}xxx/{cve}.json" | ||
|
||
# Send the GET request to retrieve the CVE data | ||
response = requests.get(url, headers=self.headers) | ||
|
||
# Attempt to parse the response as JSON | ||
data = response.json() # Raise a JSONDecodeError if the response is not valid JSON | ||
|
||
# Initialize Rich Console and Tree for displaying the CVE details | ||
|
||
# Add CVE details to the tree | ||
data_node = tree.add(Colors.text(data['cveMetadata']['cveId'])) # CVE ID | ||
|
||
data_node.add(f"Published : {data['cveMetadata']['datePublished']}") # Date published | ||
|
||
if data.get('containers', {}).get('cna', {}).get('metcrics'): | ||
data_node.add(f"Best Score : {data['containers']['cna']['metrics'][0]['cvssV3_1']['baseScore']}") # CVSS base score | ||
data_node.add(f"Vector : {data['containers']['cna']['metrics'][0]['cvssV3_1']['vectorString']}") # CVSS vector | ||
|
||
short_node = data_node.add("Description") | ||
short_node.add(data['containers']['cna']['descriptions'][0]['value'].replace('\n\n', '')) | ||
|
||
except requests.exceptions.RequestException as e: | ||
# Handle network-related errors, such as connection issues or timeouts | ||
tree.add(f"Error: [red]Request error: {e}[/red]") | ||
|
||
|
||
except json.JSONDecodeError: | ||
# Handle errors when the response is not a valid JSON | ||
tree.add(f"Error: [red]Error decoding JSON response.[/red]") | ||
|
||
except KeyError: | ||
# Handle missing keys in the JSON structure (if the CVE data is incomplete) | ||
tree.add(f"Error: [red]CVE data structure is incomplete or incorrect.[/red]") | ||
|
||
except Exception as e: | ||
|
||
# Catch-all for other exceptions | ||
if 'list index out of range' not in str(e): | ||
tree.add(f"Error: [red]An unexpected error occurred: {e}[/red]") | ||
else: | ||
tree.add(f"[yellow]CVE not detected[/yellow]") | ||
|
||
return tree |
Oops, something went wrong.