diff --git a/packages/internet_detector.vm/internet_detector.vm.nuspec b/packages/internet_detector.vm/internet_detector.vm.nuspec
new file mode 100644
index 000000000..16248794c
--- /dev/null
+++ b/packages/internet_detector.vm/internet_detector.vm.nuspec
@@ -0,0 +1,13 @@
+
+
+
+ internet_detector.vm
+ 1.0.0
+ Elliot Chernofsky and Ana Martinez Gomez
+ Tool to detect if internet connectivity exists
+
+
+
+
+
+
diff --git a/packages/internet_detector.vm/tools/chocolateyinstall.ps1 b/packages/internet_detector.vm/tools/chocolateyinstall.ps1
new file mode 100644
index 000000000..6a4dd0cc4
--- /dev/null
+++ b/packages/internet_detector.vm/tools/chocolateyinstall.ps1
@@ -0,0 +1,29 @@
+$ErrorActionPreference = 'Stop'
+Import-Module vm.common -Force -DisableNameChecking
+
+$toolName = 'internet_detector'
+$category = 'Utilities'
+
+# Install dependency for windows api
+VM-Pip-Install "pywin32"
+
+$toolDir = "${Env:RAW_TOOLS_DIR}\$toolName"
+New-Item -Path $toolDir -ItemType Directory
+VM-Assert-Path $toolDir
+
+# Download the script
+(New-Object net.webclient).DownloadFile('https://raw.githubusercontent.com/mandiant/VM-Packages/main/packages/internet_detector.vm/tools/internet_detector.pyw', $toolDir)
+
+$executablePath = (Get-Command pythonw).Source
+$filePath = Join-Path $toolDir "$toolName.pyw"
+
+VM-Install-Shortcut $toolName $category $executablePath -arguments $filePath
+
+# Define the action to be performed
+$action = New-ScheduledTaskAction -Execute $executablePath -Argument "$filePath"
+
+# Define the trigger to run every 2 minutes
+$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes 2)
+
+# Create the scheduled task
+Register-ScheduledTask -Action $action -Trigger $trigger -TaskName 'Internet Detector' -Force
diff --git a/packages/internet_detector.vm/tools/chocolateyuninstall.ps1 b/packages/internet_detector.vm/tools/chocolateyuninstall.ps1
new file mode 100644
index 000000000..5aa4127d5
--- /dev/null
+++ b/packages/internet_detector.vm/tools/chocolateyuninstall.ps1
@@ -0,0 +1,7 @@
+$ErrorActionPreference = 'Continue'
+Import-Module vm.common -Force -DisableNameChecking
+
+$toolName = 'internet_detector'
+$category = 'Utilities'
+
+VM-Uninstall $toolName $category
diff --git a/packages/internet_detector.vm/tools/internet_detector.pyw b/packages/internet_detector.vm/tools/internet_detector.pyw
new file mode 100644
index 000000000..e0d28dc09
--- /dev/null
+++ b/packages/internet_detector.vm/tools/internet_detector.pyw
@@ -0,0 +1,239 @@
+import threading
+import requests
+import win32api
+import win32gui
+import win32con
+import urllib3
+import hashlib
+import winreg
+import signal
+import ctypes
+import time
+import os
+import re
+
+
+# Define constants
+CHECK_INTERVAL = 2 # Seconds
+CONNECT_TEST_URL_AND_RESPONSES = {
+ "https://www.msftconnecttest.com/connecttest.txt": "Microsoft Connect Test", # HTTPS Test #1
+ "http://www.google.com": 'Google', # HTTP Test
+ "https://www.wikipedia.com": 'Wikipedia', # HTTPS Test #2
+ "https://www.youtube.com": 'YouTube' # HTTPS Test #3
+ }
+SPI_SETDESKWALLPAPER = 20
+SPIF_UPDATEINIFILE = 0x01
+SPIF_SENDWININICHANGE = 0x02
+COLOR_DESKTOP = 1
+ICON_INDICATOR_ON = os.path.join(os.environ.get('VM_COMMON_DIR'), "indicator_on.ico")
+ICON_INDICATOR_OFF = os.path.join(os.environ.get('VM_COMMON_DIR'), "indicator_off.ico")
+DEFAULT_BACKGROUND = os.path.join(os.environ.get('VM_COMMON_DIR'), "background.png")
+INTERNET_BACKGROUND = os.path.join(os.environ.get('VM_COMMON_DIR'),"background-internet.png")
+
+# Global variables
+tray_icon = None
+stop_event = threading.Event() # To signal the background thread to stop
+hwnd = None # We'll assign the window handle here later
+check_thread = None
+tray_icon_thread = None
+# Win32 API icon handles
+hicon_indicator_off = None
+hicon_indicator_on = None
+
+def signal_handler(sig, frame):
+ global check_thread, tray_icon_thread, tray_icon
+ print("Ctrl+C detected. Exiting...")
+ stop_event.set() # Signal the background thread to stop
+ if check_thread:
+ check_thread.join()
+ if tray_icon_thread:
+ tray_icon_thread.join()
+ if tray_icon:
+ del tray_icon
+ exit(0)
+
+def load_icon(icon_path):
+ try:
+ return win32gui.LoadImage(None, icon_path, win32con.IMAGE_ICON, 0, 0, win32con.LR_LOADFROMFILE)
+ except Exception as e:
+ print(f"Error loading indicator icon: {e}")
+ return None
+
+class SysTrayIcon:
+ def __init__(self, hwnd, icon, tooltip):
+ self.hwnd = hwnd
+ self.icon = icon
+ self.tooltip = tooltip
+ # System tray icon data structure
+ self.nid = (self.hwnd, 0, win32gui.NIF_ICON | win32gui.NIF_MESSAGE | win32gui.NIF_TIP,
+ win32con.WM_USER + 20, self.icon, self.tooltip)
+ # Add the icon to the system tray
+ win32gui.Shell_NotifyIcon(win32gui.NIM_ADD, self.nid)
+
+ def set_tooltip(self, new_tooltip):
+ self.tooltip = new_tooltip
+ self.nid = (self.hwnd, 0, win32gui.NIF_ICON | win32gui.NIF_MESSAGE | win32gui.NIF_TIP,
+ win32con.WM_USER + 20, self.icon, self.tooltip)
+ win32gui.Shell_NotifyIcon(win32gui.NIM_MODIFY, self.nid)
+
+ def set_icon(self, icon):
+ self.icon = icon
+ self.nid = (self.hwnd, 0, win32gui.NIF_ICON | win32gui.NIF_MESSAGE | win32gui.NIF_TIP,
+ win32con.WM_USER + 20, self.icon, self.tooltip)
+ win32gui.Shell_NotifyIcon(win32gui.NIM_MODIFY, self.nid)
+
+ def __del__(self):
+ # Remove the icon from the system tray when the object is destroyed
+ win32gui.Shell_NotifyIcon(win32gui.NIM_DELETE, self.nid)
+
+# Attempt to extract a known good value in response.
+def extract_title(data):
+ match = re.search(r'
(.*?)