From d8a4f66b97a78578fb7213b60932a46c38116f65 Mon Sep 17 00:00:00 2001 From: ch0ic3 Date: Sun, 15 Dec 2024 05:59:45 -0800 Subject: [PATCH] initial commit --- feeds/advisories.txt | 7 ++ feeds/alerts.txt | 0 feeds/bugbounty.txt | 20 ++++ feeds/feeds.txt | 157 ++++++++++++++++++++++++ lists/github_users.txt | 9 ++ newsbot.py | 221 ++++++++++++++++++++++++++++++++++ test2.py | 263 +++++++++++++++++++++++++++++++++++++++++ youtubes.txt | 80 +++++++++++++ ytmonitor.py | 162 +++++++++++++++++++++++++ 9 files changed, 919 insertions(+) create mode 100644 feeds/advisories.txt create mode 100644 feeds/alerts.txt create mode 100644 feeds/bugbounty.txt create mode 100644 feeds/feeds.txt create mode 100644 lists/github_users.txt create mode 100644 newsbot.py create mode 100644 test2.py create mode 100644 youtubes.txt create mode 100644 ytmonitor.py diff --git a/feeds/advisories.txt b/feeds/advisories.txt new file mode 100644 index 0000000..55bb265 --- /dev/null +++ b/feeds/advisories.txt @@ -0,0 +1,7 @@ +https://isc.sans.edu/rssfeed_full.xml +https://us-cert.cisa.gov/ics/advisories/advisories.xml +https://us-cert.cisa.gov/ncas/analysis-reports.xml +https://www.cisecurity.org/feed/advisories +https://nao-sec.org/feed +https://www.ncsc.gov.uk/api/1/services/v1/report-rss-feed.xml +https://www.ncsc.gov.uk/api/1/services/v1/guidance-rss-feed.xml \ No newline at end of file diff --git a/feeds/alerts.txt b/feeds/alerts.txt new file mode 100644 index 0000000..e69de29 diff --git a/feeds/bugbounty.txt b/feeds/bugbounty.txt new file mode 100644 index 0000000..748df50 --- /dev/null +++ b/feeds/bugbounty.txt @@ -0,0 +1,20 @@ +https://medium.com/feed/bugbountywriteup/tagged/bug-bounty +https://blog.intigriti.com/feed/ +https://github.blog/tag/bug-bounty/feed/ +https://medium.com/feed/immunefi +https://ysamm.com/?feed=rss2 +https://www.openbugbounty.org/blog/feed/ +https://bugbounter.com/feed/ +https://infosecwriteups.com/feed +https://blog.detectify.com/feed +https://portswigger.net/research/rss +https://blog.zsec.uk/feed +https://www.pmnh.site/index.xml +https://buer.haus/feed +https://blog.appsecco.com/feed +https://0xdf.gitlab.io/feed.xml +https://securitytrails.com/blog.rss +https://www.n00py.io/feed +https://itm4n.github.io/feed +https://spaceraccoon.dev/feed.xml +https://sploitus.com/rss \ No newline at end of file diff --git a/feeds/feeds.txt b/feeds/feeds.txt new file mode 100644 index 0000000..b88f24a --- /dev/null +++ b/feeds/feeds.txt @@ -0,0 +1,157 @@ +https://feeds.feedburner.com/TheHackersNews?format=xml +https://www.grahamcluley.com/feed/ +https://www.schneier.com/blog/atom.xml +http://krebsonsecurity.com/feed/ +https://www.csoonline.com/feed/ +https://www.darkreading.com/rss/all.xml +https://www.troyhunt.com/rss/ +http://feeds.feedburner.com/eset/blog +https://www.infosecurity-magazine.com/rss/news/ +https://www.jisasoftech.com/feed/ +https://simeononsecurity.ch/index.xml +https://fidelissecurity.com/feed/ +https://www.heroictec.com/feed/ +https://cyberbuilders.substack.com/feed +https://www.infoguardsecurity.com/feed/ +https://underdefense.com/feed/ +https://medium.com/feed/@vaceituno +https://cyble.com/feed/ +https://protegent360.com/blog/feed/ +https://www.varutra.com/feed/ +https://ventureinsecurity.net/feed +https://feeds.feedburner.com/mattpalmeroncybersecurity +https://medium.com/feed/@2ndsightlab +https://davinciforensics.co.za/cybersecurity/feed/ +https://truefort.com/feed/ +https://www.secops-blogger-newsl.com/blog-feed.xml +https://cybersecurity.att.com/site/blog-all-rss +https://blogs.cisco.com%20/security/feed +https://www.mcafee.com/blogs/feed/ +https://www.nist.gov/blogs/cybersecurity-insights/rss.xml +http://feeds.trendmicro.com/TrendMicroResearch +https://www.bleepingcomputer.com/feed +http://www.techrepublic.com/rssfeeds/topic/security/?feedType=rssfeeds +https://www.computerworld.com/uk/category/security/index.rss +https://www.proofpoint.com/us/rss.xml +https://www.scnsoft.com/blog/category/information-security/atom +https://www.identityiq.com/feed/ +https://blogs.quickheal.com/feed/ +https://www.webroot.com/blog/feed/ +https://blog.zonealarm.com/feed/ +https://www.upguard.com/blog/rss.xml +https://www.seqrite.com/blog/feed/ +https://blog.pcisecuritystandards.org/rss.xml +https://heimdalsecurity.com/blog/feed/ +https://sectigostore.com/blog/feed/ +http://securityaffairs.co/wordpress/feed +https://feeds.feedburner.com/govtech/blogs/lohrmann_on_infrastructure +https://www.itgovernance.co.uk/blog/category/cyber-security/feed +https://lab.wallarm.com/feed/ +https://www.tripwire.com/state-of-security/feed/ +https://www.secpod.com/blog/feed/ +https://www.cheapsslshop.com/blog/feed/ +https://www.cybertalk.org/feed/ +https://secureblitz.com/feed/ +https://www.binarydefense.com/feed/ +https://www.cyberdefensemagazine.com/feed/ +https://www.logpoint.com/en/feed/ +https://cyberhoot.com/category/blog/feed/ +https://socprime.com/feed/ +https://hackercombat.com/feed/ +https://www.pivotpointsecurity.com/feed/ +https://www.clearnetwork.com/feed/ +https://blog.securityinnovation.com/rss.xml +http://feeds.feedburner.com/GoogleOnlineSecurityBlog +https://www.blackfog.com/feed/ +https://blog.entersoftsecurity.com/feed/ +https://www.netsparker.com/blog/rss/ +https://taosecurity.blogspot.com/feeds/posts/default?alt=rss +https://www.lastwatchdog.com/feed/ +https://marcoramilli.com/feed/ +https://mazebolt.com/feed/ +https://binaryblogger.com/feed/ +https://any.run/cybersecurity-blog/feed/ +http://www.veracode.com/blog/feed/ +https://www.helpnetsecurity.com/feed/ +https://www.cm-alliance.com/cybersecurity-blog/rss.xml +https://www.vistainfosec.com/feed/ +https://dataprivacymanager.net/feed/ +https://wesecureapp.com/feed/ +https://blog.g5cybersecurity.com/feed/ +https://www.flyingpenguin.com/?feed=rss2 +https://adamlevin.com/feed/ +https://be4sec.com/feed/ +https://www.erdalozkaya.com/feed/ +https://thecybermaniacs.com/cm-blog/rss.xml +https://virtualattacks.com/feed/ +https://cnsight.io/blog/feed/ +https://www.idsalliance.org/feed/ +https://www.exploitone.com/feed/ +https://www.tsfactory.com/forums/blogs/category/infosec-digest/feed/ +https://www.cyberpilot.io/cyberpilot-blog/rss.xml +https://www.ignyteplatform.com/feed/ +https://www.canarytrap.com/feed/ +https://www.secureblink.com/rss-feeds/threat-feed +https://www.virtru.com/blog/rss.xml +https://www.cybersecuritycloudexpo.com/feed/ +https://www.theguardian.com/technology/data-computer-security/rss +https://threatpost.com/feed/ +https://nakedsecurity.sophos.com/feed/ +https://www.jbspeakr.cc/index.xml +https://personalprivacyonline.com/feed/ +https://olukaiiisosicyber.tech/f.atom +https://olukaiiisoshybrideducyber.tech/feed/ +https://internetsafetybrigade.org/our-blog/f.atom +https://medium.com/feed/@d0znpp +https://itsecuritycentral.teramind.co/feed/ +https://trustarc.com/blog/feed/ +https://www.acunetix.com/blog/feed/ +https://blog.360quadrants.com/feed/ +https://www.cyberdb.co/blog/feed/ +https://privacysavvy.com/feed/ +https://techtalk.pcmatic.com/feed/ +https://www.twingate.com/blog.rss.xml +https://securityparrot.com/feed/ +https://www.cybercrimeswatch.com/feed/ +https://www.reveantivirus.com/blog/lan/en/feed +https://www.isdecisions.com/blog/feed/ +https://www.lynxtechnologypartners.com/blog/feed/ +https://www.getcurricula.com/feed +https://securitymadesimple.org/feed/ +https://itega.org/feed/ +https://zeno-sec.com/feed/ +https://aghiathchbib.com/feed/ +https://feeds.feedburner.com/ckdiii +https://blog.blackswansecurity.com/feed/ +https://blog.infinigate.co.uk/rss.xml +https://gatefy.com/feed/ +https://www.securedyou.com/feed/ +https://www.empowerelearning.com/blog/feed/ +https://blog.zartech.net/feed/ +https://blog.itsecurityexpert.co.uk/feeds/posts/default?alt=atom +http://securityweekly.com/podcast/psw.xml +http://feeds.feedburner.com/high-tech_bridge_corporate_news +https://info-savvy.com/feed/ +https://www.zerodayinitiative.com/rss/published/ +https://cvefeed.io/rssfeed/newsroom.xml +https://cvefeed.io/rssfeed/severity/high.xml +https://cvefeed.io/rssfeed/latest.xml +https://www.zdnet.com/topic/security/rss.xml +https://www.wired.com/feed/category/security/latest/rss +http://www.malware-traffic-analysis.net/blog-entries.rss +https://www.intezer.com/blog/feed/ +https://www.hackread.com/feed/ +https://www.hackmageddon.com/feed/ +https://www.hackerone.com/blog.rss +https://www.theguardian.com/technology/data-computer-security/rss +https://www.cio.com/category/security/index.rss +https://medium.com/feed/anton-on-security +https://arstechnica.com/tag/security/feed/ +https://www.ncsc.gov.uk/api/1/services/v1/news-rss-feed.xml +https://www.ncsc.gov.uk/api/1/services/v1/blog-post-rss-feed.xml +https://www.xcitium.com/blog/rss +https://neoxnetworks.com/blog/rss +https://danielmiessler.com/rss +https://krebsonsecurity.com/rss +https://news.sophos.com/en-us/category/serious-security/rss +https://www.itsecurityguru.org/feed \ No newline at end of file diff --git a/lists/github_users.txt b/lists/github_users.txt new file mode 100644 index 0000000..9a1a9b7 --- /dev/null +++ b/lists/github_users.txt @@ -0,0 +1,9 @@ +https://github.com/EbookFoundation +https://github.com/witchdocsec +https://github.com/orgs/malectricasoftware/repositories +https://github.com/daffainfo +https://github.com/swisskyrepo +https://github.com/sundowndev +https://github.com/hak5 +https://github.com/JohnHammond +https://github.com/infosecn1nja \ No newline at end of file diff --git a/newsbot.py b/newsbot.py new file mode 100644 index 0000000..9c0f0a9 --- /dev/null +++ b/newsbot.py @@ -0,0 +1,221 @@ +import feedparser +import requests +import time +from datetime import datetime, timedelta +from dateutil import parser +from typing import List, Dict +from bs4 import BeautifulSoup +import logging +import os +import re +import schedule + +# Webhook URLs +DEFAULT_WEBHOOK_URL "WEBHOOK" = # Webhook for feeds.txt +ADVISORES_WEBHOOK = "WEBHOOK" # Webhook for threatintel.txt +ALERTS_WEBHOOK = "WEBHOOK" +BUTBOUNTY_WEBHOOK = WEBHOOK" +# File paths +PROCESSED_LINKS_FILE = 'processed_links.txt' # File to store processed links +ADVISORES = 'feeds/advisories.txt' # File for threat intel feeds (common webhook) +FEEDS_FILE = 'feeds/feeds.txt' # File for regular feeds (different webhook) +ALERTS = "feeds/alerts.txt" +BUGBOUNTY = "feeds/bugbounty.txt" + +# Set up logging +logging.basicConfig(filename='rss_feed_watcher.log', level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') + +# Helper function to send an embed message to Discord +def send_discord_embed(title: str, link: str, published: datetime, description: str, webhook_url: str): + embed = { + "embeds": [{ + "title": title, + "url": link, + "description": description, + "color": 5814783, # Hex color code for the embed (optional) + "timestamp": published.isoformat() # ISO format timestamp + }] + } + try: + response = requests.post(webhook_url, json=embed) + if response.status_code != 204: + logging.error(f"Failed to send message to Discord: {response.status_code} {response.text}") + except requests.exceptions.RequestException as e: + logging.error(f"Exception while sending message to Discord: {e}") + +# Helper function to clean HTML and extract plain text +def clean_html(html_content: str) -> str: + soup = BeautifulSoup(html_content, 'html.parser') + text = soup.get_text(separator='\n').strip() + text = re.sub(r'\n+', ' ', text) + text = re.sub(r'(read more|continue reading|more details|[ \t]*\n[ \t]*\n[ \t]*)', '', text, flags=re.IGNORECASE) + return text.strip() + +# Helper function to get posts from RSS feed +def get_recent_posts(feed_url: str, webhook_url: str, since_time: datetime, processed_links: set) -> List[dict]: + try: + response = requests.get(feed_url, timeout=10) + response.raise_for_status() # Raise an error for bad HTTP responses + feed = feedparser.parse(response.content) + recent_posts = [] + + for entry in feed.entries: + # Try to get and parse the published date from the entry + published = getattr(entry, 'published', None) + if published: + try: + published_time = parser.parse(published).replace(tzinfo=None) + except (ValueError, TypeError): + logging.warning(f"Skipping entry with invalid published date: {published}") + continue + else: + logging.warning("Skipping entry without published date") + continue + + if published_time > since_time: + link = entry.link + if link in processed_links: + continue # Skip already processed posts + + description = getattr(entry, 'description', '') + plain_text_description = clean_html(description) + + recent_posts.append({ + 'title': entry.title, + 'link': link, + 'published': published_time, + 'description': plain_text_description + }) + + # Add link to the set of processed links + processed_links.add(link) + + # Send an embed message to Discord for each new post + send_discord_embed(entry.title, link, published_time, plain_text_description, webhook_url) + + return recent_posts + except requests.exceptions.Timeout as e: + logging.error(f"Request timeout for {feed_url}: {e}") + except requests.exceptions.ConnectionError as e: + logging.error(f"Connection error for {feed_url}: {e}") + except requests.exceptions.RequestException as e: + logging.error(f"HTTP request failed for {feed_url}: {e}") + +# Load processed links from file +def load_processed_links() -> set: + if os.path.exists(PROCESSED_LINKS_FILE): + with open(PROCESSED_LINKS_FILE, 'r') as file: + return set(line.strip() for line in file) + return set() + +# Save processed links to file +def save_processed_links(processed_links: set): + with open(PROCESSED_LINKS_FILE, 'w') as file: + for link in processed_links: + file.write(f"{link}\n") + +# Helper function to load URLs from a file (feed or threat intel) +def load_feed_urls(file_path: str) -> List[str]: + if os.path.exists(file_path): + with open(file_path, 'r') as file: + return [line.strip() for line in file if line.strip()] + logging.error(f"{file_path} not found.") + return [] + +# Function to process threat intel feeds +def process_threatintel_feeds(threatintel_feeds: List[str], since_time: datetime, processed_links: set): + for feed_url in threatintel_feeds: + logging.info(f"Checking threat intel feed: {feed_url}") + recent_posts = get_recent_posts(feed_url, ADVISORES_WEBHOOK, since_time, processed_links) + try: + for post in recent_posts: + logging.info(f"New threat intel post: {post['title']}") + logging.info(f"Link: {post['link']}") + logging.info(f"Published: {post['published']}") + logging.info(f"Description: {post['description']}") + logging.info("-" * 40) + except TypeError: + pass + +# Function to process regular feeds +def process_regular_feeds(regular_feeds: List[str], since_time: datetime, processed_links: set): + for feed_url in regular_feeds: + logging.info(f"Checking regular feed: {feed_url}") + recent_posts = get_recent_posts(feed_url, DEFAULT_WEBHOOK_URL, since_time, processed_links) + try: + for post in recent_posts: + logging.info(f"New regular post: {post['title']}") + logging.info(f"Link: {post['link']}") + logging.info(f"Published: {post['published']}") + logging.info(f"Description: {post['description']}") + logging.info("-" * 40) + except TypeError: + pass + +def process_alert_feeds(regular_feeds: List[str], since_time: datetime, processed_links: set): + for feed_url in regular_feeds: + logging.info(f"Checking regular feed: {feed_url}") + recent_posts = get_recent_posts(feed_url, ALERTS_WEBHOOK, since_time, processed_links) + try: + for post in recent_posts: + logging.info(f"New regular post: {post['title']}") + logging.info(f"Link: {post['link']}") + logging.info(f"Published: {post['published']}") + logging.info(f"Description: {post['description']}") + logging.info("-" * 40) + except TypeError: + pass + +def process_bugbounty_feeds(regular_feeds: List[str], since_time: datetime, processed_links: set): + for feed_url in regular_feeds: + logging.info(f"Checking regular feed: {feed_url}") + recent_posts = get_recent_posts(feed_url, BUTBOUNTY_WEBHOOK, since_time, processed_links) + try: + for post in recent_posts: + logging.info(f"New regular post: {post['title']}") + logging.info(f"Link: {post['link']}") + logging.info(f"Published: {post['published']}") + logging.info(f"Description: {post['description']}") + logging.info("-" * 40) + except TypeError: + pass + +# Main function to run the watcher +def rss_feed_watcher(): + print("RUNNING...") + processed_links = load_processed_links() # Load previously processed links + regular_feeds = load_feed_urls(FEEDS_FILE) + # Load threat intel and regular feeds + threatintel_feeds = load_feed_urls(ADVISORES) + bug_bounty_feeds = load_feed_urls(BUGBOUNTY) + alert_feeds = load_feed_urls(ALERTS) + + # Get the timestamp to compare recent posts (last 30 minutes) + since_time = datetime.now() - timedelta(hours=12) + since_time = since_time.replace(tzinfo=None) + print("going over bug bounties...") + process_bugbounty_feeds(bug_bounty_feeds,since_time, processed_links) + print("going over regular feeds...") + process_regular_feeds(regular_feeds, since_time, processed_links) + # Process threat intel feeds + print("going over threat intel...") + process_threatintel_feeds(threatintel_feeds, since_time, processed_links) + print("going over alerts...") + process_alert_feeds(alert_feeds, since_time, processed_links) + + # Save updated processed links + save_processed_links(processed_links) + +# Schedule the RSS feed watcher to run every 30 minutes +def schedule_rss_watcher(): + schedule.every(1).hours.do(rss_feed_watcher) + logging.info("RSS Feed Watcher scheduled to run every 30 minutes.") + + while True: + schedule.run_pending() + time.sleep(1) + +if __name__ == "__main__": + rss_feed_watcher() + # Start the scheduled watcher + schedule_rss_watcher() diff --git a/test2.py b/test2.py new file mode 100644 index 0000000..1f1b75b --- /dev/null +++ b/test2.py @@ -0,0 +1,263 @@ +import requests +import time +import schedule +from datetime import datetime, timedelta +import json +import os +import re + +# Global variable to store previously fetched CVEs and their last modified timestamps +previous_cves = {} # Dictionary to store CVE IDs and their lastModified timestamps +FILE_PATH = 'previous_cves.json' + +def load_previous_cves(): + """Load previously fetched CVEs from a file.""" + global previous_cves + previous_cves = {} + if os.path.exists(FILE_PATH): + with open(FILE_PATH, 'r') as file: + try: + # Load JSON data from the file + data = json.load(file) + + # Ensure the data is a list of dictionaries + if isinstance(data, list): + previous_cves = { (cve.get('id'), cve.get('lastModified', 'Not available')): cve.get('lastModified', 'Not available') for cve in data if 'id' in cve } + else: + print("Error: JSON data is not in the expected format.") + except json.JSONDecodeError: + print("Error: Failed to decode JSON from the file.") + +def save_previous_cves(): + """Save previously fetched CVEs to a file.""" + with open(FILE_PATH, 'w') as file: + # Convert the dictionary to a list of dictionaries for saving + data_to_save = [{'id': cve_id, 'lastModified': last_modified} for (cve_id, last_modified), _ in previous_cves.items()] + json.dump(data_to_save, file, indent=2) + +def send_webhook(embed_data): + """Send an embed to a webhook URL.""" + webhook_url = '' # Replace with your webhook URL + try: + response = requests.post(webhook_url, json={'embeds': [embed_data]}) + response.raise_for_status() + print(f"Webhook sent successfully: {response.status_code}") + except requests.RequestException as e: + print(f"Error sending webhook: {e}") + +def format_embed(cve): + """Format CVE data into an embed.""" + # Extract CVE ID + cve_id = cve.get('cve', {}).get('id', 'Unknown CVE ID') + + # Get the English description, or fallback to 'No description available' + description = next( + (desc.get('value') for desc in cve.get('cve', {}).get('descriptions', []) if desc.get('lang') == 'en'), + 'No description available' + ) + + # Fetch CVSS data + cvss_metrics = cve.get('cve', {}).get('metrics', {}).get('cvssMetricV31', []) + + # Check if NIST data is available + nist_data = next((metric for metric in cvss_metrics if metric.get('source') == 'nvd@nist.gov'), None) + + # Use NIST data if available, otherwise fallback to other available metrics + if nist_data: + cvss_data = nist_data.get('cvssData', {}) + else: + cvss_data = cvss_metrics[0].get('cvssData', {}) if cvss_metrics else {} + + # Extract CVSS-related fields + base_score = cvss_data.get('baseScore', 'Not available') + base_severity = cvss_data.get('baseSeverity', 'Not available') + attack_vector = cvss_data.get('attackVector', 'Not available') + attack_complexity = cvss_data.get('attackComplexity', 'Not available') + privileges_required = cvss_data.get('privilegesRequired', 'Not available') + user_interaction = cvss_data.get('userInteraction', 'Not available') + vector_string = cvss_data.get('vectorString', 'Not available') + + # Set color based on base severity + severity_colors = { + 'LOW': 0x00FF00, # Green for Low severity + 'MEDIUM': 0xFFFF00, # Yellow for Medium severity + 'HIGH': 0xFF0000, # Red for High severity + 'CRITICAL': 0xFF0000 # Red for Critical severity (added if needed) + } + color = severity_colors.get(base_severity, 0x0000FF) # Default to blue if severity is unknown + + # Extract and format dates + published_date = cve.get('cve', {}).get('published', 'Not available') + last_modified_date = cve.get('cve', {}).get('lastModified', 'Not available') + + try: + published_date = datetime.fromisoformat(published_date).strftime('%Y-%m-%d %H:%M:%S UTC') + last_modified_date = datetime.fromisoformat(last_modified_date).strftime('%Y-%m-%d %H:%M:%S UTC') + except ValueError: + pass + + # Check if the system is vulnerable from configurations + configurations = cve.get('cve', {}).get('configurations', []) + vulnerable_criteria = [] + + for config in configurations: + for node in config.get('nodes', []): + for cpe_match in node.get('cpeMatch', []): + if cpe_match.get('vulnerable', False): + vulnerable_criteria.append(cpe_match.get('criteria', 'N/A')) + + # Collect references, if any exist + references = [ref.get('url') for ref in cve.get('cve', {}).get('references', []) if ref.get('url')] + + # Create the embed structure + embed = { + 'title': f'CVE Details: {cve_id}', + 'description': description, + 'color': color, + 'fields': [ + { + 'name': 'CVSS Score', + 'value': str(base_score) if base_score != 'Not available' else 'Not available', + 'inline': True + }, + { + 'name': 'CVSS Severity', + 'value': base_severity if base_severity != 'Not available' else 'Not available', + 'inline': True + }, + { + 'name': 'Attack Vector', + 'value': attack_vector if attack_vector != 'Not available' else 'Not available', + 'inline': True + }, + { + 'name': 'Attack Complexity', + 'value': attack_complexity if attack_complexity != 'Not available' else 'Not available', + 'inline': True + }, + { + 'name': 'Privileges Required', + 'value': privileges_required if privileges_required != 'Not available' else 'Not available', + 'inline': True + }, + { + 'name': 'User Interaction', + 'value': user_interaction if user_interaction != 'Not available' else 'Not available', + 'inline': True + }, + { + 'name': 'CVSS Vector', + 'value': vector_string if vector_string != 'Not available' else 'Not available', + 'inline': True + }, + { + 'name': 'Published Date', + 'value': published_date if published_date != 'Not available' else 'Not available', + 'inline': True + }, + { + 'name': 'Last Modified Date', + 'value': last_modified_date if last_modified_date != 'Not available' else 'Not available', + 'inline': True + }, + { + 'name': 'Vulnerable Systems', + 'value': '\n'.join(vulnerable_criteria) if vulnerable_criteria else 'No vulnerable systems specified', + 'inline': False + } + ], + 'footer': { + 'text': 'Source: NVD' + }, + 'url': f'https://nvd.nist.gov/vuln/detail/{cve_id}' + } + + # Add references if any exist + if references: + embed['fields'].append({ + 'name': 'References', + 'value': '\n'.join(references), + 'inline': False + }) + + return embed + +def fetch_cves(): + global previous_cves + + # Current time for the request + now = datetime.utcnow() + start_date = (now - timedelta(days=7)).strftime('%Y-%m-%dT%H:%M:%S.000') + end_date = now.strftime('%Y-%m-%dT%H:%M:%S.000') + + cvs = ["LOW", "MEDIUM", "HIGH"] + + # Construct the request URL with the updated date range + for severity in cvs: + url = f"https://services.nvd.nist.gov/rest/json/cves/2.0/?pubStartDate={start_date}&pubEndDate={end_date}&cvssV3Severity={severity}" + + headers = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36' + } + + retry_attempts = 3 + for attempt in range(retry_attempts): + try: + # Make the request to the NVD API + response = requests.get(url, headers=headers) + response.raise_for_status() + data = response.json() + + # Debug: Print raw response + #print("Raw response data:") + #print(json.dumps(data, indent=2)) # Pretty-print the JSON response + + # Extract CVEs + cves = data.get('vulnerabilities', []) + + # Debug: Print number of CVEs found + print(f"Number of CVEs found: {len(cves)}") + + # Identify new or updated CVEs + new_or_updated_cves = [] + for cve in cves: + cve_id = cve['cve']['id'] + last_modified = cve['cve'].get('lastModified', 'Not available') + + if (cve_id, last_modified) not in previous_cves: + new_or_updated_cves.append(cve) + + if new_or_updated_cves: + print(f"Found {len(new_or_updated_cves)} new or updated CVEs:") + for cve in new_or_updated_cves: + # Format the CVE data as an embed + embed = format_embed(cve) + # Send the embed via webhook + send_webhook(embed) + + # Update the dictionary of previously fetched CVEs + previous_cves[(cve['cve']['id'], cve['cve'].get('lastModified', 'Not available'))] = cve['cve'].get('lastModified', 'Not available') + + save_previous_cves() + + else: + print("No new or updated CVEs found.") + + # Exit the retry loop if successful + break + + except requests.RequestException as e: + print(f"Error fetching CVEs (attempt {attempt + 1}/{retry_attempts}): {e}") + # Wait before retrying + time.sleep(5) + +# Load previously fetched CVEs from file +load_previous_cves() + +# Schedule the task to run every hour +schedule.every(1).hours.do(fetch_cves) +fetch_cves() +print("Starting CVE monitoring...") +while True: + schedule.run_pending() + time.sleep(1) diff --git a/youtubes.txt b/youtubes.txt new file mode 100644 index 0000000..41af480 --- /dev/null +++ b/youtubes.txt @@ -0,0 +1,80 @@ +https://www.youtube.com/c/InsiderPhD +https://www.youtube.com/c/RanaKhalil101 +https://www.youtube.com/c/SpinTheHack +https://www.youtube.com/c/PwnFunction +https://www.youtube.com/c/CyberSecVillage +https://www.youtube.com/c/StefanRows +https://www.youtube.com/c/ITSecurityLabs +https://www.youtube.com/c/Cybrcom +https://www.youtube.com/c/TheXSSrat +https://www.youtube.com/c/CristiVladZ +https://www.youtube.com/c/HackerOneTV +https://www.youtube.com/c/PinkDraconian +https://www.youtube.com/c/ForensicTech +https://www.youtube.com/c/hak5 +https://www.youtube.com/c/TheCyberMentor +https://www.youtube.com/c/NullByteWHT +https://www.youtube.com/c/HackerSploit +https://www.youtube.com/c/STOKfredrik +https://www.youtube.com/c/ippsec +https://www.youtube.com/c/ScriptKiddieHub +https://www.youtube.com/c/zSecurity +https://www.youtube.com/c/JonGoodCyber +https://www.youtube.com/c/CybersecurityWeb +https://www.youtube.com/c/MotasemHamdaninfosec +https://www.youtube.com/c/ITCareerQuestions +https://www.youtube.com/c/BugBountyReportsExplained +https://www.youtube.com/c/TechChipNet +https://www.youtube.com/c/TechnicalNavigator +https://www.youtube.com/c/BeauKnowsTechStuff +https://www.youtube.com/c/CyberSecurityTV +https://www.youtube.com/c/indianblackhats +https://www.youtube.com/c/DavidBombal +https://www.youtube.com/c/Nahamsec +https://www.youtube.com/c/LoiLiangYang +https://www.youtube.com/c/professormesser +https://www.youtube.com/c/NetworkChuck +https://www.youtube.com/c/JohnHammond010 +https://www.youtube.com/c/DarkSec +https://www.youtube.com/c/CryptoCat23 +https://www.youtube.com/c/devnull1337 +https://www.youtube.com/c/Seytonic +https://www.youtube.com/c/LiveOverflow +https://www.youtube.com/c/SecurityFWD +https://www.youtube.com/c/TheHeraneVlogs5 +https://www.youtube.com/c/FindingUrPasswd +https://www.youtube.com/c/BittenTech +https://www.youtube.com/c/CyberAcademyHindi +https://www.youtube.com/c/Cyberspatial +https://www.youtube.com/c/GynvaelEN +https://www.youtube.com/c/SheshTheCyberSecurity +https://www.youtube.com/c/impratikdabhi +https://www.youtube.com/c/MrTurvey +https://www.youtube.com/c/Bugcrowd +https://www.youtube.com/c/BlackPerl +https://www.youtube.com/c/MurmusCTF +https://www.youtube.com/c/PentestToolscom +https://www.youtube.com/c/TheHackersWorld +https://www.youtube.com/c/BlackHatOfficialYT +https://www.youtube.com/c/InfiniteLogins +https://www.youtube.com/c/HackingSimplifiedAS +https://www.youtube.com/c/ZetaTwo +https://www.youtube.com/c/EhackingNet +https://www.youtube.com/c/MastersinIT +https://www.youtube.com/c/InfoCk +https://www.youtube.com/c/CyberInsecurity +https://www.youtube.com/c/troyhuntdotcom +https://www.youtube.com/c/Tech69YT +https://www.youtube.com/c/CloudSecurityPodcast +https://www.youtube.com/c/HusseinNasser-software-engineering +https://www.youtube.com/@DEFCONConference +https://www.youtube.com/@BlackHatOfficialYT +https://www.youtube.com/@thenewboston +https://www.youtube.com/@PentesterAcademyTV +https://www.youtube.com/@STOKfredrik +https://www.youtube.com/@InfoSecPat +https://www.youtube.com/channel/UCo1NHk_bgbAbDBc4JinrXww +https://www.youtube.com/@Malectrica +https://www.youtube.com/@NahamSec +https://www.youtube.com/@LowLevelTV +https://www.youtube.com/@Fireship \ No newline at end of file diff --git a/ytmonitor.py b/ytmonitor.py new file mode 100644 index 0000000..34cccab --- /dev/null +++ b/ytmonitor.py @@ -0,0 +1,162 @@ +import requests +from selenium import webdriver +from selenium.webdriver.chrome.options import Options +from selenium.webdriver.common.by import By +from datetime import datetime, timedelta +import time +import re + +# Set your Discord webhook URL here +DISCORD_WEBHOOK_URL = '' # Replace with your actual webhook URL +SEEN_VIDEOS_FILE = 'seen_videos.txt' # File to keep track of seen video IDs + +options = Options() +#options.add_argument("--headless") # Uncomment for headless mode +options.add_argument('--no-sandbox') # Disable sandbox +options.add_argument('--disable-dev-shm-usage') # Use shared memory in case of resource issues +options.add_argument('--disable-gpu') # Disable GPU if running into GPU issues +options.add_experimental_option("prefs", {"profile.default_content_setting_values.notifications": 1}) +options.add_argument("--disable-infobars") + + + +CHECK_INTERVAL = 60*60*1 # Check every 12 hours (43200 seconds) +seen_videos = set() # To keep track of seen video IDs + +def load_seen_videos(): + """Load seen video IDs from a file.""" + try: + with open(SEEN_VIDEOS_FILE, 'r') as file: + return set(line.strip() for line in file if line.strip()) + except FileNotFoundError: + return set() + +def save_seen_video(video_id): + """Save a video ID to the seen videos file.""" + with open(SEEN_VIDEOS_FILE, 'a') as file: + file.write(f"{video_id}\n") + +def send_discord_notification(video_title, video_link, upload_time, thumbnail_url, creator_name): + embed = { + "title": video_title, + "url": video_link, + "description": f"Creator: {creator_name}\nUploaded on: {upload_time.strftime('%Y-%m-%d %H:%M:%S')}", + "thumbnail": {"url": thumbnail_url}, + "color": 16711680 + } + data = { + "embeds": [embed] + } + requests.post(DISCORD_WEBHOOK_URL, json=data) + +def parse_time(upload_time_str): + """Convert the upload time string to a datetime object.""" + time_units = { + 'years': 0, + 'months': 0, + 'weeks': 0, + 'days': 0, + 'hours': 0, + 'minutes': 0, + 'seconds': 0 + } + + time_pattern = re.compile(r'(\d+)\s*(year|years|month|months|week|weeks|day|days|hour|hours|minute|minutes|second|seconds)') + + for match in time_pattern.finditer(upload_time_str): + value, unit = match.groups() + value = int(value) + + if 'year' in unit: + time_units['years'] += value + elif 'month' in unit: + time_units['months'] += value + elif 'week' in unit: + time_units['weeks'] += value + elif 'day' in unit: + time_units['days'] += value + elif 'hour' in unit: + time_units['hours'] += value + elif 'minute' in unit: + time_units['minutes'] += value + elif 'second' in unit: + time_units['seconds'] += value + + # Convert months and years to days + total_days = (time_units['years'] * 365) + (time_units['months'] * 30) + time_units['days'] + + # Create a timedelta + total_time = timedelta( + days=total_days, + weeks=time_units['weeks'], + hours=time_units['hours'], + minutes=time_units['minutes'], + seconds=time_units['seconds'] + ) + + # Return the correct upload time + return datetime.now() - total_time + +def fetch_latest_videos(channel_url, driver): + driver.get(channel_url) + time.sleep(3) # Wait for the page to load + + # Extract the creator name from the tag + creator_name = driver.title.replace(" - YouTube", "") + + # Click "Allow Cookies" if the button is present + try: + cookie_button = driver.find_element(By.CSS_SELECTOR, "button.VfPpkd-LgbsSe.VfPpkd-LgbsSe-OWXEXe-k8QpJ.VfPpkd-LgbsSe-OWXEXe-dgl2Hf.nCP5yc.AjY5Oe.DuMIQc.Gu558e") + cookie_button.click() + except Exception as e: + pass + + # Find all video elements + video_elements = driver.find_elements(By.CSS_SELECTOR, 'ytd-rich-grid-media') + new_videos = [] + + for video in video_elements: + title_element = video.find_element(By.ID, 'video-title-link') + upload_time_element = video.find_elements(By.CSS_SELECTOR, 'span.inline-metadata-item')[-1] # Get the last one for upload time + thumbnail_element = video.find_element(By.CSS_SELECTOR, 'img.yt-core-image') + + video_id = title_element.get_attribute('href').split('v=')[-1] + if video_id not in seen_videos: + video_title = title_element.get_attribute('title') + upload_time_str = upload_time_element.text + thumbnail_url = thumbnail_element.get_attribute('src') + + # Get upload time + upload_time = parse_time(upload_time_str) + + # Check if the video was uploaded in the last 12 hours + if datetime.now() - upload_time < timedelta(days=7): + new_videos.append((video_title, title_element.get_attribute('href'), upload_time, thumbnail_url, creator_name)) + seen_videos.add(video_id) + save_seen_video(video_id) + + return new_videos + +def main(): + global seen_videos + seen_videos = load_seen_videos() + try: + with open('youtubes.txt', 'r') as file: + channels = [line.strip() for line in file if line.strip()] + + while True: + driver = webdriver.Chrome(options=options) + for channel in channels: + channel_url = f"{channel}/videos" + new_videos = fetch_latest_videos(channel_url,driver) + for video_title, video_link, upload_time, thumbnail_url, creator_name in new_videos: + print(f"New video found: {video_title}\nLink: {video_link}\nUploaded on: {upload_time}\nThumbnail: {thumbnail_url}\nCreator: {creator_name}") + send_discord_notification(video_title, video_link, upload_time, thumbnail_url, creator_name) # Notify + driver.quit() + time.sleep(CHECK_INTERVAL) + finally: + driver.quit() + + +if __name__ == "__main__": + main()