Skip to content

Commit

Permalink
Initial Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
sh4dowByte committed Sep 15, 2024
0 parents commit 54e1116
Show file tree
Hide file tree
Showing 18 changed files with 1,300 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/app/cache/*
__pycache__
test.py
.DS_Store
21 changes: 21 additions & 0 deletions LICENSE
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.
45 changes: 45 additions & 0 deletions README.md
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.
10 changes: 10 additions & 0 deletions app/config.py
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'
130 changes: 130 additions & 0 deletions app/git_downloader.py
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}")
73 changes: 73 additions & 0 deletions app/repository/cisa.py
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
82 changes: 82 additions & 0 deletions app/repository/cve_github.py
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
Loading

0 comments on commit 54e1116

Please sign in to comment.