Navigation Menu

Skip to content

Commit

Permalink
Closes 4, 8 and 10. Added auto attacks to nmap imports. Tool addition…
Browse files Browse the repository at this point in the history
…s. Other bug fixes.
  • Loading branch information
st3r30byt3 committed Jan 15, 2015
1 parent 14b144a commit c3c34e5
Show file tree
Hide file tree
Showing 8 changed files with 790 additions and 75 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.txt
@@ -0,0 +1,10 @@
SPARTA 1.0.1 (BETA)

* added tool rdp-sec-check.pl to rdp service (credit to Portcullis Labs - http://labs.portcullis.co.uk/application/rdp-sec-check/)
* added tool WhatWeb to web services (thanks @_bcoles)
* added the screenshooter to automated attacks (thanks @harmj0y)
* added setting to run automated attacks after nmap imports (off by default)
* fixed a unicode bug (thanks Dmitry Boomov)
* fixed another unicode bug in the tool output
* fixed bug in the sort function (thanks ad0nis)
* added content to the help menu
11 changes: 7 additions & 4 deletions app/auxiliary.py
Expand Up @@ -11,7 +11,7 @@
You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
'''

import os, sys, urllib2, socket, time, datetime, webbrowser, re # for webrequests, screenshot timeouts, timestamps, browser stuff and regex
import os, sys, urllib2, socket, time, datetime, locale, webbrowser, re # for webrequests, screenshot timeouts, timestamps, browser stuff and regex
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import * # for QProcess
import errno # temporary for isHttpd
Expand All @@ -34,6 +34,7 @@ def sortArrayWithArray(array, arrayToSort):

# converts an IP address to an integer (for the sort function)
def IP2Int(ip):
ip = ip.split("/")[0] # bug fix: remove slash if it's a range
o = map(int, ip.split('.'))
res = (16777216 * o[0]) + (65536 * o[1]) + (256 * o[2]) + o[3]
return res
Expand Down Expand Up @@ -81,7 +82,7 @@ def isHttps(ip, port):
def getTimestamp(human=False):
t = time.time()
if human:
timestamp = datetime.datetime.fromtimestamp(t).strftime("%d %b %Y %H:%M:%S")
timestamp = datetime.datetime.fromtimestamp(t).strftime("%d %b %Y %H:%M:%S").decode(locale.getlocale()[1])
else:
timestamp = datetime.datetime.fromtimestamp(t).strftime('%Y%m%d%H%M%S')
return timestamp
Expand Down Expand Up @@ -176,7 +177,8 @@ def __init__(self, name, tabtitle, hostip, port, protocol, command, starttime, o
@pyqtSlot() # this slot allows the process to append its output to the display widget
def readStdOutput(self):
output = QString(self.readAllStandardOutput())
self.display.appendPlainText(unicode(output, 'utf-8').strip())
#self.display.appendPlainText(unicode(output, 'utf-8').strip())
self.display.appendPlainText(unicode(output).strip())

if self.name == 'hydra': # check if any usernames/passwords were found (if so emit a signal so that the gui can tell the user about it)
found, userlist, passlist = checkHydraResults(output)
Expand All @@ -186,7 +188,8 @@ def readStdOutput(self):
stderror = QString(self.readAllStandardError())

if len(stderror) > 0:
self.display.appendPlainText(unicode(stderror, 'utf-8').strip()) # append standard error too
#self.display.appendPlainText(unicode(stderror, 'utf-8').strip()) # append standard error too
self.display.appendPlainText(unicode(stderror).strip()) # append standard error too

# browser opener class with queue and semaphores
class BrowserOpener(QtCore.QThread):
Expand Down
11 changes: 5 additions & 6 deletions app/logic.py
Expand Up @@ -398,16 +398,16 @@ def toggleHostCheckStatus(self, ipaddr):
# this function adds a new process to the DB
def addProcessToDB(self, proc):
p_output = process_output() # add row to process_output table (separate table for performance reasons)
p = process(str(proc.pid()), str(proc.name), str(proc.tabtitle), str(proc.hostip), str(proc.port), str(proc.protocol), unicode(proc.command), str(proc.starttime), str(proc.outputfile), 'Waiting', p_output)
p = process(str(proc.pid()), str(proc.name), str(proc.tabtitle), str(proc.hostip), str(proc.port), str(proc.protocol), unicode(proc.command), proc.starttime, str(proc.outputfile), 'Waiting', p_output)
self.db.commit()
proc.id = p.id
return p.id

def addScreenshotToDB(self, ip, port, filename):
p_output = process_output() # add row to process_output table (separate table for performance reasons)
p = process("-2", "screenshooter", "screenshot ("+str(port)+"/tcp)", str(ip), str(port), "tcp", "", str(getTimestamp(True)), str(filename), "Finished", p_output)
p = process("-2", "screenshooter", "screenshot ("+str(port)+"/tcp)", str(ip), str(port), "tcp", "", getTimestamp(True), str(filename), "Finished", p_output)
self.db.commit()
return p.id
return p.id

# is not actually a toggle function. it sets all the non-running processes display flag to false to ensure they aren't shown in the process table
# but they need to be shown as tool tabs. this function is called when a user clears the processes or when a project is being closed.
Expand Down Expand Up @@ -507,7 +507,7 @@ def isCanceledProcess(self, procId):
class NmapImporter(QtCore.QThread):
tick = QtCore.pyqtSignal(int, name="changed") # New style signal
done = QtCore.pyqtSignal(name="done") # New style signal
schedule = QtCore.pyqtSignal(str, name="schedule") # New style signal
schedule = QtCore.pyqtSignal(object, bool, name="schedule") # New style signal

def __init__(self):
QtCore.QThread.__init__(self, parent=None)
Expand Down Expand Up @@ -682,8 +682,7 @@ def run(self): # it is necessary to get the qprocess because we nee
self.db.dbsemaphore.release() # we are done with the DB
print '\t[+] Finished in '+ str(time.time()-starttime) + ' seconds.'
self.done.emit()
if not self.output == '':
self.schedule.emit(self.output) # call the scheduler
self.schedule.emit(parser, self.output == '') # call the scheduler (if there is no terminal output it means we imported nmap)

except:
print '\t[-] Something went wrong when parsing the nmap file..'
Expand Down
36 changes: 36 additions & 0 deletions app/processmodels.py
Expand Up @@ -91,6 +91,42 @@ def sort(self, Ncol, order):
self.emit(SIGNAL("layoutAboutToBeChanged()"))
array=[]

if Ncol == 4:
for i in range(len(self.__processes)):
array.append(self.__processes[i]['tabtitle'])

elif Ncol == 5:
for i in range(len(self.__processes)):
array.append(IP2Int(self.__processes[i]['hostip']))

elif Ncol == 6:
for i in range(len(self.__processes)):
if self.__processes[i]['port'] == '':
return
else:
array.append(int(self.__processes[i]['port']))

elif Ncol == 9:
for i in range(len(self.__processes)):
array.append(self.__processes[i]['starttime'])

else:
for i in range(len(self.__processes)):
array.append(self.__processes[i]['status'])

sortArrayWithArray(array, self.__processes) # sort the services based on the values in the array

if order == Qt.AscendingOrder: # reverse if needed
self.__processes.reverse()

self.__controller.updateProcessesIcon() # to make sure the progress GIF is displayed in the right place

self.emit(SIGNAL("layoutChanged()"))

def sort_old(self, Ncol, order):
self.emit(SIGNAL("layoutAboutToBeChanged()"))
array=[]

if Ncol == 4:
for i in range(len(self.__processes)):
array.append(self.__processes[i]['tabtitle'])
Expand Down
10 changes: 9 additions & 1 deletion app/settings.py
Expand Up @@ -43,6 +43,7 @@ def createDefaultSettings(self):
self.actions.setValue('screenshooter-timeout','15000')
self.actions.setValue('web-services','http,https,ssl,soap,http-proxy,http-alt,https-alt')
self.actions.setValue('enable-scheduler','True')
self.actions.setValue('enable-scheduler-on-import','False')
self.actions.setValue('max-fast-processes', '10')
self.actions.setValue('max-slow-processes', '10')
self.actions.endGroup()
Expand Down Expand Up @@ -88,6 +89,7 @@ def createDefaultSettings(self):
self.actions.setValue("nikto", ["Run nikto", "nikto -o [OUTPUT].txt -p [PORT] -h [IP]", "http,https,ssl,soap,http-proxy,http-alt"])
self.actions.setValue("dirbuster", ["Launch dirbuster", "java -Xmx256M -jar /usr/share/dirbuster/DirBuster-1.0-RC1.jar -u http://[IP]:[PORT]/", "http,https,ssl,soap,http-proxy,http-alt"])
self.actions.setValue("webslayer", ["Launch webslayer", "webslayer", "http,https,ssl,soap,http-proxy,http-alt"])
self.actions.setValue("whatweb", ["Run whatweb", "whatweb [IP]:[PORT] --color=never --log-brief=[OUTPUT].txt", "http,https,ssl,soap,http-proxy,http-alt"])

### SMB
self.actions.setValue("samrdump", ["Run samrdump", "python /usr/share/doc/python-impacket-doc/examples/samrdump.py [IP] [PORT]/SMB", "netbios-ssn,microsoft-ds"])
Expand All @@ -108,9 +110,12 @@ def createDefaultSettings(self):
self.actions.setValue("ldapsearch", ["Run ldapsearch", "ldapsearch -h [IP] -p [PORT] -x -s base", "ldap"])
self.actions.setValue("snmpcheck", ["Run snmpcheck", "snmpcheck -t [IP]", "snmp,snmptrap"])
self.actions.setValue("rpcinfo", ["Run rpcinfo", "rpcinfo -p [IP]", "rpcbind"])
self.actions.setValue("rdp-sec-check", ["Run rdp-sec-check.pl", "perl ./scripts/rdp-sec-check.pl [IP]:[PORT]", "ms-wbt-server"])
self.actions.setValue("showmount", ["Show nfs shares", "showmount -e [IP]", "nfs"])
self.actions.setValue("x11screen", ["Run x11screenshot", "bash ./scripts/x11screenshot.sh [IP]", "X11"])
self.actions.setValue("sslscan", ["Run sslscan", "sslscan --no-failed [IP]:[PORT]", "http,https,ssl,soap,http-proxy,http-alt"])
self.actions.setValue("sslscan", ["Run sslscan", "sslscan --no-failed [IP]:[PORT]", "https,ssl"])
self.actions.setValue("sslyze", ["Run sslyze", "sslyze --regular [IP]:[PORT]", "https,ssl,ms-wbt-server,imap,pop3,smtp"])

self.actions.setValue("rwho", ["Run rwho", "rwho -a [IP]", "who"])
self.actions.setValue("finger", ["Enumerate users (finger)", "./scripts/fingertool.sh [IP]", "finger"])

Expand Down Expand Up @@ -151,6 +156,7 @@ def createDefaultSettings(self):

self.actions.beginGroup('SchedulerSettings')
self.actions.setValue("nikto",["http,https,ssl,soap,http-proxy,http-alt","tcp"])
self.actions.setValue("screenshooter",["http,https,ssl,http-proxy,http-alt","tcp"])
self.actions.setValue("smbenum",["microsoft-ds","tcp"])
# self.actions.setValue("enum4linux","netbios-ssn,microsoft-ds")
# self.actions.setValue("smb-null-sessions","netbios-ssn,microsoft-ds")
Expand Down Expand Up @@ -276,6 +282,7 @@ def backupAndSave(self, newSettings):
self.actions.setValue('screenshooter-timeout',newSettings.general_screenshooter_timeout)
self.actions.setValue('web-services',newSettings.general_web_services)
self.actions.setValue('enable-scheduler',newSettings.general_enable_scheduler)
self.actions.setValue('enable-scheduler-on-import',newSettings.general_enable_scheduler_on_import)
self.actions.setValue('max-fast-processes', newSettings.general_max_fast_processes)
self.actions.setValue('max-slow-processes', newSettings.general_max_slow_processes)
self.actions.endGroup()
Expand Down Expand Up @@ -380,6 +387,7 @@ def __init__(self, appSettings=None):
self.general_screenshooter_timeout = self.generalSettings['screenshooter-timeout']
self.general_web_services = self.generalSettings['web-services']
self.general_enable_scheduler = self.generalSettings['enable-scheduler']
self.general_enable_scheduler_on_import = self.generalSettings['enable-scheduler-on-import']
self.general_max_fast_processes = self.generalSettings['max-fast-processes']
self.general_max_slow_processes = self.generalSettings['max-slow-processes']

Expand Down
70 changes: 33 additions & 37 deletions controller/controller.py
Expand Up @@ -22,7 +22,7 @@ class Controller():

# initialisations that will happen once - when the program is launched
def __init__(self, view, logic):
self.version = 'SPARTA 1.0 (BETA)' # update this everytime you commit!
self.version = 'SPARTA 1.0.1 (BETA)' # update this everytime you commit!
self.logic = logic
self.view = view
self.view.setController(self)
Expand Down Expand Up @@ -616,32 +616,21 @@ def handleHydraFindings(self, bWidget, userlist, passlist): # when hydra finds
self.logic.passwordsWordlist.add(password)

# this function parses nmap's output looking for open ports to run automated attacks on
def scheduler(self, nmapoutput):
#print '[+] Calling scheduler..'
def scheduler(self, parser, isNmapImport):
if isNmapImport and self.settings.general_enable_scheduler_on_import == 'False':
return
if self.settings.general_enable_scheduler == 'True':
print '[+] Scheduler started!'

hosts = re.split('Nmap scan report for',nmapoutput) # split nmap scan by hosts
for host in hosts:
ip = re.search('[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+',host)
if ip: # search for open ports

tcpopenports = re.findall('[0-9]+/tcp[\s]+open[\s]+.+\\n', str(host), re.I)
for tcpopenport in tcpopenports:
portservice = re.search('([0-9]+)/tcp[\s]+open[\s]+([^\s]+)', tcpopenport)
if portservice:
self.runToolsFor(str(portservice.group(2)), str(ip.group()), str(portservice.group(1)), 'tcp')

#udpopenports = re.findall('[0-9]+/udp[\s]+open[\s]+.+\\n', str(host), re.I)
udpopenports = re.findall('[0-9]+/udp[\s]+open\|*\w{0,8}[\s]+.+\\n', str(host), re.I)
for udpopenport in udpopenports:
#portservice = re.search('([0-9]+)/udp[\s]+open[\s]+([^\s]+)', udpopenport)
portservice = re.search('([0-9]+)/udp[\s]+open\|*\w{0,8}[\s]+([^\s]+)', udpopenport)
if portservice:
self.runToolsFor(str(portservice.group(2)), str(ip.group()), str(portservice.group(1)), 'udp')
for h in parser.all_hosts():
for p in h.all_ports():
if p.state == 'open':
s = p.get_service()
if not (s is None):
self.runToolsFor(s.name, h.ip, p.portId, p.protocol)

print '-----------------------------------------------'
print '[+] Scheduler ended!'
print '-----------------------------------------------'
print '[+] Scheduler ended!'

def runToolsFor(self, service, ip, port, protocol='tcp'):
print '\t[+] Running tools for: ' + service + ' on ' + ip + ':' + port
Expand All @@ -652,17 +641,24 @@ def runToolsFor(self, service, ip, port, protocol='tcp'):
for tool in self.settings.automatedAttacks:
if service in tool[1].split(",") and protocol==tool[2]:
#print '\tFound tool: ' + tool[0]
for a in self.settings.portActions:
if tool[0] == a[1]:
restoring = False
tabtitle = a[1]+" ("+port+"/"+protocol+")"
outputfile = self.logic.runningfolder+"/"+getTimestamp()+'-'+a[1]+"-"+ip+"-"+port
command = str(a[2])
command = command.replace('[IP]', ip).replace('[PORT]', port).replace('[OUTPUT]', outputfile)

if 'nmap' in tabtitle: # we don't want to show nmap tabs
restoring = True

tab = self.view.ui.HostsTabWidget.tabText(self.view.ui.HostsTabWidget.currentIndex())
self.runCommand(tool[0], tabtitle, ip, port, protocol, command, getTimestamp(True), outputfile, self.view.createNewTabForHost(ip, tabtitle, not (tab == 'Hosts')))
break
if tool[0] == "screenshooter":
url = ip+':'+port
self.screenshooter.addToQueue(url)
self.screenshooter.start()

else:
for a in self.settings.portActions:
if tool[0] == a[1]:
restoring = False
tabtitle = a[1]+" ("+port+"/"+protocol+")"
outputfile = self.logic.runningfolder+"/"+getTimestamp()+'-'+a[1]+"-"+ip+"-"+port
command = str(a[2])
command = command.replace('[IP]', ip).replace('[PORT]', port).replace('[OUTPUT]', outputfile)

if 'nmap' in tabtitle: # we don't want to show nmap tabs
restoring = True

tab = self.view.ui.HostsTabWidget.tabText(self.view.ui.HostsTabWidget.currentIndex())
self.runCommand(tool[0], tabtitle, ip, port, protocol, command, getTimestamp(True), outputfile, self.view.createNewTabForHost(ip, tabtitle, not (tab == 'Hosts')))
break

0 comments on commit c3c34e5

Please sign in to comment.