From 40fa501fc461602ad208de4195f09e4750341847 Mon Sep 17 00:00:00 2001 From: GitHub Date: Tue, 16 Apr 2019 16:07:51 -0400 Subject: [PATCH 01/20] Setting python variable --- legion.conf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/legion.conf b/legion.conf index c9872748..14e4dbb0 100644 --- a/legion.conf +++ b/legion.conf @@ -277,7 +277,7 @@ webslayer=Launch webslayer, webslayer, "http,https,ssl,soap,http-proxy,http-alt" whatweb=Run whatweb, "whatweb [IP]:[PORT] --color=never --log-brief=[OUTPUT].txt", "http,https,ssl,soap,http-proxy,http-alt" x11screen=Run x11screenshot, bash ./scripts/x11screenshot.sh [IP] 0 [OUTPUT], X11 dnsmap=Run dnsmap, "dnsmap [IP] -w ./wordlists/gvit_subdomain_wordlist.txt -r [OUTPUT]", dnsmap -cloudfail=Run cloudfail, "python3.7 scripts/CloudFail/cloudfail.py --target [IP] --tor", cloudfail +cloudfail=Run cloudfail, "python scripts/CloudFail/cloudfail.py --target [IP] --tor", cloudfail [PortTerminalActions] firefox=Open with firefox, firefox [IP]:[PORT], @@ -320,3 +320,4 @@ cutycapt-path=/usr/bin/cutycapt hydra-path=/usr/bin/hydra nmap-path=/usr/bin/nmap texteditor-path=/usr/bin/leafpad +python-path=/usr/bin/python From 3c11d5177bb58732d242682cb71e6abdc5be2fc2 Mon Sep 17 00:00:00 2001 From: GitHub Date: Tue, 16 Apr 2019 16:11:51 -0400 Subject: [PATCH 02/20] Added python variable --- app/settings.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/settings.py b/app/settings.py index 2bb98378..dafdff9a 100644 --- a/app/settings.py +++ b/app/settings.py @@ -165,6 +165,7 @@ def backupAndSave(self, newSettings, saveBackup = True): self.actions.setValue('hydra-path', newSettings.tools_path_hydra) self.actions.setValue('cutycapt-path', newSettings.tools_path_cutycapt) self.actions.setValue('texteditor-path', newSettings.tools_path_texteditor) + self.actions.setValue('python-path', newSettings.tools_path_python) self.actions.endGroup() self.actions.beginGroup('StagedNmapSettings') @@ -238,6 +239,7 @@ def __init__(self, appSettings=None): self.tools_path_hydra = "/usr/bin/hydra" self.tools_path_cutycapt = "/usr/bin/cutycapt" self.tools_path_texteditor = "/usr/bin/leafpad" + self.tools_path_python = os.environ["PYTHON3BIN"] # GUI settings self.gui_process_tab_column_widths = "125,0,100,150,100,100,100,100,100,100,100,100,100,100,100,100,100" @@ -294,6 +296,7 @@ def __init__(self, appSettings=None): self.tools_path_hydra = self.toolSettings['hydra-path'] self.tools_path_cutycapt = self.toolSettings['cutycapt-path'] self.tools_path_texteditor = self.toolSettings['texteditor-path'] + self.tools_path_python = self.toolSettings['python-path'] # gui self.gui_process_tab_column_widths = self.guiSettings['process-tab-column-widths'] From 4c5c8c1e5ea538473b8b67d472531387c427a5f3 Mon Sep 17 00:00:00 2001 From: GitHub Date: Thu, 18 Apr 2019 17:31:14 -0400 Subject: [PATCH 03/20] Editing Python env variable --- deps/detectPython.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/deps/detectPython.sh b/deps/detectPython.sh index ff559847..f3e3714b 100644 --- a/deps/detectPython.sh +++ b/deps/detectPython.sh @@ -241,5 +241,6 @@ fi echo "Python 3 bin is ${pythonBin} ($(which ${pythonBin}))" echo "Pip 3 bin is ${pipBin} ($(which ${pipBin}))" -export PYTHON3BIN=$(which ${pythonBin}) +PYTHON3BIN=${pythonBin} +export PYTHON3BIN export PIP3BIN=$(which ${pipBin}) From f3bdeedc63a9fab813ac88dcd0552968da1b1441 Mon Sep 17 00:00:00 2001 From: GitHub Date: Thu, 18 Apr 2019 17:50:37 -0400 Subject: [PATCH 04/20] Changed default python variable to python3 --- legion.conf | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/legion.conf b/legion.conf index 14e4dbb0..76055f97 100644 --- a/legion.conf +++ b/legion.conf @@ -41,7 +41,7 @@ citrix-enum-apps-xml.nse=citrix-enum-apps-xml.nse, "nmap -Pn [IP] -p [PORT] --sc citrix-enum-apps.nse=citrix-enum-apps.nse, "nmap -Pn [IP] -p [PORT] --script=citrix-enum-apps.nse --script-args=unsafe=1", citrix citrix-enum-servers-xml.nse=citrix-enum-servers-xml.nse, "nmap -Pn [IP] -p [PORT] --script=citrix-enum-servers-xml.nse --script-args=unsafe=1", citrix citrix-enum-servers.nse=citrix-enum-servers.nse, "nmap -Pn [IP] -p [PORT] --script=citrix-enum-servers.nse --script-args=unsafe=1", citrix -cloudfail=Run cloudfail, python scripts/CloudFail/cloudfail.py --target [IP] --tor, cloudfail +cloudfail=Run cloudfail, python3 scripts/CloudFail/cloudfail.py --target [IP] --tor, cloudfail 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" dnsmap=Run dnsmap, dnsmap [IP] -w ./wordlists/gvit_subdomain_wordlist.txt -r [OUTPUT], dnsmap enum4linux=Run enum4linux, enum4linux [IP], "netbios-ssn,microsoft-ds" @@ -212,7 +212,7 @@ riak-http-info.nse=riak-http-info.nse, "nmap -Pn [IP] -p [PORT] --script=riak-ht rpcinfo=Run rpcinfo, rpcinfo -p [IP], rpcbind rwho=Run rwho, rwho -a [IP], who samba-vuln-cve-2012-1182.nse=samba-vuln-cve-2012-1182.nse, "nmap -Pn [IP] -p [PORT] --script=samba-vuln-cve-2012-1182.nse --script-args=unsafe=1", samba -samrdump=Run samrdump, python /usr/share/doc/python-impacket-doc/examples/samrdump.py [IP] [PORT]/SMB, "netbios-ssn,microsoft-ds" +samrdump=Run samrdump, python3 /usr/share/doc/python-impacket-doc/examples/samrdump.py [IP] [PORT]/SMB, "netbios-ssn,microsoft-ds" showmount=Show nfs shares, showmount -e [IP], nfs smb-brute.nse=smb-brute.nse, "nmap -Pn [IP] -p [PORT] --script=smb-brute.nse --script-args=unsafe=1", smb smb-check-vulns.nse=smb-check-vulns.nse, "nmap -Pn [IP] -p [PORT] --script=smb-check-vulns.nse --script-args=unsafe=1", smb @@ -256,7 +256,7 @@ smtp-vuln-cve2011-1720.nse=smtp-vuln-cve2011-1720.nse, "nmap -Pn [IP] -p [PORT] smtp-vuln-cve2011-1764.nse=smtp-vuln-cve2011-1764.nse, "nmap -Pn [IP] -p [PORT] --script=smtp-vuln-cve2011-1764.nse --script-args=unsafe=1", smtp snmp-brute=Bruteforce community strings (medusa), bash -c \"medusa -h [IP] -u root -P ./wordlists/snmp-default.txt -M snmp | grep SUCCESS\", "snmp,snmptrap" snmp-brute.nse=snmp-brute.nse, "nmap -Pn [IP] -p [PORT] --script=snmp-brute.nse --script-args=unsafe=1", snmp -snmp-default=Check for default community strings, python ./scripts/snmpbrute.py -t [IP] -p [PORT] -f ./wordlists/snmp-default.txt -b --no-colours, "snmp,snmptrap" +snmp-default=Check for default community strings, python3 ./scripts/snmpbrute.py -t [IP] -p [PORT] -f ./wordlists/snmp-default.txt -b --no-colours, "snmp,snmptrap" snmp-hh3c-logins.nse=snmp-hh3c-logins.nse, "nmap -Pn [IP] -p [PORT] --script=snmp-hh3c-logins.nse --script-args=unsafe=1", snmp snmp-interfaces.nse=snmp-interfaces.nse, "nmap -Pn [IP] -p [PORT] --script=snmp-interfaces.nse --script-args=unsafe=1", snmp snmp-ios-config.nse=snmp-ios-config.nse, "nmap -Pn [IP] -p [PORT] --script=snmp-ios-config.nse --script-args=unsafe=1", snmp @@ -277,12 +277,12 @@ webslayer=Launch webslayer, webslayer, "http,https,ssl,soap,http-proxy,http-alt" whatweb=Run whatweb, "whatweb [IP]:[PORT] --color=never --log-brief=[OUTPUT].txt", "http,https,ssl,soap,http-proxy,http-alt" x11screen=Run x11screenshot, bash ./scripts/x11screenshot.sh [IP] 0 [OUTPUT], X11 dnsmap=Run dnsmap, "dnsmap [IP] -w ./wordlists/gvit_subdomain_wordlist.txt -r [OUTPUT]", dnsmap -cloudfail=Run cloudfail, "python scripts/CloudFail/cloudfail.py --target [IP] --tor", cloudfail +cloudfail=Run cloudfail, "python3 scripts/CloudFail/cloudfail.py --target [IP] --tor", cloudfail [PortTerminalActions] firefox=Open with firefox, firefox [IP]:[PORT], ftp=Open with ftp client, ftp [IP] [PORT], ftp -mssql=Open with mssql client (as sa), python /usr/share/doc/python-impacket-doc/examples/mssqlclient.py -p [PORT] sa@[IP], "mys-sql-s,codasrv-se" +mssql=Open with mssql client (as sa), python3 /usr/share/doc/python-impacket-doc/examples/mssqlclient.py -p [PORT] sa@[IP], "mys-sql-s,codasrv-se" mysql=Open with mysql client (as root), "mysql -u root -h [IP] --port=[PORT] -p", mysql netcat=Open with netcat, nc -v [IP] [PORT], psql=Open with postgres client (as postgres), psql -h [IP] -p [PORT] -U postgres, postgres @@ -320,4 +320,4 @@ cutycapt-path=/usr/bin/cutycapt hydra-path=/usr/bin/hydra nmap-path=/usr/bin/nmap texteditor-path=/usr/bin/leafpad -python-path=/usr/bin/python +python-path=/usr/bin/python3 From 5021fe3355b90d76af8adb5108d689235ade64e1 Mon Sep 17 00:00:00 2001 From: GitHub Date: Fri, 19 Apr 2019 15:22:05 -0400 Subject: [PATCH 05/20] Added wpscan --- deps/installDeps.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/installDeps.sh b/deps/installDeps.sh index dc9cfcc5..3cb9216c 100644 --- a/deps/installDeps.sh +++ b/deps/installDeps.sh @@ -9,4 +9,4 @@ source ./deps/apt.sh apt-get update -m echo "Installing deps..." -DEBIAN_FRONTEND="noninteractive" apt-get -yqqq --allow-unauthenticated --force-yes -o DPkg::Options::="--force-overwrite" -o DPkg::Options::="--force-confdef" install nmap finger hydra nikto whatweb nbtscan nfs-common rpcbind smbclient sra-toolkit ldap-utils sslscan rwho medusa x11-apps cutycapt leafpad xvfb imagemagick eog hping3 sqlmap wapiti libqt5core5a python-pip python-impacket ruby perl dnsmap urlscan git +DEBIAN_FRONTEND="noninteractive" apt-get -yqqq --allow-unauthenticated --force-yes -o DPkg::Options::="--force-overwrite" -o DPkg::Options::="--force-confdef" install nmap finger hydra nikto whatweb nbtscan nfs-common rpcbind smbclient sra-toolkit ldap-utils sslscan rwho medusa x11-apps cutycapt leafpad xvfb imagemagick eog hping3 sqlmap wapiti libqt5core5a python-pip python-impacket ruby perl dnsmap urlscan wpscan git From 6c804e281fd5a47c99df2c4b55e40d167b620c67 Mon Sep 17 00:00:00 2001 From: GitHub Date: Fri, 19 Apr 2019 15:33:03 -0400 Subject: [PATCH 06/20] Added wpscan --- legion.conf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/legion.conf b/legion.conf index 76055f97..36f1965c 100644 --- a/legion.conf +++ b/legion.conf @@ -42,6 +42,7 @@ citrix-enum-apps.nse=citrix-enum-apps.nse, "nmap -Pn [IP] -p [PORT] --script=cit citrix-enum-servers-xml.nse=citrix-enum-servers-xml.nse, "nmap -Pn [IP] -p [PORT] --script=citrix-enum-servers-xml.nse --script-args=unsafe=1", citrix citrix-enum-servers.nse=citrix-enum-servers.nse, "nmap -Pn [IP] -p [PORT] --script=citrix-enum-servers.nse --script-args=unsafe=1", citrix cloudfail=Run cloudfail, python3 scripts/CloudFail/cloudfail.py --target [IP] --tor, cloudfail +wpscan=Run wpscan, wpscan -v --url [IP]:[PORT], wpscan 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" dnsmap=Run dnsmap, dnsmap [IP] -w ./wordlists/gvit_subdomain_wordlist.txt -r [OUTPUT], dnsmap enum4linux=Run enum4linux, enum4linux [IP], "netbios-ssn,microsoft-ds" @@ -278,6 +279,7 @@ whatweb=Run whatweb, "whatweb [IP]:[PORT] --color=never --log-brief=[OUTPUT].txt x11screen=Run x11screenshot, bash ./scripts/x11screenshot.sh [IP] 0 [OUTPUT], X11 dnsmap=Run dnsmap, "dnsmap [IP] -w ./wordlists/gvit_subdomain_wordlist.txt -r [OUTPUT]", dnsmap cloudfail=Run cloudfail, "python3 scripts/CloudFail/cloudfail.py --target [IP] --tor", cloudfail +wpscan=Run wpscan, "wpscan -v --url [IP]:[PORT]", wpscan [PortTerminalActions] firefox=Open with firefox, firefox [IP]:[PORT], From c8de218f700042032c6a5ca1d0e69f574c014d58 Mon Sep 17 00:00:00 2001 From: GitHub Date: Fri, 19 Apr 2019 15:39:10 -0400 Subject: [PATCH 07/20] Added wafw00f --- deps/installDeps.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/installDeps.sh b/deps/installDeps.sh index 3cb9216c..5a0e88fc 100644 --- a/deps/installDeps.sh +++ b/deps/installDeps.sh @@ -9,4 +9,4 @@ source ./deps/apt.sh apt-get update -m echo "Installing deps..." -DEBIAN_FRONTEND="noninteractive" apt-get -yqqq --allow-unauthenticated --force-yes -o DPkg::Options::="--force-overwrite" -o DPkg::Options::="--force-confdef" install nmap finger hydra nikto whatweb nbtscan nfs-common rpcbind smbclient sra-toolkit ldap-utils sslscan rwho medusa x11-apps cutycapt leafpad xvfb imagemagick eog hping3 sqlmap wapiti libqt5core5a python-pip python-impacket ruby perl dnsmap urlscan wpscan git +DEBIAN_FRONTEND="noninteractive" apt-get -yqqq --allow-unauthenticated --force-yes -o DPkg::Options::="--force-overwrite" -o DPkg::Options::="--force-confdef" install nmap finger hydra nikto whatweb nbtscan nfs-common rpcbind smbclient sra-toolkit ldap-utils sslscan rwho medusa x11-apps cutycapt leafpad xvfb imagemagick eog hping3 sqlmap wapiti libqt5core5a python-pip python-impacket ruby perl dnsmap urlscan wpscan wafw00f git From 5b37f966443651efe03c1dc4ba6978cb07473674 Mon Sep 17 00:00:00 2001 From: GitHub Date: Fri, 19 Apr 2019 15:40:49 -0400 Subject: [PATCH 08/20] Added wafw00f --- legion.conf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/legion.conf b/legion.conf index 36f1965c..c2767658 100644 --- a/legion.conf +++ b/legion.conf @@ -43,6 +43,7 @@ citrix-enum-servers-xml.nse=citrix-enum-servers-xml.nse, "nmap -Pn [IP] -p [PORT citrix-enum-servers.nse=citrix-enum-servers.nse, "nmap -Pn [IP] -p [PORT] --script=citrix-enum-servers.nse --script-args=unsafe=1", citrix cloudfail=Run cloudfail, python3 scripts/CloudFail/cloudfail.py --target [IP] --tor, cloudfail wpscan=Run wpscan, wpscan -v --url [IP]:[PORT], wpscan +wafw00f=Run wafw00f, wafw00f [IP], wafw00f 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" dnsmap=Run dnsmap, dnsmap [IP] -w ./wordlists/gvit_subdomain_wordlist.txt -r [OUTPUT], dnsmap enum4linux=Run enum4linux, enum4linux [IP], "netbios-ssn,microsoft-ds" @@ -280,6 +281,7 @@ x11screen=Run x11screenshot, bash ./scripts/x11screenshot.sh [IP] 0 [OUTPUT], X1 dnsmap=Run dnsmap, "dnsmap [IP] -w ./wordlists/gvit_subdomain_wordlist.txt -r [OUTPUT]", dnsmap cloudfail=Run cloudfail, "python3 scripts/CloudFail/cloudfail.py --target [IP] --tor", cloudfail wpscan=Run wpscan, "wpscan -v --url [IP]:[PORT]", wpscan +wafw00f=Run wafw00f, "wafw00f [IP]", wafw00f [PortTerminalActions] firefox=Open with firefox, firefox [IP]:[PORT], From b3faf54867867814bf7d56353ce5fe2d8cb319d0 Mon Sep 17 00:00:00 2001 From: GitHub Date: Mon, 22 Apr 2019 11:56:12 -0400 Subject: [PATCH 09/20] Added AutoSploit --- deps/detectScripts.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/deps/detectScripts.sh b/deps/detectScripts.sh index 28d95648..5a230aae 100644 --- a/deps/detectScripts.sh +++ b/deps/detectScripts.sh @@ -66,6 +66,13 @@ else git clone https://github.com/m0rtem/CloudFail.git scripts/CloudFail fi +if [ -a scripts/AutoSploit/autosploit.py ] + then + echo "AutoSploit is already installed" +else + git clone https://github.com/NullArray/AutoSploit.git scripts/AutoSploit +fi + if [ ! -f ".initialized" ] then scripts/installDeps.sh From 6884f3c403a40feefc42f4d6f55f28d1bc5fb29f Mon Sep 17 00:00:00 2001 From: GitHub Date: Mon, 22 Apr 2019 12:00:56 -0400 Subject: [PATCH 10/20] Added autosploit --- legion.conf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/legion.conf b/legion.conf index c2767658..417cf9d6 100644 --- a/legion.conf +++ b/legion.conf @@ -44,6 +44,7 @@ citrix-enum-servers.nse=citrix-enum-servers.nse, "nmap -Pn [IP] -p [PORT] --scri cloudfail=Run cloudfail, python3 scripts/CloudFail/cloudfail.py --target [IP] --tor, cloudfail wpscan=Run wpscan, wpscan -v --url [IP]:[PORT], wpscan wafw00f=Run wafw00f, wafw00f [IP], wafw00f +autosploit=Run autosploit, python3 scripts/AutoSploit/autosploit.py -e -C default [IP] [PORT], autosploit 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" dnsmap=Run dnsmap, dnsmap [IP] -w ./wordlists/gvit_subdomain_wordlist.txt -r [OUTPUT], dnsmap enum4linux=Run enum4linux, enum4linux [IP], "netbios-ssn,microsoft-ds" @@ -282,6 +283,7 @@ dnsmap=Run dnsmap, "dnsmap [IP] -w ./wordlists/gvit_subdomain_wordlist.txt -r [O cloudfail=Run cloudfail, "python3 scripts/CloudFail/cloudfail.py --target [IP] --tor", cloudfail wpscan=Run wpscan, "wpscan -v --url [IP]:[PORT]", wpscan wafw00f=Run wafw00f, "wafw00f [IP]", wafw00f +autosploit=Run autosploit, "python3 scripts/AutoSploit/autosploit.py -e -C default [IP] [PORT]", autosploit [PortTerminalActions] firefox=Open with firefox, firefox [IP]:[PORT], From dd26407a47b624ed38034acc1921aadbb84d8a7d Mon Sep 17 00:00:00 2001 From: GitHub Date: Mon, 22 Apr 2019 12:37:26 -0400 Subject: [PATCH 11/20] Edited autosploit --- legion.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/legion.conf b/legion.conf index 417cf9d6..5029ba61 100644 --- a/legion.conf +++ b/legion.conf @@ -44,7 +44,7 @@ citrix-enum-servers.nse=citrix-enum-servers.nse, "nmap -Pn [IP] -p [PORT] --scri cloudfail=Run cloudfail, python3 scripts/CloudFail/cloudfail.py --target [IP] --tor, cloudfail wpscan=Run wpscan, wpscan -v --url [IP]:[PORT], wpscan wafw00f=Run wafw00f, wafw00f [IP], wafw00f -autosploit=Run autosploit, python3 scripts/AutoSploit/autosploit.py -e -C default [IP] [PORT], autosploit +autosploit=Run autosploit, python scripts/AutoSploit/autosploit.py -e -C default [IP] [PORT], autosploit 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" dnsmap=Run dnsmap, dnsmap [IP] -w ./wordlists/gvit_subdomain_wordlist.txt -r [OUTPUT], dnsmap enum4linux=Run enum4linux, enum4linux [IP], "netbios-ssn,microsoft-ds" @@ -283,7 +283,7 @@ dnsmap=Run dnsmap, "dnsmap [IP] -w ./wordlists/gvit_subdomain_wordlist.txt -r [O cloudfail=Run cloudfail, "python3 scripts/CloudFail/cloudfail.py --target [IP] --tor", cloudfail wpscan=Run wpscan, "wpscan -v --url [IP]:[PORT]", wpscan wafw00f=Run wafw00f, "wafw00f [IP]", wafw00f -autosploit=Run autosploit, "python3 scripts/AutoSploit/autosploit.py -e -C default [IP] [PORT]", autosploit +autosploit=Run autosploit, "python scripts/AutoSploit/autosploit.py -e -C default [IP] [PORT]", autosploit [PortTerminalActions] firefox=Open with firefox, firefox [IP]:[PORT], From cf2fee9505b4c456bf180834b7e44c4c495c10e9 Mon Sep 17 00:00:00 2001 From: GitHub Date: Mon, 22 Apr 2019 16:19:00 -0400 Subject: [PATCH 12/20] Fixed autosploit --- legion.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/legion.conf b/legion.conf index 5029ba61..d1b0c2f2 100644 --- a/legion.conf +++ b/legion.conf @@ -44,7 +44,7 @@ citrix-enum-servers.nse=citrix-enum-servers.nse, "nmap -Pn [IP] -p [PORT] --scri cloudfail=Run cloudfail, python3 scripts/CloudFail/cloudfail.py --target [IP] --tor, cloudfail wpscan=Run wpscan, wpscan -v --url [IP]:[PORT], wpscan wafw00f=Run wafw00f, wafw00f [IP], wafw00f -autosploit=Run autosploit, python scripts/AutoSploit/autosploit.py -e -C default [IP] [PORT], autosploit +autosploit=Run autosploit, cd scripts/AutoSploit/ && python autosploit.py -e -C default [IP] [PORT], autosploit 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" dnsmap=Run dnsmap, dnsmap [IP] -w ./wordlists/gvit_subdomain_wordlist.txt -r [OUTPUT], dnsmap enum4linux=Run enum4linux, enum4linux [IP], "netbios-ssn,microsoft-ds" @@ -283,7 +283,7 @@ dnsmap=Run dnsmap, "dnsmap [IP] -w ./wordlists/gvit_subdomain_wordlist.txt -r [O cloudfail=Run cloudfail, "python3 scripts/CloudFail/cloudfail.py --target [IP] --tor", cloudfail wpscan=Run wpscan, "wpscan -v --url [IP]:[PORT]", wpscan wafw00f=Run wafw00f, "wafw00f [IP]", wafw00f -autosploit=Run autosploit, "python scripts/AutoSploit/autosploit.py -e -C default [IP] [PORT]", autosploit +autosploit=Run autosploit, "cd scripts/AutoSploit/ && python autosploit.py -e -C default [IP] [PORT]", autosploit [PortTerminalActions] firefox=Open with firefox, firefox [IP]:[PORT], From c80d93f1df39adc5064798da3341cfa77d3f8367 Mon Sep 17 00:00:00 2001 From: GitHub Date: Thu, 25 Apr 2019 13:17:52 -0400 Subject: [PATCH 13/20] Removed dnsmap --- deps/installDeps.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/installDeps.sh b/deps/installDeps.sh index 5a0e88fc..7ecfbcd2 100644 --- a/deps/installDeps.sh +++ b/deps/installDeps.sh @@ -9,4 +9,4 @@ source ./deps/apt.sh apt-get update -m echo "Installing deps..." -DEBIAN_FRONTEND="noninteractive" apt-get -yqqq --allow-unauthenticated --force-yes -o DPkg::Options::="--force-overwrite" -o DPkg::Options::="--force-confdef" install nmap finger hydra nikto whatweb nbtscan nfs-common rpcbind smbclient sra-toolkit ldap-utils sslscan rwho medusa x11-apps cutycapt leafpad xvfb imagemagick eog hping3 sqlmap wapiti libqt5core5a python-pip python-impacket ruby perl dnsmap urlscan wpscan wafw00f git +DEBIAN_FRONTEND="noninteractive" apt-get -yqqq --allow-unauthenticated --force-yes -o DPkg::Options::="--force-overwrite" -o DPkg::Options::="--force-confdef" install nmap finger hydra nikto whatweb nbtscan nfs-common rpcbind smbclient sra-toolkit ldap-utils sslscan rwho medusa x11-apps cutycapt leafpad xvfb imagemagick eog hping3 sqlmap wapiti libqt5core5a python-pip python-impacket ruby perl urlscan wpscan wafw00f git From 6eee8d679640c19a870678cf6c1485169b46a493 Mon Sep 17 00:00:00 2001 From: GitHub Date: Thu, 25 Apr 2019 13:48:35 -0400 Subject: [PATCH 14/20] Put dnsmap back for now --- deps/installDeps.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/installDeps.sh b/deps/installDeps.sh index 7ecfbcd2..396395d4 100644 --- a/deps/installDeps.sh +++ b/deps/installDeps.sh @@ -9,4 +9,4 @@ source ./deps/apt.sh apt-get update -m echo "Installing deps..." -DEBIAN_FRONTEND="noninteractive" apt-get -yqqq --allow-unauthenticated --force-yes -o DPkg::Options::="--force-overwrite" -o DPkg::Options::="--force-confdef" install nmap finger hydra nikto whatweb nbtscan nfs-common rpcbind smbclient sra-toolkit ldap-utils sslscan rwho medusa x11-apps cutycapt leafpad xvfb imagemagick eog hping3 sqlmap wapiti libqt5core5a python-pip python-impacket ruby perl urlscan wpscan wafw00f git +DEBIAN_FRONTEND="noninteractive" apt-get -yqqq --allow-unauthenticated --force-yes -o DPkg::Options::="--force-overwrite" -o DPkg::Options::="--force-confdef" install nmap finger hydra nikto whatweb nbtscan nfs-common rpcbind smbclient sra-toolkit ldap-utils sslscan rwho medusa x11-apps cutycapt leafpad xvfb imagemagick eog hping3 sqlmap wapiti libqt5core5a python-pip python-impacket ruby perl urlscan dnsmap wpscan wafw00f git From 05adceb163b24f0ddcd10d78151b40c1d75bb554 Mon Sep 17 00:00:00 2001 From: GitHub Date: Thu, 25 Apr 2019 17:35:17 -0400 Subject: [PATCH 15/20] Removed wpscan --- deps/installDeps.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/installDeps.sh b/deps/installDeps.sh index 396395d4..b0214051 100644 --- a/deps/installDeps.sh +++ b/deps/installDeps.sh @@ -9,4 +9,4 @@ source ./deps/apt.sh apt-get update -m echo "Installing deps..." -DEBIAN_FRONTEND="noninteractive" apt-get -yqqq --allow-unauthenticated --force-yes -o DPkg::Options::="--force-overwrite" -o DPkg::Options::="--force-confdef" install nmap finger hydra nikto whatweb nbtscan nfs-common rpcbind smbclient sra-toolkit ldap-utils sslscan rwho medusa x11-apps cutycapt leafpad xvfb imagemagick eog hping3 sqlmap wapiti libqt5core5a python-pip python-impacket ruby perl urlscan dnsmap wpscan wafw00f git +DEBIAN_FRONTEND="noninteractive" apt-get -yqqq --allow-unauthenticated --force-yes -o DPkg::Options::="--force-overwrite" -o DPkg::Options::="--force-confdef" install nmap finger hydra nikto whatweb nbtscan nfs-common rpcbind smbclient sra-toolkit ldap-utils sslscan rwho medusa x11-apps cutycapt leafpad xvfb imagemagick eog hping3 sqlmap wapiti libqt5core5a python-pip python-impacket ruby perl urlscan dnsmap wafw00f git From dd46fb2773d5b03df1526874255533f6905199f1 Mon Sep 17 00:00:00 2001 From: GitHub Date: Thu, 25 Apr 2019 17:48:04 -0400 Subject: [PATCH 16/20] Added wpscan --- deps/detectScripts.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/deps/detectScripts.sh b/deps/detectScripts.sh index 5a230aae..209449f0 100644 --- a/deps/detectScripts.sh +++ b/deps/detectScripts.sh @@ -73,6 +73,13 @@ else git clone https://github.com/NullArray/AutoSploit.git scripts/AutoSploit fi +if [ -d "scripts/wpscan" ] + then + echo "wpscan is already installed" +else + git clone https://github.com/wpscanteam/wpscan.git scripts/wpscan +fi + if [ ! -f ".initialized" ] then scripts/installDeps.sh From de417bfc22406c5d91ed502d6585849a15ab51cf Mon Sep 17 00:00:00 2001 From: GitHub Date: Thu, 25 Apr 2019 17:52:22 -0400 Subject: [PATCH 17/20] Edited wpscan --- legion.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/legion.conf b/legion.conf index d1b0c2f2..af4417da 100644 --- a/legion.conf +++ b/legion.conf @@ -42,7 +42,7 @@ citrix-enum-apps.nse=citrix-enum-apps.nse, "nmap -Pn [IP] -p [PORT] --script=cit citrix-enum-servers-xml.nse=citrix-enum-servers-xml.nse, "nmap -Pn [IP] -p [PORT] --script=citrix-enum-servers-xml.nse --script-args=unsafe=1", citrix citrix-enum-servers.nse=citrix-enum-servers.nse, "nmap -Pn [IP] -p [PORT] --script=citrix-enum-servers.nse --script-args=unsafe=1", citrix cloudfail=Run cloudfail, python3 scripts/CloudFail/cloudfail.py --target [IP] --tor, cloudfail -wpscan=Run wpscan, wpscan -v --url [IP]:[PORT], wpscan +wpscan=Run wpscan, ruby scripts/wpscan/bin/wpscan -v --url [IP]:[PORT], wpscan wafw00f=Run wafw00f, wafw00f [IP], wafw00f autosploit=Run autosploit, cd scripts/AutoSploit/ && python autosploit.py -e -C default [IP] [PORT], autosploit 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" @@ -281,7 +281,7 @@ whatweb=Run whatweb, "whatweb [IP]:[PORT] --color=never --log-brief=[OUTPUT].txt x11screen=Run x11screenshot, bash ./scripts/x11screenshot.sh [IP] 0 [OUTPUT], X11 dnsmap=Run dnsmap, "dnsmap [IP] -w ./wordlists/gvit_subdomain_wordlist.txt -r [OUTPUT]", dnsmap cloudfail=Run cloudfail, "python3 scripts/CloudFail/cloudfail.py --target [IP] --tor", cloudfail -wpscan=Run wpscan, "wpscan -v --url [IP]:[PORT]", wpscan +wpscan=Run wpscan, "ruby scripts/wpscan/bin/wpscan -v --url [IP]:[PORT]", wpscan wafw00f=Run wafw00f, "wafw00f [IP]", wafw00f autosploit=Run autosploit, "cd scripts/AutoSploit/ && python autosploit.py -e -C default [IP] [PORT]", autosploit From 1b0907aec41c19f723e5418f6f0ff65bea441488 Mon Sep 17 00:00:00 2001 From: sscottgvit Date: Wed, 1 May 2019 13:58:50 -0500 Subject: [PATCH 18/20] Bug fixes, new class types, copy paste --- app/cvemodels.py | 7 ++- app/logic.py | 119 ++++++++++++++++++++------------------- app/processmodels.py | 2 +- app/servicemodels.py | 4 +- app/settings.py | 3 - controller/controller.py | 4 +- db/database.py | 77 +++++++++++++++++-------- deps/detectPython.sh | 3 +- deps/detectScripts.sh | 12 ++-- deps/installDeps.sh | 2 +- legion.conf | 19 ++----- precommit.sh | 6 ++ ui/view.py | 43 +++++++++++++- 13 files changed, 183 insertions(+), 118 deletions(-) diff --git a/app/cvemodels.py b/app/cvemodels.py index 646246c0..05199559 100644 --- a/app/cvemodels.py +++ b/app/cvemodels.py @@ -47,7 +47,7 @@ def headerData(self, section, orientation, role): def data(self, index, role): # this method takes care of how the information is displayed - if role == QtCore.Qt.DisplayRole: # how to display each cell + if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole: # how to display each cell value = '' row = index.row() column = index.column() @@ -97,12 +97,15 @@ def sort(self, Ncol, order): self.layoutChanged.emit() def flags(self, index): # method that allows views to know how to treat each item, eg: if it should be enabled, editable, selectable etc - return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable + return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable ### getter functions ### def getCveDBIdForRow(self, row): return self.__cves[row]['name'] + + def getCveForRow(self, row): + return self.__cves[row] def getRowForDBId(self, id): for i in range(len(self.__cves)): diff --git a/app/logic.py b/app/logic.py index 07dedf04..261dc671 100644 --- a/app/logic.py +++ b/app/logic.py @@ -186,14 +186,14 @@ def saveProjectAs(self, filename, replace=0, projectType = 'legion'): return False def isHostInDB(self, host): # used we don't run tools on hosts out of scope - query = 'SELECT host.ip FROM nmap_host AS host WHERE host.ip == ? OR host.hostname == ?' + query = 'SELECT host.ip FROM hostObj AS host WHERE host.ip == ? OR host.hostname == ?' result = self.db.metadata.bind.execute(query, str(host), str(host)).fetchall() if result: return True return False def getHostsFromDB(self, filters): - query = 'SELECT * FROM nmap_host AS hosts WHERE 1=1' + query = 'SELECT * FROM hostObj AS hosts WHERE 1=1' if filters.down == False: query += ' AND hosts.status!=\'down\'' @@ -208,9 +208,9 @@ def getHostsFromDB(self, filters): # get distinct service names from DB def getServiceNamesFromDB(self, filters): - query = ('SELECT DISTINCT service.name FROM nmap_service as service ' + - 'INNER JOIN nmap_port as ports ' + - 'INNER JOIN nmap_host AS hosts ' + + query = ('SELECT DISTINCT service.name FROM serviceObj as service ' + + 'INNER JOIN portObj as ports ' + + 'INNER JOIN hostObj AS hosts ' + 'ON hosts.id = ports.host_id AND service.id=ports.service_id WHERE 1=1') if filters.down == False: @@ -243,31 +243,31 @@ def getNoteFromDB(self, hostId): # get script info for given host IP def getScriptsFromDB(self, hostIP): - query = ('SELECT host.id,host.script_id,port.port_id,port.protocol FROM nmap_script AS host ' + - 'INNER JOIN nmap_host AS hosts ON hosts.id = host.host_id ' + - 'LEFT OUTER JOIN nmap_port AS port ON port.id=host.port_id ' + - 'WHERE hosts.ip=?') + query = ('SELECT host.id, host.script_id, port.port_id, port.protocol FROM l1ScriptObj AS host ' + + 'INNER JOIN hostObj AS hosts ON hosts.id = host.host_id ' + + 'LEFT OUTER JOIN portObj AS port ON port.id = host.port_id ' + + 'WHERE hosts.ip=?') return self.db.metadata.bind.execute(query, str(hostIP)).fetchall() ## FIX def getCvesFromDB(self, hostIP): query = ('SELECT cves.name, cves.severity, cves.product, cves.version, cves.url, cves.source FROM cve AS cves ' + - 'INNER JOIN nmap_host AS hosts ON hosts.id = cves.host_id ' + - 'WHERE hosts.ip=?') + 'INNER JOIN hostObj AS hosts ON hosts.id = cves.host_id ' + + 'WHERE hosts.ip = ?') return self.db.metadata.bind.execute(query, str(hostIP)).fetchall() def getScriptOutputFromDB(self, scriptDBId): - query = ('SELECT script.output FROM nmap_script as script WHERE script.id=?') + query = ('SELECT script.output FROM l1ScriptObj as script WHERE script.id = ?') return self.db.metadata.bind.execute(query, str(scriptDBId)).fetchall() # get port and service info for given host IP def getPortsAndServicesForHostFromDB(self, hostIP, filters): - query = ('SELECT hosts.ip,ports.port_id,ports.protocol,ports.state,ports.host_id,ports.service_id,services.name,services.product,services.version,services.extrainfo,services.fingerprint FROM nmap_port AS ports ' + - 'INNER JOIN nmap_host AS hosts ON hosts.id = ports.host_id ' + - 'LEFT OUTER JOIN nmap_service AS services ON services.id=ports.service_id ' + - 'WHERE hosts.ip=?') + query = ('SELECT hosts.ip, ports.port_id, ports.protocol, ports.state, ports.host_id, ports.service_id, services.name, services.product, services.version, services.extrainfo, services.fingerprint FROM portObj AS ports ' + + 'INNER JOIN hostObj AS hosts ON hosts.id = ports.host_id ' + + 'LEFT OUTER JOIN serviceObj AS services ON services.id = ports.service_id ' + + 'WHERE hosts.ip = ?') if filters.portopen == False: query += ' AND ports.state!=\'open\' AND ports.state!=\'open|filtered\'' @@ -284,27 +284,27 @@ def getPortsAndServicesForHostFromDB(self, hostIP, filters): # used to check if there are any ports of a specific protocol for a given host def getPortsForHostFromDB(self, hostIP, protocol): - query = ('SELECT ports.port_id FROM nmap_port AS ports ' + - 'INNER JOIN nmap_host AS hosts ON hosts.id = ports.host_id ' + - 'WHERE hosts.ip=? and ports.protocol=?') + query = ('SELECT ports.port_id FROM portObj AS ports ' + + 'INNER JOIN hostObj AS hosts ON hosts.id = ports.host_id ' + + 'WHERE hosts.ip = ? and ports.protocol = ?') results = self.db.metadata.bind.execute(query, str(hostIP), str(protocol)).first() return results # used to get the service name given a host ip and a port when we are in tools tab (left) and right click on a host def getServiceNameForHostAndPort(self, hostIP, port): - query = ('SELECT services.name FROM nmap_service AS services ' + - 'INNER JOIN nmap_host AS hosts ON hosts.id = ports.host_id ' + - 'INNER JOIN nmap_port AS ports ON services.id=ports.service_id ' + - 'WHERE hosts.ip=? and ports.port_id=?') + query = ('SELECT services.name FROM serviceObj AS services ' + + 'INNER JOIN hostObj AS hosts ON hosts.id = ports.host_id ' + + 'INNER JOIN portObj AS ports ON services.id=ports.service_id ' + + 'WHERE hosts.ip=? and ports.port_id = ?') results = self.db.metadata.bind.execute(query, str(hostIP), str(port)).first() return results # used to delete all port/script data related to a host - to overwrite portscan info with the latest scan def deleteAllPortsAndScriptsForHostFromDB(self, hostID, protocol): session = self.db.session() - ports_for_host = session.query(nmap_port).filter(nmap_port.host_id == hostID).filter(nmap_port.protocol == str(protocol)).all() + ports_for_host = session.query(portObj).filter(portObj.host_id == hostID).filter(portObj.protocol == str(protocol)).all() for p in ports_for_host: - scripts_for_ports = session.query(nmap_script).filter(nmap_script.port_id == p.id).all() + scripts_for_ports = session.query(l1ScriptObj).filter(l1ScriptObj.port_id == p.id).all() for s in scripts_for_ports: session.delete(s) for p in ports_for_host: @@ -314,25 +314,25 @@ def deleteAllPortsAndScriptsForHostFromDB(self, hostID, protocol): def getHostInformation(self, hostIP): session = self.db.session() - results = session.query(nmap_host).filter_by(ip=str(hostIP)).first() + results = session.query(hostObj).filter_by(ip=str(hostIP)).first() return results def deleteHost(self, hostIP): session = self.db.session() - h = session.query(nmap_host).filter_by(ip=str(hostIP)).first() + h = session.query(hostObj).filter_by(ip=str(hostIP)).first() session.delete(h) session.commit() return def getPortStatesForHost(self, hostID): - query = ('SELECT port.state FROM nmap_port as port WHERE port.host_id=?') + query = ('SELECT port.state FROM portObj as port WHERE port.host_id = ?') results = self.db.metadata.bind.execute(query, str(hostID)).fetchall() return results def getHostsAndPortsForServiceFromDB(self, serviceName, filters): - query = ('SELECT hosts.ip,ports.port_id,ports.protocol,ports.state,ports.host_id,ports.service_id,services.name,services.product,services.version,services.extrainfo,services.fingerprint FROM nmap_port AS ports ' + - 'INNER JOIN nmap_host AS hosts ON hosts.id = ports.host_id ' + - 'LEFT OUTER JOIN nmap_service AS services ON services.id=ports.service_id ' + + query = ('SELECT hosts.ip,ports.port_id,ports.protocol,ports.state,ports.host_id,ports.service_id,services.name,services.product,services.version,services.extrainfo,services.fingerprint FROM portObj AS ports ' + + 'INNER JOIN hostObj AS hosts ON hosts.id = ports.host_id ' + + 'LEFT OUTER JOIN serviceObj AS services ON services.id=ports.service_id ' + 'WHERE services.name=?') if filters.down == False: @@ -404,7 +404,7 @@ def getPidForProcess(self, procid): def toggleHostCheckStatus(self, ipaddr): session = self.db.session() - h = session.query(nmap_host).filter_by(ip=ipaddr).first() + h = session.query(hostObj).filter_by(ip=ipaddr).first() if h: if h.checked == 'False': h.checked = 'True' @@ -671,10 +671,10 @@ def run(self): # it is nece createPortsProgress = 0 for h in parser.all_hosts(): # create all the hosts that need to be created - db_host = session.query(nmap_host).filter_by(ip=h.ip).first() + db_host = session.query(hostObj).filter_by(ip=h.ip).first() if not db_host: # if host doesn't exist in DB, create it first - hid = nmap_host(os_match='', os_accuracy='', ip=h.ip, ipv4=h.ipv4, ipv6=h.ipv6, macaddr=h.macaddr, status=h.status, hostname=h.hostname, vendor=h.vendor, uptime=h.uptime, lastboot=h.lastboot, distance=h.distance, state=h.state, count=h.count) + hid = hostObj(os_match='', os_accuracy='', ip=h.ip, ipv4=h.ipv4, ipv6=h.ipv6, macaddr=h.macaddr, status=h.status, hostname=h.hostname, vendor=h.vendor, uptime=h.uptime, lastboot=h.lastboot, distance=h.distance, state=h.state, count=h.count) self.tsLog("Adding db_host") session.add(hid) t_note = note(h.ip, 'Added by nmap') @@ -692,7 +692,7 @@ def run(self): # it is nece for h in parser.all_hosts(): # create all OS, service and port objects that need to be created self.tsLog("Processing h {ip}".format(ip=h.ip)) - db_host = session.query(nmap_host).filter_by(ip=h.ip).first() + db_host = session.query(hostObj).filter_by(ip=h.ip).first() if db_host: self.tsLog("Found db_host during os/ports/service processing") else: @@ -702,11 +702,11 @@ def run(self): # it is nece self.tsLog(" 'os_nodes' to process: {os_nodes}".format(os_nodes=str(len(os_nodes)))) for os in os_nodes: self.tsLog(" Processing os obj {os}".format(os=str(os.name))) - db_os = session.query(nmap_os).filter_by(host_id=db_host.id).filter_by(name=os.name).filter_by(family=os.family).filter_by(generation=os.generation).filter_by(os_type=os.os_type).filter_by(vendor=os.vendor).first() + db_os = session.query(osObj).filter_by(host_id=db_host.id).filter_by(name=os.name).filter_by(family=os.family).filter_by(generation=os.generation).filter_by(os_type=os.os_type).filter_by(vendor=os.vendor).first() if not db_os: - t_nmap_os = nmap_os(os.name, os.family, os.generation, os.os_type, os.vendor, os.accuracy, db_host.id) - session.add(t_nmap_os) + t_osObj = osObj(os.name, os.family, os.generation, os.os_type, os.vendor, os.accuracy, db_host.id) + session.add(t_osObj) createOsNodesProgress = createOsNodesProgress + ((100.0 / hostCount) / 5) totalprogress = totalprogress + createOsNodesProgress @@ -723,11 +723,11 @@ def run(self): # it is nece if not (s is None): # check if service already exists to avoid adding duplicates #print(" Found service {service} for port {port}".format(service=str(s.name),port=str(p.portId))) - #db_service = session.query(nmap_service).filter_by(name=s.name).filter_by(product=s.product).filter_by(version=s.version).filter_by(extrainfo=s.extrainfo).filter_by(fingerprint=s.fingerprint).first() - db_service = session.query(nmap_service).filter_by(name=s.name).first() + #db_service = session.query(serviceObj).filter_by(name=s.name).filter_by(product=s.product).filter_by(version=s.version).filter_by(extrainfo=s.extrainfo).filter_by(fingerprint=s.fingerprint).first() + db_service = session.query(serviceObj).filter_by(name=s.name).first() if not db_service: #print("Did not find service *********** name={0} prod={1} ver={2} extra={3} fing={4}".format(s.name, s.product, s.version, s.extrainfo, s.fingerprint)) - db_service = nmap_service(s.name, s.product, s.version, s.extrainfo, s.fingerprint) + db_service = serviceObj(s.name, s.product, s.version, s.extrainfo, s.fingerprint) session.add(db_service) # else: #print("FOUND service *************** name={0}".format(db_service.name)) @@ -735,14 +735,14 @@ def run(self): # it is nece else: # else, there is no service info to parse db_service = None # fetch the port - db_port = session.query(nmap_port).filter_by(host_id=db_host.id).filter_by(port_id=p.portId).filter_by(protocol=p.protocol).first() + db_port = session.query(portObj).filter_by(host_id=db_host.id).filter_by(port_id=p.portId).filter_by(protocol=p.protocol).first() if not db_port: #print("Did not find port *********** portid={0} proto={1}".format(p.portId, p.protocol)) if db_service: - db_port = nmap_port(p.portId, p.protocol, p.state, db_host.id, db_service.id) + db_port = portObj(p.portId, p.protocol, p.state, db_host.id, db_service.id) else: - db_port = nmap_port(p.portId, p.protocol, p.state, db_host.id, '') + db_port = portObj(p.portId, p.protocol, p.state, db_host.id, '') session.add(db_port) #else: #print('FOUND port *************** portid={0}'.format(db_port.port_id)) @@ -758,34 +758,35 @@ def run(self): # it is nece for h in parser.all_hosts(): # create all script objects that need to be created - db_host = session.query(nmap_host).filter_by(ip=h.ip).first() + db_host = session.query(hostObj).filter_by(ip=h.ip).first() for p in h.all_ports(): for scr in p.get_scripts(): self.tsLog(" Processing script obj {scr}".format(scr=str(scr))) - db_port = session.query(nmap_port).filter_by(host_id=db_host.id).filter_by(port_id=p.portId).filter_by(protocol=p.protocol).first() - db_script = session.query(nmap_script).filter_by(script_id=scr.scriptId).filter_by(port_id=db_port.id).first() + print(" Processing script obj {scr}".format(scr=str(scr))) + db_port = session.query(portObj).filter_by(host_id=db_host.id).filter_by(port_id=p.portId).filter_by(protocol=p.protocol).first() + db_script = session.query(l1ScriptObj).filter_by(script_id=scr.scriptId).filter_by(port_id=db_port.id).first() cveResults = scr.get_cves() for cveEntry in cveResults: t_cve = cve(name = cveEntry.name, url = cveEntry.url, source = cveEntry.source, severity = cveEntry.severity, product = cveEntry.product, version = cveEntry.version, hostId = db_host.id) session.add(t_cve) if not db_script: # if this script object doesn't exist, create it - t_nmap_script = nmap_script(scr.scriptId, scr.output, db_port.id, db_host.id) - self.tsLog(" Adding nmap_script obj {script}".format(script=scr.scriptId)) - session.add(t_nmap_script) + t_l1ScriptObj = l1ScriptObj(scr.scriptId, scr.output, db_port.id, db_host.id) + self.tsLog(" Adding l1ScriptObj obj {script}".format(script=scr.scriptId)) + session.add(t_l1ScriptObj) for hs in h.get_hostscripts(): - db_script = session.query(nmap_script).filter_by(script_id=hs.scriptId).filter_by(host_id=db_host.id).first() + db_script = session.query(l1ScriptObj).filter_by(script_id=hs.scriptId).filter_by(host_id=db_host.id).first() if not db_script: - t_nmap_script = nmap_script(hs.scriptId, hs.output, None, db_host.id) - session.add(t_nmap_script) + t_l1ScriptObj = l1ScriptObj(hs.scriptId, hs.output, None, db_host.id) + session.add(t_l1ScriptObj) session.commit() for h in parser.all_hosts(): # update everything - db_host = session.query(nmap_host).filter_by(ip=h.ip).first() + db_host = session.query(hostObj).filter_by(ip=h.ip).first() if db_host.ipv4 == '' and not h.ipv4 == '': db_host.ipv4 = h.ipv4 @@ -817,7 +818,7 @@ def run(self): # it is nece os_nodes = h.get_OS() for os in os_nodes: - db_os = session.query(nmap_os).filter_by(host_id=db_host.id).filter_by(name=os.name).filter_by(family=os.family).filter_by(generation=os.generation).filter_by(os_type=os.os_type).filter_by(vendor=os.vendor).first() + db_os = session.query(osObj).filter_by(host_id=db_host.id).filter_by(name=os.name).filter_by(family=os.family).filter_by(generation=os.generation).filter_by(os_type=os.os_type).filter_by(vendor=os.vendor).first() db_os.os_accuracy = os.accuracy # update the accuracy @@ -837,12 +838,12 @@ def run(self): # it is nece for p in h.all_ports(): s = p.get_service() if not (s is None): - #db_service = session.query(nmap_service).filter_by(name=s.name).filter_by(product=s.product).filter_by(version=s.version).filter_by(extrainfo=s.extrainfo).filter_by(fingerprint=s.fingerprint).first() - db_service = session.query(nmap_service).filter_by(name=s.name).first() + #db_service = session.query(serviceObj).filter_by(name=s.name).filter_by(product=s.product).filter_by(version=s.version).filter_by(extrainfo=s.extrainfo).filter_by(fingerprint=s.fingerprint).first() + db_service = session.query(serviceObj).filter_by(name=s.name).first() else: db_service = None # fetch the port - db_port = session.query(nmap_port).filter_by(host_id=db_host.id).filter_by(port_id=p.portId).filter_by(protocol=p.protocol).first() + db_port = session.query(portObj).filter_by(host_id=db_host.id).filter_by(port_id=p.portId).filter_by(protocol=p.protocol).first() if db_port: #print("************************ Found {0}".format(db_port)) @@ -855,7 +856,7 @@ def run(self): # it is nece session.add(db_port) for scr in p.get_scripts(): # store the script results (note that existing script outputs are also kept) - db_script = session.query(nmap_script).filter_by(script_id=scr.scriptId).filter_by(port_id=db_port.id).first() + db_script = session.query(l1ScriptObj).filter_by(script_id=scr.scriptId).filter_by(port_id=db_port.id).first() if not scr.output == '' and scr.output is not None: db_script.output = scr.output diff --git a/app/processmodels.py b/app/processmodels.py index 63ef3637..9e86992a 100644 --- a/app/processmodels.py +++ b/app/processmodels.py @@ -134,7 +134,7 @@ def sort(self, Ncol, order): pass def flags(self, index): # method that allows views to know how to treat each item, eg: if it should be enabled, editable, selectable etc - return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable + return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable def setDataList(self, processes): self.__processes = processes diff --git a/app/servicemodels.py b/app/servicemodels.py index df7d66b7..5d9225d5 100644 --- a/app/servicemodels.py +++ b/app/servicemodels.py @@ -93,7 +93,7 @@ def data(self, index, role): # this metho return value def flags(self, index): # method that allows views to know how to treat each item, eg: if it should be enabled, editable, selectable etc - return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable + return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable def sort(self, Ncol, order): # sort function called when the user clicks on a header self.layoutAboutToBeChanged.emit() @@ -195,7 +195,7 @@ def data(self, index, role): # This metho return self.__serviceNames[row]['name'] def flags(self, index): # method that allows views to know how to treat each item, eg: if it should be enabled, editable, selectable etc - return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable + return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable def sort(self, Ncol, order): # sort function called when the user clicks on a header diff --git a/app/settings.py b/app/settings.py index dafdff9a..2bb98378 100644 --- a/app/settings.py +++ b/app/settings.py @@ -165,7 +165,6 @@ def backupAndSave(self, newSettings, saveBackup = True): self.actions.setValue('hydra-path', newSettings.tools_path_hydra) self.actions.setValue('cutycapt-path', newSettings.tools_path_cutycapt) self.actions.setValue('texteditor-path', newSettings.tools_path_texteditor) - self.actions.setValue('python-path', newSettings.tools_path_python) self.actions.endGroup() self.actions.beginGroup('StagedNmapSettings') @@ -239,7 +238,6 @@ def __init__(self, appSettings=None): self.tools_path_hydra = "/usr/bin/hydra" self.tools_path_cutycapt = "/usr/bin/cutycapt" self.tools_path_texteditor = "/usr/bin/leafpad" - self.tools_path_python = os.environ["PYTHON3BIN"] # GUI settings self.gui_process_tab_column_widths = "125,0,100,150,100,100,100,100,100,100,100,100,100,100,100,100,100" @@ -296,7 +294,6 @@ def __init__(self, appSettings=None): self.tools_path_hydra = self.toolSettings['hydra-path'] self.tools_path_cutycapt = self.toolSettings['cutycapt-path'] self.tools_path_texteditor = self.toolSettings['texteditor-path'] - self.tools_path_python = self.toolSettings['python-path'] # gui self.gui_process_tab_column_widths = self.guiSettings['process-tab-column-widths'] diff --git a/controller/controller.py b/controller/controller.py index 4b57d4c5..f1de0925 100644 --- a/controller/controller.py +++ b/controller/controller.py @@ -28,13 +28,13 @@ class Controller(): def __init__(self, view, logic): self.name = "LEGION" self.version = '0.3.4' - self.build = '1555077770' + self.build = '1556736984' self.author = 'GoVanguard' self.copyright = '2019' self.links = ['http://github.com/GoVanguard/legion/issues', 'https://GoVanguard.io/legion'] self.emails = [] - self.update = '04/12/2019' + self.update = '05/01/2019' self.license = "GPL v3" self.desc = "Legion is a fork of SECFORCE's Sparta, Legion is an open source, easy-to-use, \nsuper-extensible and semi-automated network penetration testing tool that aids in discovery, \nreconnaissance and exploitation of information systems." diff --git a/db/database.py b/db/database.py index 82a051dd..8db4c2c3 100644 --- a/db/database.py +++ b/db/database.py @@ -90,8 +90,8 @@ def __init__(self, filename, *args, **kwargs): self.down_hosts = kwargs.get('down_hosts') or '0' -class nmap_os(Base): - __tablename__ = 'nmap_os' +class osObj(Base): + __tablename__ = 'osObj' id = Column(Integer, primary_key = True) name = Column(String) family = Column(String) @@ -99,7 +99,7 @@ class nmap_os(Base): os_type = Column(String) vendor = Column(String) accuracy = Column(String) - host_id = Column(String, ForeignKey('nmap_host.id')) + host_id = Column(String, ForeignKey('hostObj.id')) def __init__(self, name, *args): self.name = name @@ -110,15 +110,15 @@ def __init__(self, name, *args): self.accuracy = args[4] self.host_id = args[5] -class nmap_port(Base): - __tablename__ = 'nmap_port' +class portObj(Base): + __tablename__ = 'portObj' port_id = Column(String) id = Column(Integer, primary_key = True) protocol = Column(String) state = Column(String) - host_id = Column(String, ForeignKey('nmap_host.id')) - service_id = Column(String, ForeignKey('nmap_service.id')) - script_id = Column(String, ForeignKey('nmap_script.id')) + host_id = Column(String, ForeignKey('hostObj.id')) + service_id = Column(String, ForeignKey('serviceObj.id')) + script_id = Column(String, ForeignKey('l1ScriptObj.id')) def __init__(self, port_id, protocol, state, host, service = ''): self.port_id = port_id @@ -136,8 +136,8 @@ class cve(Base): severity = Column(String) source = Column(String) version = Column(String) - service_id = Column(String, ForeignKey('nmap_service.id')) - host_id = Column(String, ForeignKey('nmap_host.id')) + service_id = Column(String, ForeignKey('serviceObj.id')) + host_id = Column(String, ForeignKey('hostObj.id')) def __init__(self, name, url, product, hostId, severity = '', source = '', version = ''): self.url = url @@ -148,15 +148,15 @@ def __init__(self, name, url, product, hostId, severity = '', source = '', versi self.version = version self.host_id = hostId -class nmap_service(Base): - __tablename__ = 'nmap_service' +class serviceObj(Base): + __tablename__ = 'serviceObj' name = Column(String) id = Column(Integer, primary_key = True) product = Column(String) version = Column(String) extrainfo = Column(String) fingerprint = Column(String) - port = relationship(nmap_port) + port = relationship(portObj) cves = relationship(cve) def __init__(self, name = '', product = '', version = '', extrainfo = '', fingerprint = ''): @@ -166,13 +166,13 @@ def __init__(self, name = '', product = '', version = '', extrainfo = '', finger self.extrainfo = extrainfo self.fingerprint = fingerprint -class nmap_script(Base): - __tablename__ = 'nmap_script' +class l1ScriptObj(Base): + __tablename__ = 'l1ScriptObj' script_id = Column(String) id = Column(Integer, primary_key = True) output = Column(String) - port_id = Column(String, ForeignKey('nmap_port.id')) - host_id = Column(String, ForeignKey('nmap_host.id')) + port_id = Column(String, ForeignKey('portObj.id')) + host_id = Column(String, ForeignKey('hostObj.id')) def __init__(self, script_id, output, portId, hostId): self.script_id = script_id @@ -180,8 +180,41 @@ def __init__(self, script_id, output, portId, hostId): self.port_id = portId self.host_id = hostId -class nmap_host(Base): - __tablename__ = 'nmap_host' +class l2ScriptObj(Base): + __tablename__ = 'l2ScriptObj' + script_id = Column(String) + id = Column(Integer, primary_key = True) + output = Column(String) + port_id = Column(String, ForeignKey('portObj.id')) + host_id = Column(String, ForeignKey('hostObj.id')) + + def __init__(self, script_id, output, portId, hostId): + self.script_id = script_id + self.output = unicode(output) + self.port_id = portId + self.host_id = hostId + +class appObj(Base): + __tablename__ = 'appObj' + name = Column(String) + id = Column(Integer, primary_key = True) + product = Column(String) + version = Column(String) + extrainfo = Column(String) + fingerprint = Column(String) + cpe = Column(String) + service = relationship(serviceObj) + + def __init__(self, name = '', product = '', version = '', extrainfo = '', fingerprint = '', cpe = ''): + self.name = name + self.product = product + self.version = version + self.extrainfo = extrainfo + self.fingerprint = fingerprint + self.cpe - cpe + +class hostObj(Base): + __tablename__ = 'hostObj' checked = Column(String) os_match = Column(String) os_accuracy = Column(String) @@ -201,8 +234,8 @@ class nmap_host(Base): count = Column(String) # host relationships - os = relationship(nmap_os) - ports = relationship(nmap_port) + os = relationship(osObj) + ports = relationship(portObj) cves = relationship(cve) def __init__(self, **kwargs): @@ -226,7 +259,7 @@ def __init__(self, **kwargs): class note(Base): __tablename__ = 'note' - host_id = Column(Integer, ForeignKey('nmap_host.id')) + host_id = Column(Integer, ForeignKey('hostObj.id')) id = Column(Integer, primary_key = True) text = Column(String) diff --git a/deps/detectPython.sh b/deps/detectPython.sh index f3e3714b..ff559847 100644 --- a/deps/detectPython.sh +++ b/deps/detectPython.sh @@ -241,6 +241,5 @@ fi echo "Python 3 bin is ${pythonBin} ($(which ${pythonBin}))" echo "Pip 3 bin is ${pipBin} ($(which ${pipBin}))" -PYTHON3BIN=${pythonBin} -export PYTHON3BIN +export PYTHON3BIN=$(which ${pythonBin}) export PIP3BIN=$(which ${pipBin}) diff --git a/deps/detectScripts.sh b/deps/detectScripts.sh index 209449f0..8eb55424 100644 --- a/deps/detectScripts.sh +++ b/deps/detectScripts.sh @@ -66,18 +66,16 @@ else git clone https://github.com/m0rtem/CloudFail.git scripts/CloudFail fi -if [ -a scripts/AutoSploit/autosploit.py ] +if [ -a scripts/exploutdb/searchsploit ] then - echo "AutoSploit is already installed" + echo "Exploit-db has been found" else - git clone https://github.com/NullArray/AutoSploit.git scripts/AutoSploit + git clone https://github.com/offensive-security/exploitdb.git scripts/exploitdb fi -if [ -d "scripts/wpscan" ] +if [ ! -f ".initialized" ] then - echo "wpscan is already installed" -else - git clone https://github.com/wpscanteam/wpscan.git scripts/wpscan + scripts/installDeps.sh fi if [ ! -f ".initialized" ] diff --git a/deps/installDeps.sh b/deps/installDeps.sh index b0214051..dc9cfcc5 100644 --- a/deps/installDeps.sh +++ b/deps/installDeps.sh @@ -9,4 +9,4 @@ source ./deps/apt.sh apt-get update -m echo "Installing deps..." -DEBIAN_FRONTEND="noninteractive" apt-get -yqqq --allow-unauthenticated --force-yes -o DPkg::Options::="--force-overwrite" -o DPkg::Options::="--force-confdef" install nmap finger hydra nikto whatweb nbtscan nfs-common rpcbind smbclient sra-toolkit ldap-utils sslscan rwho medusa x11-apps cutycapt leafpad xvfb imagemagick eog hping3 sqlmap wapiti libqt5core5a python-pip python-impacket ruby perl urlscan dnsmap wafw00f git +DEBIAN_FRONTEND="noninteractive" apt-get -yqqq --allow-unauthenticated --force-yes -o DPkg::Options::="--force-overwrite" -o DPkg::Options::="--force-confdef" install nmap finger hydra nikto whatweb nbtscan nfs-common rpcbind smbclient sra-toolkit ldap-utils sslscan rwho medusa x11-apps cutycapt leafpad xvfb imagemagick eog hping3 sqlmap wapiti libqt5core5a python-pip python-impacket ruby perl dnsmap urlscan git diff --git a/legion.conf b/legion.conf index af4417da..25879639 100644 --- a/legion.conf +++ b/legion.conf @@ -9,7 +9,7 @@ store-cleartext-passwords-on-exit=True username-wordlist-path=/usr/share/wordlists/ [GUISettings] -process-tab-column-widths="125,0,74,92,67,0,124,130,0,0,0,0,0,0,0,554,100" +process-tab-column-widths="125,0,74,92,67,0,124,130,0,0,0,0,0,0,0,544,100" process-tab-detail=False [GeneralSettings] @@ -41,10 +41,7 @@ citrix-enum-apps-xml.nse=citrix-enum-apps-xml.nse, "nmap -Pn [IP] -p [PORT] --sc citrix-enum-apps.nse=citrix-enum-apps.nse, "nmap -Pn [IP] -p [PORT] --script=citrix-enum-apps.nse --script-args=unsafe=1", citrix citrix-enum-servers-xml.nse=citrix-enum-servers-xml.nse, "nmap -Pn [IP] -p [PORT] --script=citrix-enum-servers-xml.nse --script-args=unsafe=1", citrix citrix-enum-servers.nse=citrix-enum-servers.nse, "nmap -Pn [IP] -p [PORT] --script=citrix-enum-servers.nse --script-args=unsafe=1", citrix -cloudfail=Run cloudfail, python3 scripts/CloudFail/cloudfail.py --target [IP] --tor, cloudfail -wpscan=Run wpscan, ruby scripts/wpscan/bin/wpscan -v --url [IP]:[PORT], wpscan -wafw00f=Run wafw00f, wafw00f [IP], wafw00f -autosploit=Run autosploit, cd scripts/AutoSploit/ && python autosploit.py -e -C default [IP] [PORT], autosploit +cloudfail=Run cloudfail, python3.7 scripts/CloudFail/cloudfail.py --target [IP] --tor, cloudfail 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" dnsmap=Run dnsmap, dnsmap [IP] -w ./wordlists/gvit_subdomain_wordlist.txt -r [OUTPUT], dnsmap enum4linux=Run enum4linux, enum4linux [IP], "netbios-ssn,microsoft-ds" @@ -215,7 +212,7 @@ riak-http-info.nse=riak-http-info.nse, "nmap -Pn [IP] -p [PORT] --script=riak-ht rpcinfo=Run rpcinfo, rpcinfo -p [IP], rpcbind rwho=Run rwho, rwho -a [IP], who samba-vuln-cve-2012-1182.nse=samba-vuln-cve-2012-1182.nse, "nmap -Pn [IP] -p [PORT] --script=samba-vuln-cve-2012-1182.nse --script-args=unsafe=1", samba -samrdump=Run samrdump, python3 /usr/share/doc/python-impacket-doc/examples/samrdump.py [IP] [PORT]/SMB, "netbios-ssn,microsoft-ds" +samrdump=Run samrdump, python /usr/share/doc/python-impacket-doc/examples/samrdump.py [IP] [PORT]/SMB, "netbios-ssn,microsoft-ds" showmount=Show nfs shares, showmount -e [IP], nfs smb-brute.nse=smb-brute.nse, "nmap -Pn [IP] -p [PORT] --script=smb-brute.nse --script-args=unsafe=1", smb smb-check-vulns.nse=smb-check-vulns.nse, "nmap -Pn [IP] -p [PORT] --script=smb-check-vulns.nse --script-args=unsafe=1", smb @@ -259,7 +256,7 @@ smtp-vuln-cve2011-1720.nse=smtp-vuln-cve2011-1720.nse, "nmap -Pn [IP] -p [PORT] smtp-vuln-cve2011-1764.nse=smtp-vuln-cve2011-1764.nse, "nmap -Pn [IP] -p [PORT] --script=smtp-vuln-cve2011-1764.nse --script-args=unsafe=1", smtp snmp-brute=Bruteforce community strings (medusa), bash -c \"medusa -h [IP] -u root -P ./wordlists/snmp-default.txt -M snmp | grep SUCCESS\", "snmp,snmptrap" snmp-brute.nse=snmp-brute.nse, "nmap -Pn [IP] -p [PORT] --script=snmp-brute.nse --script-args=unsafe=1", snmp -snmp-default=Check for default community strings, python3 ./scripts/snmpbrute.py -t [IP] -p [PORT] -f ./wordlists/snmp-default.txt -b --no-colours, "snmp,snmptrap" +snmp-default=Check for default community strings, python ./scripts/snmpbrute.py -t [IP] -p [PORT] -f ./wordlists/snmp-default.txt -b --no-colours, "snmp,snmptrap" snmp-hh3c-logins.nse=snmp-hh3c-logins.nse, "nmap -Pn [IP] -p [PORT] --script=snmp-hh3c-logins.nse --script-args=unsafe=1", snmp snmp-interfaces.nse=snmp-interfaces.nse, "nmap -Pn [IP] -p [PORT] --script=snmp-interfaces.nse --script-args=unsafe=1", snmp snmp-ios-config.nse=snmp-ios-config.nse, "nmap -Pn [IP] -p [PORT] --script=snmp-ios-config.nse --script-args=unsafe=1", snmp @@ -279,16 +276,11 @@ vnc-info.nse=vnc-info.nse, "nmap -Pn [IP] -p [PORT] --script=vnc-info.nse --scri webslayer=Launch webslayer, webslayer, "http,https,ssl,soap,http-proxy,http-alt" whatweb=Run whatweb, "whatweb [IP]:[PORT] --color=never --log-brief=[OUTPUT].txt", "http,https,ssl,soap,http-proxy,http-alt" x11screen=Run x11screenshot, bash ./scripts/x11screenshot.sh [IP] 0 [OUTPUT], X11 -dnsmap=Run dnsmap, "dnsmap [IP] -w ./wordlists/gvit_subdomain_wordlist.txt -r [OUTPUT]", dnsmap -cloudfail=Run cloudfail, "python3 scripts/CloudFail/cloudfail.py --target [IP] --tor", cloudfail -wpscan=Run wpscan, "ruby scripts/wpscan/bin/wpscan -v --url [IP]:[PORT]", wpscan -wafw00f=Run wafw00f, "wafw00f [IP]", wafw00f -autosploit=Run autosploit, "cd scripts/AutoSploit/ && python autosploit.py -e -C default [IP] [PORT]", autosploit [PortTerminalActions] firefox=Open with firefox, firefox [IP]:[PORT], ftp=Open with ftp client, ftp [IP] [PORT], ftp -mssql=Open with mssql client (as sa), python3 /usr/share/doc/python-impacket-doc/examples/mssqlclient.py -p [PORT] sa@[IP], "mys-sql-s,codasrv-se" +mssql=Open with mssql client (as sa), python /usr/share/doc/python-impacket-doc/examples/mssqlclient.py -p [PORT] sa@[IP], "mys-sql-s,codasrv-se" mysql=Open with mysql client (as root), "mysql -u root -h [IP] --port=[PORT] -p", mysql netcat=Open with netcat, nc -v [IP] [PORT], psql=Open with postgres client (as postgres), psql -h [IP] -p [PORT] -U postgres, postgres @@ -326,4 +318,3 @@ cutycapt-path=/usr/bin/cutycapt hydra-path=/usr/bin/hydra nmap-path=/usr/bin/nmap texteditor-path=/usr/bin/leafpad -python-path=/usr/bin/python3 diff --git a/precommit.sh b/precommit.sh index 8dfd55fa..e39c694d 100644 --- a/precommit.sh +++ b/precommit.sh @@ -20,3 +20,9 @@ rm -Rf ./tmp/* # Clear all pyc and pyc find . -name \*.pyc -delete find . -name \*.pyo -delete + +# Remove cloned scripts +rm -Rf ./scripts/CloudFail/ + +# Removed backups +rm -Rf ./backups/* diff --git a/ui/view.py b/ui/view.py index ff6c4783..eb9bb44d 100644 --- a/ui/view.py +++ b/ui/view.py @@ -32,6 +32,7 @@ from app.auxiliary import * import time #temp from six import u as unicode +import pandas as pd # this class handles everything gui-related class View(QtCore.QObject): @@ -505,6 +506,7 @@ def connectHostTableClick(self): def hostTableClick(self): if self.ui.HostsTableView.selectionModel().selectedRows(): # get the IP address of the selected host (if any) row = self.ui.HostsTableView.selectionModel().selectedRows()[len(self.ui.HostsTableView.selectionModel().selectedRows())-1].row() + print(row) ip = self.HostsTableModel.getHostIPForRow(row) self.ip_clicked = ip save = self.ui.ServicesTabWidget.currentIndex() @@ -524,6 +526,7 @@ def connectServiceNamesTableClick(self): def serviceNamesTableClick(self): if self.ui.ServiceNamesTableView.selectionModel().selectedRows(): row = self.ui.ServiceNamesTableView.selectionModel().selectedRows()[len(self.ui.ServiceNamesTableView.selectionModel().selectedRows())-1].row() + print(row) self.service_clicked = self.ServiceNamesTableModel.getServiceNameForRow(row) self.updatePortsByServiceTableView(self.service_clicked) @@ -535,6 +538,7 @@ def connectToolsTableClick(self): def toolsTableClick(self): if self.ui.ToolsTableView.selectionModel().selectedRows(): row = self.ui.ToolsTableView.selectionModel().selectedRows()[len(self.ui.ToolsTableView.selectionModel().selectedRows())-1].row() + print(row) self.tool_clicked = self.ToolsTableModel.getToolNameForRow(row) self.updateToolHostsTableView(self.tool_clicked) self.displayScreenshots(self.tool_clicked == 'screenshooter') # if we clicked on the screenshooter we need to display the screenshot widget @@ -553,6 +557,7 @@ def connectScriptTableClick(self): def scriptTableClick(self): if self.ui.ScriptsTableView.selectionModel().selectedRows(): row = self.ui.ScriptsTableView.selectionModel().selectedRows()[len(self.ui.ScriptsTableView.selectionModel().selectedRows())-1].row() + print(row) self.script_clicked = self.ScriptsTableModel.getScriptDBIdForRow(row) self.updateScriptsOutputView(self.script_clicked) @@ -565,6 +570,7 @@ def connectToolHostsClick(self): def toolHostsClick(self): if self.ui.ToolHostsTableView.selectionModel().selectedRows(): row = self.ui.ToolHostsTableView.selectionModel().selectedRows()[len(self.ui.ToolHostsTableView.selectionModel().selectedRows())-1].row() + print(row) self.tool_host_clicked = self.ToolHostsTableModel.getProcessIdForRow(row) ip = self.ToolHostsTableModel.getIpForRow(row) @@ -614,17 +620,47 @@ def updateFilterKeywords(self): def connectTableDoubleClick(self): self.ui.ServicesTableView.doubleClicked.connect(self.tableDoubleClick) self.ui.ToolHostsTableView.doubleClicked.connect(self.tableDoubleClick) + self.ui.CvesTableView.doubleClicked.connect(self.rightTableDoubleClick) + + def rightTableDoubleClick(self, signal): + row = signal.row() # RETRIEVES ROW OF CELL THAT WAS DOUBLE CLICKED + column = signal.column() # RETRIEVES COLUMN OF CELL THAT WAS DOUBLE CLICKED + model = self.CvesTableModel + cell_dict = model.itemData(signal) # RETURNS DICT VALUE OF SIGNAL + cell_value = cell_dict.get(0) # RETRIEVE VALUE FROM DICT + + index = signal.sibling(row, 0) + index_dict = model.itemData(index) + index_value = index_dict.get(0) + print( + 'Row {}, Column {} clicked - value: {}\nColumn 1 contents: {}'.format(row, column, cell_value, index_value)) + df=pd.DataFrame([cell_value]) + df.to_clipboard(index=False,header=False) + + #def rightTableDoubleClick(self): + # tab = self.ui.ServicesTabWidget.tabText(self.ui.ServicesTabWidget.currentIndex()) + # print(tab) + # + # if tab == 'CVEs': + # row = self.ui.CvesTableView.selectionModel().selectedRows()[len(self.ui.CvesTableView.selectionModel().selectedRows())-1].row() + # selectedRowData = self.CvesTableModel.getCveForRow(row) + # print(row) + # print(selectedRowData) + # column = self.ui.CvesTableView.selectionModel().selectedColumns()[len(self.ui.CvesTableView.selectionModel().selectedRows())-1].column() + # print(column) + # + # else: + # return def tableDoubleClick(self): tab = self.ui.HostsTabWidget.tabText(self.ui.HostsTabWidget.currentIndex()) + print(tab) if tab == 'Services': row = self.ui.ServicesTableView.selectionModel().selectedRows()[len(self.ui.ServicesTableView.selectionModel().selectedRows())-1].row() - ## Missing ip = self.PortsByServiceTableModel.getIpForRow(row) elif tab == 'Tools': row = self.ui.ToolHostsTableView.selectionModel().selectedRows()[len(self.ui.ToolHostsTableView.selectionModel().selectedRows())-1].row() - ## Missing ip = self.ToolHostsTableModel.getIpForRow(row) else: return @@ -670,7 +706,7 @@ def switchTabClick(self): self.updateServiceNamesTableView() self.serviceNamesTableClick() - #elif selectedTab == 'CVEs': + #elif selectedTab == 'CVEs': # self.ui.ServicesTabWidget.setCurrentIndex(0) # self.removeToolTabs(0) # remove the tool tabs # self.controller.saveProject(self.lastHostIdClicked, self.ui.NotesTextEdit.toPlainText()) @@ -1064,6 +1100,7 @@ def updateScriptsView(self, hostIP): def updateCvesByHostView(self, hostIP): headers = ["ID", "CVSS Score", "Product", "Version", "URL", "Source"] cves = self.controller.getCvesFromDB(hostIP) + print(cves) self.CvesTableModel = CvesTableModel(self,self.controller.getCvesFromDB(hostIP), headers) self.ui.CvesTableView.horizontalHeader().resizeSection(0,175) From 24bed8c1c94eaab289e04a7b4575ec67e076760f Mon Sep 17 00:00:00 2001 From: sscottgvit Date: Sun, 5 May 2019 19:10:54 -0500 Subject: [PATCH 19/20] Bugfixes, New types --- app/logic.py | 4 +- app/processmodels.py | 82 ++++++++++++++++++++-------------------- controller/controller.py | 4 +- db/database.py | 44 ++++++++++++--------- legion.conf | 2 +- parsers/Script.py | 17 +++++++++ requirements.txt | 1 + ui/view.py | 11 ++++-- 8 files changed, 95 insertions(+), 70 deletions(-) diff --git a/app/logic.py b/app/logic.py index 261dc671..6eae38cb 100644 --- a/app/logic.py +++ b/app/logic.py @@ -250,12 +250,10 @@ def getScriptsFromDB(self, hostIP): return self.db.metadata.bind.execute(query, str(hostIP)).fetchall() - ## FIX def getCvesFromDB(self, hostIP): - query = ('SELECT cves.name, cves.severity, cves.product, cves.version, cves.url, cves.source FROM cve AS cves ' + + query = ('SELECT cves.name, cves.severity, cves.product, cves.version, cves.url, cves.source, cves.edbid, cves.exploit, cves.exploiturl FROM cve AS cves ' + 'INNER JOIN hostObj AS hosts ON hosts.id = cves.host_id ' + 'WHERE hosts.ip = ?') - return self.db.metadata.bind.execute(query, str(hostIP)).fetchall() def getScriptOutputFromDB(self, scriptDBId): diff --git a/app/processmodels.py b/app/processmodels.py index 9e86992a..12346e80 100644 --- a/app/processmodels.py +++ b/app/processmodels.py @@ -48,51 +48,49 @@ def headerData(self, section, orientation, role): return "not implemented" def data(self, index, role): # this method takes care of how the information is displayed - if role != QtCore.Qt.DisplayRole: # how to display each cell - return - - value = '' - row = index.row() - column = index.column() - processColumns = {0:'progress', 1:'display', 2:'elapsed', 3:'estimatedremaining', 4:'pid', 5:'name', 6:'tabtitle', 7:'hostip', 8:'port', 9:'protocol', 10:'command', 11:'starttime', 12:'endtime', 13:'outputfile', 14:'output', 15:'status', 16:'closed'} - try: - if column == 0: - value = '' - elif column == 2: - pid = int(self.__processes[row]['pid']) - elapsed = round(self.__controller.controller.processMeasurements.get(pid, 0), 2) - value = "{0:.2f}{1}".format(float(elapsed), "s") - elif column == 3: - status = str(self.__processes[row]['status']) - if status == "Finished" or status == "Crashed" or status == "Killed": - estimatedRemaining = 0 - else: + if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole: # how to display each cell + value = '' + row = index.row() + column = index.column() + processColumns = {0:'progress', 1:'display', 2:'elapsed', 3:'estimatedremaining', 4:'pid', 5:'name', 6:'tabtitle', 7:'hostip', 8:'port', 9:'protocol', 10:'command', 11:'starttime', 12:'endtime', 13:'outputfile', 14:'output', 15:'status', 16:'closed'} + try: + if column == 0: + value = '' + elif column == 2: pid = int(self.__processes[row]['pid']) elapsed = round(self.__controller.controller.processMeasurements.get(pid, 0), 2) - estimatedRemaining = int(self.__processes[row]['estimatedremaining']) - float(elapsed) - value = "{0:.2f}{1}".format(float(estimatedRemaining), "s") if estimatedRemaining >= 0 else 'Unknown' - elif column == 6: - if not self.__processes[row]['tabtitle'] == '': - value = self.__processes[row]['tabtitle'] - else: - value = self.__processes[row]['name'] - elif column == 8: - if not self.__processes[row]['port'] == '' and not self.__processes[row]['protocol'] == '': - value = self.__processes[row]['port'] + '/' + self.__processes[row]['protocol'] + value = "{0:.2f}{1}".format(float(elapsed), "s") + elif column == 3: + status = str(self.__processes[row]['status']) + if status == "Finished" or status == "Crashed" or status == "Killed": + estimatedRemaining = 0 + else: + pid = int(self.__processes[row]['pid']) + elapsed = round(self.__controller.controller.processMeasurements.get(pid, 0), 2) + estimatedRemaining = int(self.__processes[row]['estimatedremaining']) - float(elapsed) + value = "{0:.2f}{1}".format(float(estimatedRemaining), "s") if estimatedRemaining >= 0 else 'Unknown' + elif column == 6: + if not self.__processes[row]['tabtitle'] == '': + value = self.__processes[row]['tabtitle'] + else: + value = self.__processes[row]['name'] + elif column == 8: + if not self.__processes[row]['port'] == '' and not self.__processes[row]['protocol'] == '': + value = self.__processes[row]['port'] + '/' + self.__processes[row]['protocol'] + else: + value = self.__processes[row]['port'] + elif column == 16: + value = "" else: - value = self.__processes[row]['port'] - elif column == 16: - value = "" - else: - try: - value = self.__processes[row][processColumns.get(int(column))] - except: - value = "Missing data c #{0} - {1}".format(int(column), processColumns.get(int(column))) - pass - except Exception as e: - value = "Missing data c #{0} - {1}".format(int(column), processColumns.get(int(column))) - pass - return value + try: + value = self.__processes[row][processColumns.get(int(column))] + except: + value = "Missing data c #{0} - {1}".format(int(column), processColumns.get(int(column))) + pass + except Exception as e: + value = "Missing data c #{0} - {1}".format(int(column), processColumns.get(int(column))) + pass + return value def sort(self, Ncol, order): self.layoutAboutToBeChanged.emit() diff --git a/controller/controller.py b/controller/controller.py index f1de0925..36e3e747 100644 --- a/controller/controller.py +++ b/controller/controller.py @@ -28,13 +28,13 @@ class Controller(): def __init__(self, view, logic): self.name = "LEGION" self.version = '0.3.4' - self.build = '1556736984' + self.build = '1557101410' self.author = 'GoVanguard' self.copyright = '2019' self.links = ['http://github.com/GoVanguard/legion/issues', 'https://GoVanguard.io/legion'] self.emails = [] - self.update = '05/01/2019' + self.update = '05/05/2019' self.license = "GPL v3" self.desc = "Legion is a fork of SECFORCE's Sparta, Legion is an open source, easy-to-use, \nsuper-extensible and semi-automated network penetration testing tool that aids in discovery, \nreconnaissance and exploitation of information systems." diff --git a/db/database.py b/db/database.py index 8db4c2c3..cf6435c5 100644 --- a/db/database.py +++ b/db/database.py @@ -136,6 +136,9 @@ class cve(Base): severity = Column(String) source = Column(String) version = Column(String) + edbid = Column(Integer) + exploit = Column(String) + exploitUrl = Column(String) service_id = Column(String, ForeignKey('serviceObj.id')) host_id = Column(String, ForeignKey('hostObj.id')) @@ -146,8 +149,30 @@ def __init__(self, name, url, product, hostId, severity = '', source = '', versi self.severity = severity self.source = source self.version = version + self.edbid = 0 + self.exploit = '' + self.exploitUrl = '' self.host_id = hostId +class appObj(Base): + __tablename__ = 'appObj' + name = Column(String) + id = Column(Integer, primary_key = True) + product = Column(String) + version = Column(String) + extrainfo = Column(String) + fingerprint = Column(String) + cpe = Column(String) + service_id = Column(String, ForeignKey('serviceObj.id')) + + def __init__(self, name = '', product = '', version = '', extrainfo = '', fingerprint = '', cpe = ''): + self.name = name + self.product = product + self.version = version + self.extrainfo = extrainfo + self.fingerprint = fingerprint + self.cpe = cpe + class serviceObj(Base): __tablename__ = 'serviceObj' name = Column(String) @@ -158,6 +183,7 @@ class serviceObj(Base): fingerprint = Column(String) port = relationship(portObj) cves = relationship(cve) + application = relationship(appObj) def __init__(self, name = '', product = '', version = '', extrainfo = '', fingerprint = ''): self.name = name @@ -194,24 +220,6 @@ def __init__(self, script_id, output, portId, hostId): self.port_id = portId self.host_id = hostId -class appObj(Base): - __tablename__ = 'appObj' - name = Column(String) - id = Column(Integer, primary_key = True) - product = Column(String) - version = Column(String) - extrainfo = Column(String) - fingerprint = Column(String) - cpe = Column(String) - service = relationship(serviceObj) - - def __init__(self, name = '', product = '', version = '', extrainfo = '', fingerprint = '', cpe = ''): - self.name = name - self.product = product - self.version = version - self.extrainfo = extrainfo - self.fingerprint = fingerprint - self.cpe - cpe class hostObj(Base): __tablename__ = 'hostObj' diff --git a/legion.conf b/legion.conf index 25879639..e8e5ad53 100644 --- a/legion.conf +++ b/legion.conf @@ -9,7 +9,7 @@ store-cleartext-passwords-on-exit=True username-wordlist-path=/usr/share/wordlists/ [GUISettings] -process-tab-column-widths="125,0,74,92,67,0,124,130,0,0,0,0,0,0,0,544,100" +process-tab-column-widths="125,0,74,92,67,0,124,130,0,0,0,0,0,0,0,964,100" process-tab-detail=False [GeneralSettings] diff --git a/parsers/Script.py b/parsers/Script.py index e8ae190b..6a332fe6 100644 --- a/parsers/Script.py +++ b/parsers/Script.py @@ -7,6 +7,7 @@ import sys import xml.dom.minidom import parsers.CVE as CVE +from pyExploitDb import PyExploitDb class Script: scriptId = '' @@ -17,6 +18,11 @@ def __init__(self, ScriptNode): self.scriptId = ScriptNode.getAttribute('id') self.output = ScriptNode.getAttribute('output') + def getExploitDataFromCves(self, cveSet): + for cveEntry in cveSet: + print("CVE Entry: {0}".format(cveEntry)) + cveExploitData = self.pyExploitDb.searchCve(cveEntry(0)) + print("CVE Exploit Data: {0}".format(cveExploitData)) def processVulnersScriptOutput(self, vulnersOutput): output = vulnersOutput.replace('\t\t\t','\t') @@ -27,6 +33,10 @@ def processVulnersScriptOutput(self, vulnersOutput): output = output.split('\n') output = [entry for entry in output if len(entry) > 1] + pyExploitDb = PyExploitDb() + pyExploitDb.debug = False + pyExploitDb.openFile() + cpeList = [] count = 0 for entry in output: @@ -59,6 +69,12 @@ def processVulnersScriptOutput(self, vulnersOutput): resultCveDict['id'] = resultCveData[0] resultCveDict['severity'] = resultCveData[1] resultCveDict['url'] = resultCveData[2] + exploitResults = pyExploitDb.searchCve(resultCveData[0]) + print("-----------------{0}".format(exploitResults)) + if exploitResults: + resultCveDict['exploitid'] = exploitResults['edbid'] + resultCveDict['exploit'] = exploitResults['exploit'] + resultCveDict['exploiturl'] = "https://www.exploit-db.com/exploits/{0}".format(resultCveDict['exploit']) resultCvesProcessed.append(resultCveDict) resultCpeDetails['cves'] = resultCvesProcessed resultsDict[resultCpeData[3]] = resultCpeDetails @@ -72,6 +88,7 @@ def get_cves(self): if len(cveOutput) > 0: cvesResults = self.processVulnersScriptOutput(cveOutput) + for cpeEntry in cvesResults: cpeData = cvesResults[cpeEntry] cpeProduct = cpeEntry diff --git a/requirements.txt b/requirements.txt index 759509dd..a814949c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,3 +14,4 @@ pyfiglet colorama termcolor win_inet_pton +pyExploitDb==0.1.7 diff --git a/ui/view.py b/ui/view.py index eb9bb44d..504ff77a 100644 --- a/ui/view.py +++ b/ui/view.py @@ -184,7 +184,7 @@ def initTables(self): # this funct setTableProperties(self.ui.ServiceNamesTableView, len(headers)) # cves table (right) - headers = ["Id", "Severity", "Product", "Version", "URL", "Source"] + headers = ["Id", "Severity", "Product", "Version", "URL", "Source", "Exploit ID", "Exploit", "Exploit URL"] setTableProperties(self.ui.CvesTableView, len(headers)) self.ui.CvesTableView.setSortingEnabled(True) @@ -1097,11 +1097,14 @@ def updateScriptsView(self, hostIP): self.ui.ScriptsTableView.selectRow(row) self.scriptTableClick() + self.ui.ScriptsTableView.repaint() + self.ui.ScriptsTableView.update() + def updateCvesByHostView(self, hostIP): - headers = ["ID", "CVSS Score", "Product", "Version", "URL", "Source"] + headers = ["ID", "CVSS Score", "Product", "Version", "URL", "Source", "Exploit ID", "Exploit", "Exploit URL"] cves = self.controller.getCvesFromDB(hostIP) - print(cves) - self.CvesTableModel = CvesTableModel(self,self.controller.getCvesFromDB(hostIP), headers) + print("CVES: {0}".format(str(cves))) + self.CvesTableModel = CvesTableModel(self, cves, headers) self.ui.CvesTableView.horizontalHeader().resizeSection(0,175) self.ui.CvesTableView.horizontalHeader().resizeSection(2,175) From 5223f00f8de4a880f316db8d2f1f8f557c000879 Mon Sep 17 00:00:00 2001 From: sscottgvit Date: Mon, 6 May 2019 07:26:01 -0500 Subject: [PATCH 20/20] New scripts, CVE processing optimization, Early Shodan --- .gitignore | 2 + CHANGELOG.txt | 6 + README.md | 2 + app/auxiliary.py | 8 +- app/cvemodels.py | 15 +++ app/hostmodels.py | 6 +- app/logic.py | 256 +++++++++++++++++++----------------- app/processmodels.py | 14 +- app/scriptmodels.py | 10 +- app/servicemodels.py | 14 +- controller/controller.py | 56 ++++---- db/database.py | 172 +++++++++++++----------- debian/changelog | 2 +- debian/watch | 2 +- deps/detectScripts.sh | 7 - deps/installDeps.sh | 2 +- deps/installPythonLibs.sh | 4 +- legion.conf | 4 +- parsers/CVE.py | 6 + parsers/Host.py | 215 +++++++++++++++--------------- parsers/OS.py | 8 +- parsers/Parser.py | 58 ++++---- parsers/Port.py | 14 +- parsers/Script.py | 44 +++++-- parsers/Session.py | 26 ++-- precommit.sh | 2 +- requirements.txt | 16 +-- scripts/nmap/shodan-api.nse | 223 +++++++++++++++++++++++++++++++ scripts/nmap/shodan-hq.nse | 135 +++++++++++++++++++ ui/view.py | 58 ++++---- 30 files changed, 908 insertions(+), 479 deletions(-) create mode 100644 scripts/nmap/shodan-api.nse create mode 100644 scripts/nmap/shodan-hq.nse diff --git a/.gitignore b/.gitignore index 2670db3a..a82c559d 100644 --- a/.gitignore +++ b/.gitignore @@ -118,3 +118,5 @@ scripts/snmpbrute.py scripts/installDeps.sh scripts/smtp-user-enum.pl scripts/snmpcheck.rb + +scripts/CloudFail diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 46de76db..18884e71 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,9 @@ +LEGION 0.3.5 + +* Bug Fixes +* Copy from tables using double click +* CVE -> ExploitDB redesign using pyExploitDb and bugfixes + LEGION 0.3.4 * Depnendancy polish diff --git a/README.md b/README.md index 1e3af6f0..0f37e695 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Legion, a fork of SECFORCE's Sparta, is an open source, easy-to-use, super-exten * Modular functionality allows users to easily customize Legion and automatically call their own scripts/tools * Highly customizable stage scanning for ninja-like IPS evasion * Automatic detection of CPEs (Common Platform Enumeration) and CVEs (Common Vulnerabilities and Exposures) +* Ties CVEs to Exploits as detailed in Exploit-Database * Realtime autosaving of project results and tasks ### NOTABLE CHANGES FROM SPARTA @@ -36,6 +37,7 @@ Legion, a fork of SECFORCE's Sparta, is an open source, easy-to-use, super-exten ![](https://govanguard.io/wp-content/uploads/2019/02/LegionDemo.gif) ## INSTALLATION +It is preferable to use the docker image over a traditional installation. This is because of all the dependancy requirements and the complications that occur in environments which differ from a clean, non-default installation. ### TRADITIONAL METHOD Assumes Ubuntu, Kali or Parrot Linux is being used with Python 3.6 installed. diff --git a/app/auxiliary.py b/app/auxiliary.py index b4998eb7..46ae3b7e 100644 --- a/app/auxiliary.py +++ b/app/auxiliary.py @@ -199,16 +199,16 @@ def add(self, word): class MyQProcess(QProcess): sigHydra = QtCore.pyqtSignal(QObject, list, list, name="hydra") # signal to indicate Hydra found stuff - def __init__(self, name, tabtitle, hostip, port, protocol, command, starttime, outputfile, textbox): + def __init__(self, name, tabTitle, hostIp, port, protocol, command, startTime, outputfile, textbox): QProcess.__init__(self) self.id = -1 self.name = name - self.tabtitle = tabtitle - self.hostip = hostip + self.tabTitle = tabTitle + self.hostIp = hostIp self.port = port self.protocol = protocol self.command = command - self.starttime = starttime + self.startTime = startTime self.outputfile = outputfile self.display = textbox # has its own display widget to be able to display its output in the GUI self.elapsed = -1 diff --git a/app/cvemodels.py b/app/cvemodels.py index 05199559..b8b342fd 100644 --- a/app/cvemodels.py +++ b/app/cvemodels.py @@ -63,6 +63,12 @@ def data(self, index, role): # this metho value = self.__cves[row]['url'] elif column == 5: value = self.__cves[row]['source'] + elif column == 6: + value = self.__cves[row]['exploitId'] + elif column == 7: + value = self.__cves[row]['exploit'] + elif column == 8: + value = self.__cves[row]['exploitUrl'] return value @@ -88,6 +94,15 @@ def sort(self, Ncol, order): elif Ncol == 5: for i in range(len(self.__cves)): array.append(self.__cves[i]['source']) + elif Ncol == 6: + for i in range(len(self.__cves)): + array.append(self.__cves[i]['exploitId']) + elif Ncol == 7: + for i in range(len(self.__cves)): + array.append(self.__cves[i]['exploit']) + elif Ncol == 8: + for i in range(len(self.__cves)): + array.append(self.__cves[i]['exploitUrl']) sortArrayWithArray(array, self.__cves) # sort the services based on the values in the array diff --git a/app/hostmodels.py b/app/hostmodels.py index 616a1d12..5146dfa7 100644 --- a/app/hostmodels.py +++ b/app/hostmodels.py @@ -46,7 +46,7 @@ def headerData(self, section, orientation, role): def data(self, index, role): # this method takes care of how the information is displayed if role == QtCore.Qt.DecorationRole: # to show the operating system icon instead of text if index.column() == 1: # if trying to display the operating system - os_string = self.__hosts[index.row()]['os_match'] + os_string = self.__hosts[index.row()]['osMatch'] if os_string == '': # if there is no OS information, use the question mark icon return QtGui.QIcon("./images/question-icon.png") @@ -78,7 +78,7 @@ def data(self, index, role): # this metho if column == 0: value = self.__hosts[row]['id'] elif column == 2: - value = self.__hosts[row]['os_accuracy'] + value = self.__hosts[row]['osAccuracy'] elif column == 3: if not self.__hosts[row]['hostname'] == '': value = self.__hosts[row]['ip'] + ' ('+ self.__hosts[row]['hostname'] +')' @@ -133,7 +133,7 @@ def sort(self, Ncol, order): # sort funct elif Ncol == 1: # if sorting by OS for i in range(len(self.__hosts)): - os_string = self.__hosts[i]['os_match'] + os_string = self.__hosts[i]['osMatch'] if os_string == '': array.append('') diff --git a/app/logic.py b/app/logic.py index 6eae38cb..da15eb58 100644 --- a/app/logic.py +++ b/app/logic.py @@ -202,7 +202,7 @@ def getHostsFromDB(self, filters): if filters.checked == False: query += ' AND hosts.checked!=\'True\'' for word in filters.keywords: - query += ' AND (hosts.ip LIKE \'%'+sanitise(word)+'%\' OR hosts.os_match LIKE \'%'+sanitise(word)+'%\' OR hosts.hostname LIKE \'%'+sanitise(word)+'%\')' + query += ' AND (hosts.ip LIKE \'%'+sanitise(word)+'%\' OR hosts.osMatch LIKE \'%'+sanitise(word)+'%\' OR hosts.hostname LIKE \'%'+sanitise(word)+'%\')' return self.db.metadata.bind.execute(query).fetchall() @@ -211,7 +211,7 @@ def getServiceNamesFromDB(self, filters): query = ('SELECT DISTINCT service.name FROM serviceObj as service ' + 'INNER JOIN portObj as ports ' + 'INNER JOIN hostObj AS hosts ' + - 'ON hosts.id = ports.host_id AND service.id=ports.service_id WHERE 1=1') + 'ON hosts.id = ports.hostId AND service.id=ports.serviceId WHERE 1=1') if filters.down == False: query += ' AND hosts.status!=\'down\'' @@ -220,7 +220,7 @@ def getServiceNamesFromDB(self, filters): if filters.checked == False: query += ' AND hosts.checked!=\'True\'' for word in filters.keywords: - query += ' AND (hosts.ip LIKE \'%'+sanitise(word)+'%\' OR hosts.os_match LIKE \'%'+sanitise(word)+'%\' OR hosts.hostname LIKE \'%'+sanitise(word)+'%\')' + query += ' AND (hosts.ip LIKE \'%'+sanitise(word)+'%\' OR hosts.osMatch LIKE \'%'+sanitise(word)+'%\' OR hosts.hostname LIKE \'%'+sanitise(word)+'%\')' if filters.portopen == False: query += ' AND ports.state!=\'open\' AND ports.state!=\'open|filtered\'' if filters.portclosed == False: @@ -239,20 +239,20 @@ def getServiceNamesFromDB(self, filters): # get notes for given host IP def getNoteFromDB(self, hostId): session = self.db.session() - return session.query(note).filter_by(host_id=str(hostId)).first() + return session.query(note).filter_by(hostId=str(hostId)).first() # get script info for given host IP def getScriptsFromDB(self, hostIP): - query = ('SELECT host.id, host.script_id, port.port_id, port.protocol FROM l1ScriptObj AS host ' + - 'INNER JOIN hostObj AS hosts ON hosts.id = host.host_id ' + - 'LEFT OUTER JOIN portObj AS port ON port.id = host.port_id ' + + query = ('SELECT host.id, host.scriptId, port.portId, port.protocol FROM l1ScriptObj AS host ' + + 'INNER JOIN hostObj AS hosts ON hosts.id = host.hostId ' + + 'LEFT OUTER JOIN portObj AS port ON port.id = host.portId ' + 'WHERE hosts.ip=?') return self.db.metadata.bind.execute(query, str(hostIP)).fetchall() def getCvesFromDB(self, hostIP): - query = ('SELECT cves.name, cves.severity, cves.product, cves.version, cves.url, cves.source, cves.edbid, cves.exploit, cves.exploiturl FROM cve AS cves ' + - 'INNER JOIN hostObj AS hosts ON hosts.id = cves.host_id ' + + query = ('SELECT cves.name, cves.severity, cves.product, cves.version, cves.url, cves.source, cves.exploitId, cves.exploit, cves.exploitUrl FROM cve AS cves ' + + 'INNER JOIN hostObj AS hosts ON hosts.id = cves.hostId ' + 'WHERE hosts.ip = ?') return self.db.metadata.bind.execute(query, str(hostIP)).fetchall() @@ -262,9 +262,9 @@ def getScriptOutputFromDB(self, scriptDBId): # get port and service info for given host IP def getPortsAndServicesForHostFromDB(self, hostIP, filters): - query = ('SELECT hosts.ip, ports.port_id, ports.protocol, ports.state, ports.host_id, ports.service_id, services.name, services.product, services.version, services.extrainfo, services.fingerprint FROM portObj AS ports ' + - 'INNER JOIN hostObj AS hosts ON hosts.id = ports.host_id ' + - 'LEFT OUTER JOIN serviceObj AS services ON services.id = ports.service_id ' + + query = ('SELECT hosts.ip, ports.portId, ports.protocol, ports.state, ports.hostId, ports.serviceId, services.name, services.product, services.version, services.extrainfo, services.fingerprint FROM portObj AS ports ' + + 'INNER JOIN hostObj AS hosts ON hosts.id = ports.hostId ' + + 'LEFT OUTER JOIN serviceObj AS services ON services.id = ports.serviceId ' + 'WHERE hosts.ip = ?') if filters.portopen == False: @@ -282,8 +282,8 @@ def getPortsAndServicesForHostFromDB(self, hostIP, filters): # used to check if there are any ports of a specific protocol for a given host def getPortsForHostFromDB(self, hostIP, protocol): - query = ('SELECT ports.port_id FROM portObj AS ports ' + - 'INNER JOIN hostObj AS hosts ON hosts.id = ports.host_id ' + + query = ('SELECT ports.portId FROM portObj AS ports ' + + 'INNER JOIN hostObj AS hosts ON hosts.id = ports.hostId ' + 'WHERE hosts.ip = ? and ports.protocol = ?') results = self.db.metadata.bind.execute(query, str(hostIP), str(protocol)).first() return results @@ -291,18 +291,18 @@ def getPortsForHostFromDB(self, hostIP, protocol): # used to get the service name given a host ip and a port when we are in tools tab (left) and right click on a host def getServiceNameForHostAndPort(self, hostIP, port): query = ('SELECT services.name FROM serviceObj AS services ' + - 'INNER JOIN hostObj AS hosts ON hosts.id = ports.host_id ' + - 'INNER JOIN portObj AS ports ON services.id=ports.service_id ' + - 'WHERE hosts.ip=? and ports.port_id = ?') + 'INNER JOIN hostObj AS hosts ON hosts.id = ports.hostId ' + + 'INNER JOIN portObj AS ports ON services.id=ports.serviceId ' + + 'WHERE hosts.ip=? and ports.portId = ?') results = self.db.metadata.bind.execute(query, str(hostIP), str(port)).first() return results # used to delete all port/script data related to a host - to overwrite portscan info with the latest scan def deleteAllPortsAndScriptsForHostFromDB(self, hostID, protocol): session = self.db.session() - ports_for_host = session.query(portObj).filter(portObj.host_id == hostID).filter(portObj.protocol == str(protocol)).all() + ports_for_host = session.query(portObj).filter(portObj.hostId == hostID).filter(portObj.protocol == str(protocol)).all() for p in ports_for_host: - scripts_for_ports = session.query(l1ScriptObj).filter(l1ScriptObj.port_id == p.id).all() + scripts_for_ports = session.query(l1ScriptObj).filter(l1ScriptObj.portId == p.id).all() for s in scripts_for_ports: session.delete(s) for p in ports_for_host: @@ -323,14 +323,14 @@ def deleteHost(self, hostIP): return def getPortStatesForHost(self, hostID): - query = ('SELECT port.state FROM portObj as port WHERE port.host_id = ?') + query = ('SELECT port.state FROM portObj as port WHERE port.hostId = ?') results = self.db.metadata.bind.execute(query, str(hostID)).fetchall() return results def getHostsAndPortsForServiceFromDB(self, serviceName, filters): - query = ('SELECT hosts.ip,ports.port_id,ports.protocol,ports.state,ports.host_id,ports.service_id,services.name,services.product,services.version,services.extrainfo,services.fingerprint FROM portObj AS ports ' + - 'INNER JOIN hostObj AS hosts ON hosts.id = ports.host_id ' + - 'LEFT OUTER JOIN serviceObj AS services ON services.id=ports.service_id ' + + query = ('SELECT hosts.ip,ports.portId,ports.protocol,ports.state,ports.hostId,ports.serviceId,services.name,services.product,services.version,services.extrainfo,services.fingerprint FROM portObj AS ports ' + + 'INNER JOIN hostObj AS hosts ON hosts.id = ports.hostId ' + + 'LEFT OUTER JOIN serviceObj AS services ON services.id=ports.serviceId ' + 'WHERE services.name=?') if filters.down == False: @@ -350,7 +350,7 @@ def getHostsAndPortsForServiceFromDB(self, serviceName, filters): if filters.udp == False: query += ' AND ports.protocol!=\'udp\'' for word in filters.keywords: - query += ' AND (hosts.ip LIKE \'%'+sanitise(word)+'%\' OR hosts.os_match LIKE \'%'+sanitise(word)+'%\' OR hosts.hostname LIKE \'%'+sanitise(word)+'%\')' + query += ' AND (hosts.ip LIKE \'%'+sanitise(word)+'%\' OR hosts.osMatch LIKE \'%'+sanitise(word)+'%\' OR hosts.hostname LIKE \'%'+sanitise(word)+'%\')' return self.db.metadata.bind.execute(query, str(serviceName)).fetchall() @@ -363,13 +363,13 @@ def getProcessesFromDB(self, filters, showProcesses='noNmap', sort = 'desc', nco result = self.db.metadata.bind.execute(query).fetchall() elif showProcesses == False: # when opening a project, fetch only the processes that have display=false and were not in tabs that were closed by the user - query = ('SELECT process.id, process.hostip, process.tabtitle, process.outputfile, output.output FROM process AS process ' - 'INNER JOIN process_output AS output ON process.id = output.process_id ' + query = ('SELECT process.id, process.hostIp, process.tabTitle, process.outputfile, output.output FROM process AS process ' + 'INNER JOIN process_output AS output ON process.id = output.processId ' 'WHERE process.display=? AND process.closed="False" order by process.id desc') result = self.db.metadata.bind.execute(query, str(showProcesses)).fetchall() - #query = ('SELECT process.id, process.hostip, process.tabtitle, process.outputfile, output.output FROM process AS process ' - #'INNER JOIN process_output AS output ON process.id = output.process_id ' + #query = ('SELECT process.id, process.hostIp, process.tabTitle, process.outputfile, output.output FROM process AS process ' + #'INNER JOIN process_output AS output ON process.id = output.processId ' #'WHERE process.display=? AND process.closed="False" order by process.id desc') else: # show all the processes in the (bottom) process table (no matter their closed value) @@ -380,9 +380,9 @@ def getProcessesFromDB(self, filters, showProcesses='noNmap', sort = 'desc', nco def getHostsForTool(self, toolname, closed='False'): if closed == 'FetchAll': - query = ('SELECT "0", "0", "0", "0", "0", process.hostip, process.port, process.protocol, "0", "0", process.outputfile, "0", "0", "0" FROM process AS process WHERE process.name=?') + query = ('SELECT "0", "0", "0", "0", "0", process.hostIp, process.port, process.protocol, "0", "0", process.outputfile, "0", "0", "0" FROM process AS process WHERE process.name=?') else: - query = ('SELECT process.id, "0", "0", "0", "0", "0", "0", process.hostip, process.port, process.protocol, "0", "0", process.outputfile, "0", "0", "0" FROM process AS process WHERE process.name=? and process.closed="False"') + query = ('SELECT process.id, "0", "0", "0", "0", "0", "0", process.hostIp, process.port, process.protocol, "0", "0", process.outputfile, "0", "0", "0" FROM process AS process WHERE process.name=? and process.closed="False"') return self.db.metadata.bind.execute(query, str(toolname)).fetchall() @@ -415,7 +415,7 @@ def toggleHostCheckStatus(self, ipaddr): def addProcessToDB(self, proc): log.info('Add process') 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), proc.starttime, "", str(proc.outputfile), 'Waiting', [p_output], 100, 0) + 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], 100, 0) log.info(p) session = self.db.session() session.add(p) @@ -455,7 +455,7 @@ def storeProcessKillStatusInDB(self, procId): #proc = process.query.filter_by(id=procId).first() if proc and not proc.status == 'Finished': proc.status = 'Killed' - proc.endtime = getTimestamp(True) # store end time + proc.endTime = getTimestamp(True) # store end time session.add(proc) #session.commit() self.db.commit() @@ -466,7 +466,7 @@ def storeProcessCrashStatusInDB(self, procId): #proc = process.query.filter_by(id=procId).first() if proc and not proc.status == 'Killed' and not proc.status == 'Cancelled': proc.status = 'Crashed' - proc.endtime = getTimestamp(True) # store end time + proc.endTime = getTimestamp(True) # store end time session.add(proc) #session.commit() self.db.commit() @@ -478,7 +478,7 @@ def storeProcessCancelStatusInDB(self, procId): #proc = process.query.filter_by(id=procId).first() if proc: proc.status = 'Cancelled' - proc.endtime = getTimestamp(True) # store end time + proc.endTime = getTimestamp(True) # store end time session.add(proc) #session.commit() self.db.commit() @@ -525,7 +525,7 @@ def storeProcessOutputInDB(self, procId, output): proc_output.output=unicode(output) session.add(proc_output) - proc.endtime = getTimestamp(True) # store end time + proc.endTime = getTimestamp(True) # store end time if proc.status == "Killed" or proc.status == "Cancelled" or proc.status == "Crashed": # if the process has been killed don't change the status to "Finished" self.db.commit() # new: this was missing but maybe this is important here to ensure that we save the process output no matter what @@ -561,7 +561,57 @@ def isCanceledProcess(self, procId): if not proc or str(proc[0][0]) == "Cancelled": return True return False - + +class ShodanImporter(QtCore.QThread): + tick = QtCore.pyqtSignal(int, name="changed") # New style signal + done = QtCore.pyqtSignal(name="done") # New style signal + schedule = QtCore.pyqtSignal(object, bool, name="schedule") # New style signal + log = QtCore.pyqtSignal(str, name="log") + + def __init__(self): + QtCore.QThread.__init__(self, parent=None) + self.output = '' + self.importProgressWidget = ProgressWidget('Importing shodan data..') + + def tsLog(self, msg): + self.log.emit(str(msg)) + + def setDB(self, db): + self.db = db + + def setFilename(self, filename): + self.filename = filename + + def setOutput(self, output): + self.output = output + + def run(self): # it is necessary to get the qprocess because we need to send it back to the scheduler when we're done importing + try: + session = self.db.session() + startTime = time() + self.db.dbsemaphore.acquire() # ensure that while this thread is running, no one else can write to the DB + + for h in parser.getAllHosts(): # create all the hosts that need to be created + db_host = session.query(hostObj).filter_by(ip=h.ip).first() + + if not db_host: # if host doesn't exist in DB, create it first + hid = hostObj(osMatch='', osAccuracy='', ip=h.ip, ipv4=h.ipv4, ipv6=h.ipv6, macaddr=h.macaddr, status=h.status, hostname=h.hostname, vendor=h.vendor, uptime=h.uptime, \ + lastboot=h.lastboot, distance=h.distance, state=h.state, count=h.count) + self.tsLog("Adding db_host") + session.add(hid) + else: + self.tsLog("Found db_host already in db") + session.commit() + self.db.dbsemaphore.release() # we are done with the DB + self.tsLog('Finished in '+ str(time()-startTime) + ' seconds.') + self.done.emit() + self.schedule.emit(parser, self.output == '') # call the scheduler (if there is no terminal output it means we imported nmap) + + except Exception as e: + self.tsLog(e) + raise + self.done.emit() + class NmapImporter(QtCore.QThread): tick = QtCore.pyqtSignal(int, name="changed") # New style signal done = QtCore.pyqtSignal(name="done") # New style signal @@ -585,63 +635,12 @@ def setFilename(self, filename): def setOutput(self, output): self.output = output - def getCveFuzzy(self, searchPhrase): - import requests - VULNERS_LINKS = { - 'search':'https://vulners.com/api/v3/search/lucene/', - 'id':'https://vulners.com/api/v3/search/id/', - } - exploitExcludeList = ['nessus', 'openvas', 'seebug'] - searchParameters = { - 'size':500, - 'skip':0, - } - searchQuery = '("%s") AND cvelist:[* TO *] AND %s' % (searchPhrase, " AND ".join(["-type:%s" % type for type in exploitExcludeList]).strip()) - cveIdentificatorsSet = set() - bulkSearch = searchParameters - bulkSearch['query'] = searchQuery - bulletinSearch = searchParameters - print("Executing search with query: %s" % searchQuery) - findAllBulletins = requests.post(VULNERS_LINKS['search'], json=bulkSearch).json().get('data') - totalBulletins = findAllBulletins.get('total') - print("Total found bulletins: %s" % totalBulletins) - allBulletinIds = [bulletinEntry['_source']['id'] for bulletinEntry in findAllBulletins['search']] - for bulletinId in allBulletinIds: - bulletinSearch['id'] = bulletinId - searchResult = requests.post(VULNERS_LINKS['id'], json=bulletinSearch).json()['data']['documents'][bulletinId] - if not searchResult .get('cvelist'): - print("No CVE identificators for %s" % bulletinId) - else: - cveIdentificatorsSet = cveIdentificatorsSet.union(searchResult.get('cvelist')) - return list(cveIdentificatorsSet) - - def getCve(self, product, version): - import vulners - formattedResults = [] - try: - vulnersApi = vulners.Vulners(api_key="X02GUJ0BARMNBPTYCHK113SEAUOXTHMF6COCD8M7TCAIY2FHWX9OIROBBVNMQCF2") - queryResults = vulnersApi.softwareVulnerabilities(str(product), str(version)) - #exploitList = results.get('exploit') - vulnList = [queryResults.get(key) for key in queryResults if key not in ['info', 'blog', 'bugbounty']] - for vulnEntry in vulnList: - vulnEntry = vulnEntry[0] - cveList = vulnEntry['cvelist'] - cveUrl = vulnEntry['href'] - cveCvss = vulnEntry['cvss'] - cveTitle = vulnEntry[0]['title'] - cveType = vulnEntry[0]['type'] - formattedResult = {'cveList': cveList, 'cveUrl': cveUrl, 'cveTitle': cveTitle} - formattedResults.append(formattedResult) - except: - print("Vulners query issue") - return formattedResults - def run(self): # it is necessary to get the qprocess because we need to send it back to the scheduler when we're done importing try: self.importProgressWidget.show() session = self.db.session() self.tsLog("Parsing nmap xml file: " + self.filename) - starttime = time() + startTime = time() try: parser = Parser(self.filename) @@ -652,11 +651,11 @@ def run(self): # it is nece return self.db.dbsemaphore.acquire() # ensure that while this thread is running, no one else can write to the DB - s = parser.get_session() # nmap session info + s = parser.getSession() # nmap session info if s: - n = nmap_session(self.filename, s.start_time, s.finish_time, s.nmap_version, s.scan_args, s.total_hosts, s.up_hosts, s.down_hosts) + n = nmapSessionObj(self.filename, s.startTime, s.finish_time, s.nmapVersion, s.scanArgs, s.totalHosts, s.upHosts, s.downHosts) session.add(n) - hostCount = len(parser.all_hosts()) + hostCount = len(parser.getAllHosts()) if hostCount==0: # to fix a division by zero if we ran nmap on one host hostCount=1 totalprogress = 0 @@ -668,11 +667,11 @@ def run(self): # it is nece createOsNodesProgress = 0 createPortsProgress = 0 - for h in parser.all_hosts(): # create all the hosts that need to be created + for h in parser.getAllHosts(): # create all the hosts that need to be created db_host = session.query(hostObj).filter_by(ip=h.ip).first() if not db_host: # if host doesn't exist in DB, create it first - hid = hostObj(os_match='', os_accuracy='', ip=h.ip, ipv4=h.ipv4, ipv6=h.ipv6, macaddr=h.macaddr, status=h.status, hostname=h.hostname, vendor=h.vendor, uptime=h.uptime, lastboot=h.lastboot, distance=h.distance, state=h.state, count=h.count) + hid = hostObj(osMatch='', osAccuracy='', ip=h.ip, ipv4=h.ipv4, ipv6=h.ipv6, macaddr=h.macaddr, status=h.status, hostname=h.hostname, vendor=h.vendor, uptime=h.uptime, lastboot=h.lastboot, distance=h.distance, state=h.state, count=h.count) self.tsLog("Adding db_host") session.add(hid) t_note = note(h.ip, 'Added by nmap') @@ -687,7 +686,7 @@ def run(self): # it is nece session.commit() - for h in parser.all_hosts(): # create all OS, service and port objects that need to be created + for h in parser.getAllHosts(): # create all OS, service and port objects that need to be created self.tsLog("Processing h {ip}".format(ip=h.ip)) db_host = session.query(hostObj).filter_by(ip=h.ip).first() @@ -696,14 +695,14 @@ def run(self): # it is nece else: self.log("Did not find db_host during os/ports/service processing") - os_nodes = h.get_OS() # parse and store all the OS nodes + os_nodes = h.getOs() # parse and store all the OS nodes self.tsLog(" 'os_nodes' to process: {os_nodes}".format(os_nodes=str(len(os_nodes)))) for os in os_nodes: self.tsLog(" Processing os obj {os}".format(os=str(os.name))) - db_os = session.query(osObj).filter_by(host_id=db_host.id).filter_by(name=os.name).filter_by(family=os.family).filter_by(generation=os.generation).filter_by(os_type=os.os_type).filter_by(vendor=os.vendor).first() + db_os = session.query(osObj).filter_by(hostId=db_host.id).filter_by(name=os.name).filter_by(family=os.family).filter_by(generation=os.generation).filter_by(osType=os.osType).filter_by(vendor=os.vendor).first() if not db_os: - t_osObj = osObj(os.name, os.family, os.generation, os.os_type, os.vendor, os.accuracy, db_host.id) + t_osObj = osObj(os.name, os.family, os.generation, os.osType, os.vendor, os.accuracy, db_host.id) session.add(t_osObj) createOsNodesProgress = createOsNodesProgress + ((100.0 / hostCount) / 5) @@ -717,7 +716,7 @@ def run(self): # it is nece self.tsLog(" 'ports' to process: {all_ports}".format(all_ports=str(len(all_ports)))) for p in all_ports: # parse the ports self.tsLog(" Processing port obj {port}".format(port=str(p.portId))) - s = p.get_service() + s = p.getService() if not (s is None): # check if service already exists to avoid adding duplicates #print(" Found service {service} for port {port}".format(service=str(s.name),port=str(p.portId))) @@ -733,7 +732,7 @@ def run(self): # it is nece else: # else, there is no service info to parse db_service = None # fetch the port - db_port = session.query(portObj).filter_by(host_id=db_host.id).filter_by(port_id=p.portId).filter_by(protocol=p.protocol).first() + db_port = session.query(portObj).filter_by(hostId=db_host.id).filter_by(portId=p.portId).filter_by(protocol=p.protocol).first() if not db_port: #print("Did not find port *********** portid={0} proto={1}".format(p.portId, p.protocol)) @@ -743,7 +742,7 @@ def run(self): # it is nece db_port = portObj(p.portId, p.protocol, p.state, db_host.id, '') session.add(db_port) #else: - #print('FOUND port *************** portid={0}'.format(db_port.port_id)) + #print('FOUND port *************** portid={0}'.format(db_port.portId)) createPortsProgress = createPortsProgress + ((100.0 / hostCount) / 5) totalprogress = totalprogress + createPortsProgress self.importProgressWidget.setProgress(totalprogress) @@ -754,35 +753,30 @@ def run(self): # it is nece #totalprogress += progress #self.tick.emit(int(totalprogress)) - for h in parser.all_hosts(): # create all script objects that need to be created - + for h in parser.getAllHosts(): # create all script objects that need to be created db_host = session.query(hostObj).filter_by(ip=h.ip).first() for p in h.all_ports(): - for scr in p.get_scripts(): + for scr in p.getScripts(): self.tsLog(" Processing script obj {scr}".format(scr=str(scr))) print(" Processing script obj {scr}".format(scr=str(scr))) - db_port = session.query(portObj).filter_by(host_id=db_host.id).filter_by(port_id=p.portId).filter_by(protocol=p.protocol).first() - db_script = session.query(l1ScriptObj).filter_by(script_id=scr.scriptId).filter_by(port_id=db_port.id).first() - cveResults = scr.get_cves() - for cveEntry in cveResults: - t_cve = cve(name = cveEntry.name, url = cveEntry.url, source = cveEntry.source, severity = cveEntry.severity, product = cveEntry.product, version = cveEntry.version, hostId = db_host.id) - session.add(t_cve) + db_port = session.query(portObj).filter_by(hostId=db_host.id).filter_by(portId=p.portId).filter_by(protocol=p.protocol).first() + db_script = session.query(l1ScriptObj).filter_by(scriptId=scr.scriptId).filter_by(portId=db_port.id).first() if not db_script: # if this script object doesn't exist, create it t_l1ScriptObj = l1ScriptObj(scr.scriptId, scr.output, db_port.id, db_host.id) self.tsLog(" Adding l1ScriptObj obj {script}".format(script=scr.scriptId)) session.add(t_l1ScriptObj) - for hs in h.get_hostscripts(): - db_script = session.query(l1ScriptObj).filter_by(script_id=hs.scriptId).filter_by(host_id=db_host.id).first() + for hs in h.getHostScripts(): + db_script = session.query(l1ScriptObj).filter_by(scriptId=hs.scriptId).filter_by(hostId=db_host.id).first() if not db_script: t_l1ScriptObj = l1ScriptObj(hs.scriptId, hs.output, None, db_host.id) session.add(t_l1ScriptObj) session.commit() - for h in parser.all_hosts(): # update everything + for h in parser.getAllHosts(): # update everything db_host = session.query(hostObj).filter_by(ip=h.ip).first() @@ -814,11 +808,11 @@ def run(self): # it is nece tmp_name = '' tmp_accuracy = '0' # TODO: check if better to convert to int for comparison - os_nodes = h.get_OS() + os_nodes = h.getOs() for os in os_nodes: - db_os = session.query(osObj).filter_by(host_id=db_host.id).filter_by(name=os.name).filter_by(family=os.family).filter_by(generation=os.generation).filter_by(os_type=os.os_type).filter_by(vendor=os.vendor).first() + db_os = session.query(osObj).filter_by(hostId=db_host.id).filter_by(name=os.name).filter_by(family=os.family).filter_by(generation=os.generation).filter_by(osType=os.osType).filter_by(vendor=os.vendor).first() - db_os.os_accuracy = os.accuracy # update the accuracy + db_os.osAccuracy = os.accuracy # update the accuracy if not os.name == '': # get the most accurate OS match/accuracy to store it in the host table for easier access if os.accuracy > tmp_accuracy: @@ -828,20 +822,34 @@ def run(self): # it is nece if os_nodes: # if there was operating system info to parse if not tmp_name == '' and not tmp_accuracy == '0': # update the current host with the most accurate OS match - db_host.os_match = tmp_name - db_host.os_accuracy = tmp_accuracy + db_host.osMatch = tmp_name + db_host.osAccuracy = tmp_accuracy session.add(db_host) + + for scr in h.getHostScripts(): + print("-----------------------Host SCR: {0}".format(scr.scriptId)) + db_host = session.query(hostObj).filter_by(ip=h.ip).first() + scrProcessorResults = scr.scriptSelector(db_host) + for scrProcessorResult in scrProcessorResults: + session.add(scrProcessorResult) + + for scr in h.getScripts(): + print("-----------------------SCR: {0}".format(scr.scriptId)) + db_host = session.query(hostObj).filter_by(ip=h.ip).first() + scrProcessorResults = scr.scriptSelector(db_host) + for scrProcessorResult in scrProcessorResults: + session.add(scrProcessorResult) for p in h.all_ports(): - s = p.get_service() + s = p.getService() if not (s is None): #db_service = session.query(serviceObj).filter_by(name=s.name).filter_by(product=s.product).filter_by(version=s.version).filter_by(extrainfo=s.extrainfo).filter_by(fingerprint=s.fingerprint).first() db_service = session.query(serviceObj).filter_by(name=s.name).first() else: db_service = None # fetch the port - db_port = session.query(portObj).filter_by(host_id=db_host.id).filter_by(port_id=p.portId).filter_by(protocol=p.protocol).first() + db_port = session.query(portObj).filter_by(hostId=db_host.id).filter_by(portId=p.portId).filter_by(protocol=p.protocol).first() if db_port: #print("************************ Found {0}".format(db_port)) @@ -849,12 +857,12 @@ def run(self): # it is nece db_port.state = p.state session.add(db_port) - if not (db_service is None) and db_port.service_id != db_service.id: # if there is some new service information, update it - db_port.service_id = db_service.id + if not (db_service is None) and db_port.serviceId != db_service.id: # if there is some new service information, update it + db_port.serviceId = db_service.id session.add(db_port) - for scr in p.get_scripts(): # store the script results (note that existing script outputs are also kept) - db_script = session.query(l1ScriptObj).filter_by(script_id=scr.scriptId).filter_by(port_id=db_port.id).first() + for scr in p.getScripts(): # store the script results (note that existing script outputs are also kept) + db_script = session.query(l1ScriptObj).filter_by(scriptId=scr.scriptId).filter_by(portId=db_port.id).first() if not scr.output == '' and scr.output is not None: db_script.output = scr.output @@ -867,7 +875,7 @@ def run(self): # it is nece session.commit() self.db.dbsemaphore.release() # we are done with the DB - self.tsLog('Finished in '+ str(time()-starttime) + ' seconds.') + self.tsLog('Finished in '+ str(time()-startTime) + ' seconds.') self.done.emit() self.importProgressWidget.hide() self.schedule.emit(parser, self.output == '') # call the scheduler (if there is no terminal output it means we imported nmap) diff --git a/app/processmodels.py b/app/processmodels.py index 12346e80..905ef57f 100644 --- a/app/processmodels.py +++ b/app/processmodels.py @@ -52,7 +52,7 @@ def data(self, index, role): # this metho value = '' row = index.row() column = index.column() - processColumns = {0:'progress', 1:'display', 2:'elapsed', 3:'estimatedremaining', 4:'pid', 5:'name', 6:'tabtitle', 7:'hostip', 8:'port', 9:'protocol', 10:'command', 11:'starttime', 12:'endtime', 13:'outputfile', 14:'output', 15:'status', 16:'closed'} + processColumns = {0:'progress', 1:'display', 2:'elapsed', 3:'estimatedRemaining', 4:'pid', 5:'name', 6:'tabTitle', 7:'hostIp', 8:'port', 9:'protocol', 10:'command', 11:'startTime', 12:'endTime', 13:'outputfile', 14:'output', 15:'status', 16:'closed'} try: if column == 0: value = '' @@ -67,11 +67,11 @@ def data(self, index, role): # this metho else: pid = int(self.__processes[row]['pid']) elapsed = round(self.__controller.controller.processMeasurements.get(pid, 0), 2) - estimatedRemaining = int(self.__processes[row]['estimatedremaining']) - float(elapsed) + estimatedRemaining = int(self.__processes[row]['estimatedRemaining']) - float(elapsed) value = "{0:.2f}{1}".format(float(estimatedRemaining), "s") if estimatedRemaining >= 0 else 'Unknown' elif column == 6: - if not self.__processes[row]['tabtitle'] == '': - value = self.__processes[row]['tabtitle'] + if not self.__processes[row]['tabTitle'] == '': + value = self.__processes[row]['tabTitle'] else: value = self.__processes[row]['name'] elif column == 8: @@ -96,13 +96,13 @@ def sort(self, Ncol, order): self.layoutAboutToBeChanged.emit() array=[] - sortColumns = {5:'name', 6:'tabtitle', 11:'starttime', 12:'endtime'} + sortColumns = {5:'name', 6:'tabTitle', 11:'startTime', 12:'endTime'} field = sortColumns.get(int(Ncol)) or 'status' try: if Ncol == 7: for i in range(len(self.__processes)): - array.append(IP2Int(self.__processes[i]['hostip'])) + array.append(IP2Int(self.__processes[i]['hostIp'])) elif Ncol == 8: for i in range(len(self.__processes)): @@ -180,7 +180,7 @@ def getRowForDBId(self, dbid): # new return i def getIpForRow(self, row): - return self.__processes[row]['hostip'] + return self.__processes[row]['hostIp'] def getPortForRow(self, row): return self.__processes[row]['port'] diff --git a/app/scriptmodels.py b/app/scriptmodels.py index 457b87b8..9f5bbbd1 100644 --- a/app/scriptmodels.py +++ b/app/scriptmodels.py @@ -55,10 +55,10 @@ def data(self, index, role): # this metho if column == 0: value = self.__scripts[row]['id'] elif column == 1: - value = self.__scripts[row]['script_id'] + value = self.__scripts[row]['scriptId'] elif column == 2: - if self.__scripts[row]['port_id'] and self.__scripts[row]['protocol'] and not self.__scripts[row]['port_id'] == '' and not self.__scripts[row]['protocol'] == '': - value = self.__scripts[row]['port_id'] + '/' + self.__scripts[row]['protocol'] + if self.__scripts[row]['portId'] and self.__scripts[row]['protocol'] and not self.__scripts[row]['portId'] == '' and not self.__scripts[row]['protocol'] == '': + value = self.__scripts[row]['portId'] + '/' + self.__scripts[row]['protocol'] else: value = '' elif column == 3: @@ -72,10 +72,10 @@ def sort(self, Ncol, order): if Ncol == 1: for i in range(len(self.__scripts)): - array.append(self.__scripts[i]['script_id']) + array.append(self.__scripts[i]['scriptId']) if Ncol == 2: for i in range(len(self.__scripts)): - array.append(int(self.__scripts[i]['port_id'])) + array.append(int(self.__scripts[i]['portId'])) sortArrayWithArray(array, self.__scripts) # sort the services based on the values in the array diff --git a/app/servicemodels.py b/app/servicemodels.py index 5d9225d5..de680265 100644 --- a/app/servicemodels.py +++ b/app/servicemodels.py @@ -62,17 +62,17 @@ def data(self, index, role): # this metho if column == 0: value = ' ' + self.__services[row]['ip'] # the spaces are needed for spacing with the icon that precedes the text elif column == 1: - value = self.__services[row]['port_id'] + value = self.__services[row]['portId'] elif column == 2: - value = ' ' + self.__services[row]['port_id'] # the spaces are needed for spacing with the icon that precedes the text + value = ' ' + self.__services[row]['portId'] # the spaces are needed for spacing with the icon that precedes the text elif column == 3: value = self.__services[row]['protocol'] elif column == 4: value = self.__services[row]['state'] elif column == 5: - value = self.__services[row]['host_id'] + value = self.__services[row]['hostId'] elif column == 6: - value = self.__services[row]['service_id'] + value = self.__services[row]['serviceId'] elif column == 7: value = self.__services[row]['name'] elif column == 8: @@ -105,11 +105,11 @@ def sort(self, Ncol, order): # sort funct elif Ncol == 1: # if sorting by port for i in range(len(self.__services)): - array.append(int(self.__services[i]['port_id'])) + array.append(int(self.__services[i]['portId'])) elif Ncol == 2: # if sorting by port for i in range(len(self.__services)): - array.append(int(self.__services[i]['port_id'])) + array.append(int(self.__services[i]['portId'])) elif Ncol == 3: # if sorting by protocol for i in range(len(self.__services)): @@ -146,7 +146,7 @@ def sort(self, Ncol, order): # sort funct ### getter functions ### def getPortForRow(self, row): - return self.__services[row]['port_id'] + return self.__services[row]['portId'] def getServiceNameForRow(self, row): return self.__services[row]['name'] diff --git a/controller/controller.py b/controller/controller.py index 36e3e747..3ba0e689 100644 --- a/controller/controller.py +++ b/controller/controller.py @@ -27,14 +27,14 @@ class Controller(): @timing def __init__(self, view, logic): self.name = "LEGION" - self.version = '0.3.4' - self.build = '1557101410' + self.version = '0.3.5' + self.build = '1557145534' self.author = 'GoVanguard' self.copyright = '2019' self.links = ['http://github.com/GoVanguard/legion/issues', 'https://GoVanguard.io/legion'] self.emails = [] - self.update = '05/05/2019' + self.update = '05/06/2019' self.license = "GPL v3" self.desc = "Legion is a fork of SECFORCE's Sparta, Legion is an open source, easy-to-use, \nsuper-extensible and semi-automated network penetration testing tool that aids in discovery, \nreconnaissance and exploitation of information systems." @@ -49,6 +49,7 @@ def __init__(self, view, logic): self.loadSettings() # creation of context menu actions from settings file and set up of various settings self.initNmapImporter() + self.initShodanImporter() self.initScreenshooter() self.initBrowserOpener() self.start() # initialisations (globals, etc) @@ -63,14 +64,21 @@ def start(self, title='*untitled'): self.fastProcessesRunning = 0 # counts the number of fast processes currently running self.slowProcessesRunning = 0 # counts the number of slow processes currently running self.nmapImporter.setDB(self.logic.db) # tell nmap importer which db to use + self.shodanImporter.setDB(self.logic.db) self.updateOutputFolder() # tell screenshooter where the output folder is self.view.start(title) def initNmapImporter(self): self.nmapImporter = NmapImporter() - self.nmapImporter.done.connect(self.nmapImportFinished) + self.nmapImporter.done.connect(self.importFinished) self.nmapImporter.schedule.connect(self.scheduler) # run automated attacks self.nmapImporter.log.connect(self.view.ui.LogOutputTextView.append) + + def initShodanImporter(self): + self.shodanImporter = ShodanImporter() + self.shodanImporter.done.connect(self.importFinished) + self.shodanImporter.schedule.connect(self.scheduler) # run automated attacks + self.shodanImporter.log.connect(self.view.ui.LogOutputTextView.append) def initScreenshooter(self): self.screenshooter = Screenshooter(self.settings.general_screenshooter_timeout) # screenshot taker object (different thread) @@ -321,8 +329,8 @@ def handleHostAction(self, ip, hostid, actions, action): if self.logic.getPortsForHostFromDB(ip, proto): # if we are running nmap we need to purge previous portscan results (of the same protocol) self.logic.deleteAllPortsAndScriptsForHostFromDB(hostid, proto) - tabtitle = self.settings.hostActions[i][1] - self.runCommand(name, tabtitle, ip, '','', command, getTimestamp(True), outputfile, self.view.createNewTabForHost(ip, tabtitle, invisibleTab)) + tabTitle = self.settings.hostActions[i][1] + self.runCommand(name, tabTitle, ip, '','', command, getTimestamp(True), outputfile, self.view.createNewTabForHost(ip, tabTitle, invisibleTab)) break @timing @@ -369,7 +377,7 @@ def handleServiceNameAction(self, targets, actions, action, restoring=True): srvc_num = actions[i][0] for ip in targets: tool = self.settings.portActions[srvc_num][1] - tabtitle = self.settings.portActions[srvc_num][1]+" ("+ip[1]+"/"+ip[2]+")" + tabTitle = self.settings.portActions[srvc_num][1]+" ("+ip[1]+"/"+ip[2]+")" outputfile = self.logic.runningfolder+"/"+re.sub("[^0-9a-zA-Z]", "", str(tool))+"/"+getTimestamp()+'-'+tool+"-"+ip[0]+"-"+ip[1] command = str(self.settings.portActions[srvc_num][2]) @@ -378,10 +386,10 @@ def handleServiceNameAction(self, targets, actions, action, restoring=True): if 'nmap' in command and ip[2] == 'udp': command=command.replace("-sV","-sVU") - if 'nmap' in tabtitle: # we don't want to show nmap tabs + if 'nmap' in tabTitle: # we don't want to show nmap tabs restoring = True - self.runCommand(tool, tabtitle, ip[0], ip[1], ip[2], command, getTimestamp(True), outputfile, self.view.createNewTabForHost(ip[0], tabtitle, restoring)) + self.runCommand(tool, tabTitle, ip[0], ip[1], ip[2], command, getTimestamp(True), outputfile, self.view.createNewTabForHost(ip[0], tabTitle, restoring)) break @timing @@ -583,19 +591,19 @@ def handleProcUpdate(*vargs): self.processMeasurements[qProcess.pid()] = procTime name = args[0] - tabtitle = args[1] - hostip = args[2] + tabTitle = args[1] + hostIp = args[2] port = args[3] protocol = args[4] command = args[5] - starttime = args[6] + startTime = args[6] outputfile = args[7] textbox = args[8] timer = QtCore.QTime() updateElapsed = QTimer() self.logic.createFolderForTool(name) - qProcess = MyQProcess(name, tabtitle, hostip, port, protocol, command, starttime, outputfile, textbox) + qProcess = MyQProcess(name, tabTitle, hostIp, port, protocol, command, startTime, outputfile, textbox) qProcess.started.connect(timer.start) qProcess.finished.connect(handleProcStop) updateElapsed.timeout.connect(handleProcUpdate) @@ -624,21 +632,21 @@ def handleProcUpdate(*vargs): if stage > 0 and stage < 6: # if this is a staged nmap, launch the next stage log.info("runCommand connected for stage {0}".format(str(stage))) nextStage = stage + 1 - qProcess.finished.connect(lambda: self.runStagedNmap(str(hostip), discovery = discovery, stage = nextStage, stop = self.logic.isKilledProcess(str(qProcess.id)))) + qProcess.finished.connect(lambda: self.runStagedNmap(str(hostIp), discovery = discovery, stage = nextStage, stop = self.logic.isKilledProcess(str(qProcess.id)))) return qProcess.pid() # return the pid so that we can kill the process if needed def runPython(self): textbox = self.view.createNewConsole("python") name = 'python' - tabtitle = name - hostip = '127.0.0.1' + tabTitle = name + hostIp = '127.0.0.1' port = '22' protocol = 'tcp' command = 'python3 /mnt/c/Users/hackm/OneDrive/Documents/Customers/GVIT/GIT/legion/test.py' - starttime = getTimestamp(True) + startTime = getTimestamp(True) outputfile = '/tmp/a' - qProcess = MyQProcess(name, tabtitle, hostip, port, protocol, command, starttime, outputfile, textbox) + qProcess = MyQProcess(name, tabTitle, hostIp, port, protocol, command, startTime, outputfile, textbox) textbox.setProperty('dbId', str(self.logic.addProcessToDB(qProcess))) @@ -698,7 +706,7 @@ def runStagedNmap(self, targetHosts, discovery = True, stage = 1, stop = False): self.runCommand('nmap','nmap (stage '+str(stage)+')', str(targetHosts), '', '', command, getTimestamp(True), outputfile, textbox, discovery = discovery, stage = stage, stop = stop) - def nmapImportFinished(self): + def importFinished(self): self.updateUI2Timer.stop() self.updateUI2Timer.start(800) self.view.displayAddHostsOverlay(False) # if nmap import was the first action, we need to hide the overlay (note: we shouldn't need to do this everytime. this can be improved) @@ -771,10 +779,10 @@ def scheduler(self, parser, isNmapImport): if self.settings.general_enable_scheduler == 'True': log.info('Scheduler started!') - for h in parser.all_hosts(): + for h in parser.getAllHosts(): for p in h.all_ports(): if p.state == 'open': - s = p.get_service() + s = p.getService() if not (s is None): self.runToolsFor(s.name, h.ip, p.portId, p.protocol) @@ -798,16 +806,16 @@ def runToolsFor(self, service, ip, port, protocol='tcp'): for a in self.settings.portActions: if tool[0] == a[1]: restoring = False - tabtitle = a[1]+" ("+port+"/"+protocol+")" + tabTitle = a[1]+" ("+port+"/"+protocol+")" outputfile = self.logic.runningfolder+"/"+re.sub("[^0-9a-zA-Z]", "", str(tool[0]))+"/"+getTimestamp()+'-'+a[1]+"-"+ip+"-"+port command = str(a[2]) command = command.replace('[IP]', ip).replace('[PORT]', port).replace('[OUTPUT]', outputfile) log.debug("Running tool command " + str(command)) - if 'nmap' in tabtitle: # we don't want to show nmap tabs + 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'))) + self.runCommand(tool[0], tabTitle, ip, port, protocol, command, getTimestamp(True), outputfile, self.view.createNewTabForHost(ip, tabTitle, not (tab == 'Hosts'))) break diff --git a/db/database.py b/db/database.py index cf6435c5..08e7b438 100644 --- a/db/database.py +++ b/db/database.py @@ -35,14 +35,14 @@ class process(Base): id = Column(Integer, primary_key = True) display = Column(String) name = Column(String) - tabtitle = Column(String) - hostip = Column(String) + tabTitle = Column(String) + hostIp = Column(String) port = Column(String) protocol = Column(String) command = Column(String) - starttime = Column(String) - endtime = Column(String) - estimatedremaining = Column(Integer) + startTime = Column(String) + endTime = Column(String) + estimatedRemaining = Column(Integer) elapsed = Column(Integer) outputfile = Column(String) output = relationship("process_output") @@ -53,41 +53,41 @@ def __init__(self, pid, *args): self.display = 'True' self.pid = pid self.name = args[0] - self.tabtitle = args[1] - self.hostip = args[2] + self.tabTitle = args[1] + self.hostIp = args[2] self.port = args[3] self.protocol = args[4] self.command = args[5] - self.starttime = args[6] - self.endtime = args[7] + self.startTime = args[6] + self.endTime = args[7] self.outputfile = args[8] self.output = args[10] self.status = args[9] self.closed = 'False' - self.estimatedremaining = args[11] + self.estimatedRemaining = args[11] self.elapsed = args[12] # This class holds various info about an nmap scan -class nmap_session(Base): - __tablename__ = 'nmap_session' +class nmapSessionObj(Base): + __tablename__ = 'nmapSessionObj' filename = Column(String, primary_key = True) - start_time = Column(String) + startTime = Column(String) finish_time = Column(String) - nmap_version = Column(String) - scan_args = Column(String) - total_hosts = Column(String) - up_hosts = Column(String) - down_hosts = Column(String) + nmapVersion = Column(String) + scanArgs = Column(String) + totalHosts = Column(String) + upHosts = Column(String) + downHosts = Column(String) def __init__(self, filename, *args, **kwargs): self.filename = filename - self.start_time = args[0] + self.startTime = args[0] self.finish_time = args[1] - self.nmap_version = kwargs.get('nmap_version') or 'unknown' - self.scan_args = kwargs.get('scan_args') or '' - self.total_hosts = kwargs.get('total_host') or '0' - self.up_hosts = kwargs.get('up_hosts') or '0' - self.down_hosts = kwargs.get('down_hosts') or '0' + self.nmapVersion = kwargs.get('nmapVersion') or 'unknown' + self.scanArgs = kwargs.get('scanArgs') or '' + self.totalHosts = kwargs.get('total_host') or '0' + self.upHosts = kwargs.get('upHosts') or '0' + self.downHosts = kwargs.get('downHosts') or '0' class osObj(Base): @@ -96,36 +96,36 @@ class osObj(Base): name = Column(String) family = Column(String) generation = Column(String) - os_type = Column(String) + osType = Column(String) vendor = Column(String) accuracy = Column(String) - host_id = Column(String, ForeignKey('hostObj.id')) + hostId = Column(String, ForeignKey('hostObj.id')) def __init__(self, name, *args): self.name = name self.family = args[0] self.generation = args[1] - self.os_type = args[2] + self.osType = args[2] self.vendor = args[3] self.accuracy = args[4] - self.host_id = args[5] + self.hostId = args[5] class portObj(Base): __tablename__ = 'portObj' - port_id = Column(String) + portId = Column(String) id = Column(Integer, primary_key = True) protocol = Column(String) state = Column(String) - host_id = Column(String, ForeignKey('hostObj.id')) - service_id = Column(String, ForeignKey('serviceObj.id')) - script_id = Column(String, ForeignKey('l1ScriptObj.id')) + hostId = Column(String, ForeignKey('hostObj.id')) + serviceId = Column(String, ForeignKey('serviceObj.id')) + scriptId = Column(String, ForeignKey('l1ScriptObj.id')) - def __init__(self, port_id, protocol, state, host, service = ''): - self.port_id = port_id + def __init__(self, portId, protocol, state, host, service = ''): + self.portId = portId self.protocol = protocol self.state = state - self.service_id = service - self.host_id = host + self.serviceId = service + self.hostId = host class cve(Base): __tablename__ = 'cve' @@ -136,23 +136,23 @@ class cve(Base): severity = Column(String) source = Column(String) version = Column(String) - edbid = Column(Integer) + exploitId = Column(Integer) exploit = Column(String) exploitUrl = Column(String) - service_id = Column(String, ForeignKey('serviceObj.id')) - host_id = Column(String, ForeignKey('hostObj.id')) + serviceId = Column(String, ForeignKey('serviceObj.id')) + hostId = Column(String, ForeignKey('hostObj.id')) - def __init__(self, name, url, product, hostId, severity = '', source = '', version = ''): + def __init__(self, name, url, product, hostId, severity = '', source = '', version = '', exploitId = 0, exploit = '', exploitUrl = ''): self.url = url self.name = name self.product = product self.severity = severity self.source = source self.version = version - self.edbid = 0 - self.exploit = '' - self.exploitUrl = '' - self.host_id = hostId + self.exploitId = exploitId + self.exploit = exploit + self.exploitUrl = exploitUrl + self.hostId = hostId class appObj(Base): __tablename__ = 'appObj' @@ -163,7 +163,7 @@ class appObj(Base): extrainfo = Column(String) fingerprint = Column(String) cpe = Column(String) - service_id = Column(String, ForeignKey('serviceObj.id')) + serviceId = Column(String, ForeignKey('serviceObj.id')) def __init__(self, name = '', product = '', version = '', extrainfo = '', fingerprint = '', cpe = ''): self.name = name @@ -194,53 +194,74 @@ def __init__(self, name = '', product = '', version = '', extrainfo = '', finger class l1ScriptObj(Base): __tablename__ = 'l1ScriptObj' - script_id = Column(String) + scriptId = Column(String) id = Column(Integer, primary_key = True) output = Column(String) - port_id = Column(String, ForeignKey('portObj.id')) - host_id = Column(String, ForeignKey('hostObj.id')) + portId = Column(String, ForeignKey('portObj.id')) + hostId = Column(String, ForeignKey('hostObj.id')) - def __init__(self, script_id, output, portId, hostId): - self.script_id = script_id + def __init__(self, scriptId, output, portId, hostId): + self.scriptId = scriptId self.output = unicode(output) - self.port_id = portId - self.host_id = hostId + self.portId = portId + self.hostId = hostId class l2ScriptObj(Base): __tablename__ = 'l2ScriptObj' - script_id = Column(String) + scriptId = Column(String) id = Column(Integer, primary_key = True) output = Column(String) - port_id = Column(String, ForeignKey('portObj.id')) - host_id = Column(String, ForeignKey('hostObj.id')) + portId = Column(String, ForeignKey('portObj.id')) + hostId = Column(String, ForeignKey('hostObj.id')) - def __init__(self, script_id, output, portId, hostId): - self.script_id = script_id + def __init__(self, scriptId, output, portId, hostId): + self.scriptId = scriptId self.output = unicode(output) - self.port_id = portId - self.host_id = hostId + self.portId = portId + self.hostId = hostId class hostObj(Base): __tablename__ = 'hostObj' + # State + state = Column(String) + count = Column(String) checked = Column(String) - os_match = Column(String) - os_accuracy = Column(String) + + # OS + osMatch = Column(String) + osAccuracy = Column(String) + vendor = Column(String) + uptime = Column(String) + lastboot = Column(String) + + # Network + isp = Column(String) + asn = Column(String) ip = Column(String) ipv4 = Column(String) ipv6 = Column(String) macaddr = Column(String) status = Column(String) hostname = Column(String) - host_id = Column(String) + + # ID + hostId = Column(String) id = Column(Integer, primary_key = True) - vendor = Column(String) - uptime = Column(String) - lastboot = Column(String) - distance = Column(String) - state = Column(String) count = Column(String) + # Location + city = Column(String) + countryCode = Column(String) + postalCode = Column(String) + longitude = Column(String) + latitude = Column(String) + distance = Column(String) + + # Network + isp = Column(String) + asn = Column(String) + # host relationships os = relationship(osObj) ports = relationship(portObj) @@ -248,15 +269,15 @@ class hostObj(Base): def __init__(self, **kwargs): self.checked = kwargs.get('checked') or 'False' - self.os_match = kwargs.get('os_match') or 'unknown' - self.os_accuracy = kwargs.get('os_accuracy') or 'NaN' + self.osMatch = kwargs.get('osMatch') or 'unknown' + self.osAccuracy = kwargs.get('osAccuracy') or 'NaN' self.ip = kwargs.get('ip') or 'unknown' self.ipv4 = kwargs.get('ipv4') or 'unknown' self.ipv6 = kwargs.get('ipv6') or 'unknown' self.macaddr = kwargs.get('macaddr') or 'unknown' self.status = kwargs.get('status') or 'unknown' self.hostname = kwargs.get('hostname') or 'unknown' - self.host_id = kwargs.get('hostname') or 'unknown' + self.hostId = kwargs.get('hostname') or 'unknown' self.vendor = kwargs.get('vendor') or 'unknown' self.uptime = kwargs.get('uptime') or 'unknown' self.lastboot = kwargs.get('lastboot') or 'unknown' @@ -267,17 +288,17 @@ def __init__(self, **kwargs): class note(Base): __tablename__ = 'note' - host_id = Column(Integer, ForeignKey('hostObj.id')) + hostId = Column(Integer, ForeignKey('hostObj.id')) id = Column(Integer, primary_key = True) text = Column(String) def __init__(self, hostId, text): self.text = unicode(text) - self.host_id = hostId + self.hostId = hostId class process_output(Base): __tablename__ = 'process_output' - process_id = Column(Integer, ForeignKey('process.id')) + processId = Column(Integer, ForeignKey('process.id')) id = Column(Integer, primary_key = True) output = Column(String) @@ -338,8 +359,3 @@ def commit(self): pass self.dbsemaphore.release() log.info("DB lock released") - - -if __name__ == "__main__": - - db = Database('myDatabase') diff --git a/debian/changelog b/debian/changelog index 2eb72d15..7530497c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -legion (0.3.4-1) UNRELEASED; urgency=medium +legion (0.3.5-0) UNRELEASED; urgency=medium * Initial release. (Closes: #XXXXXX) diff --git a/debian/watch b/debian/watch index 2980909d..dfd6aac5 100644 --- a/debian/watch +++ b/debian/watch @@ -1,3 +1,3 @@ -version=3.4.0 +version=3.5.0 opts="filenamemangle=s/.*\/v(\d.*).tar.gz/legion-$1.tar.gz/" \ https://github.com/GoVanguard/Legion/releases .*/v(\d.*)\.tar\.gz diff --git a/deps/detectScripts.sh b/deps/detectScripts.sh index 8eb55424..eddbe878 100644 --- a/deps/detectScripts.sh +++ b/deps/detectScripts.sh @@ -66,13 +66,6 @@ else git clone https://github.com/m0rtem/CloudFail.git scripts/CloudFail fi -if [ -a scripts/exploutdb/searchsploit ] - then - echo "Exploit-db has been found" -else - git clone https://github.com/offensive-security/exploitdb.git scripts/exploitdb -fi - if [ ! -f ".initialized" ] then scripts/installDeps.sh diff --git a/deps/installDeps.sh b/deps/installDeps.sh index dc9cfcc5..f87b322b 100644 --- a/deps/installDeps.sh +++ b/deps/installDeps.sh @@ -9,4 +9,4 @@ source ./deps/apt.sh apt-get update -m echo "Installing deps..." -DEBIAN_FRONTEND="noninteractive" apt-get -yqqq --allow-unauthenticated --force-yes -o DPkg::Options::="--force-overwrite" -o DPkg::Options::="--force-confdef" install nmap finger hydra nikto whatweb nbtscan nfs-common rpcbind smbclient sra-toolkit ldap-utils sslscan rwho medusa x11-apps cutycapt leafpad xvfb imagemagick eog hping3 sqlmap wapiti libqt5core5a python-pip python-impacket ruby perl dnsmap urlscan git +DEBIAN_FRONTEND="noninteractive" apt-get -yqqqm --allow-unauthenticated --force-yes -o DPkg::Options::="--force-overwrite" -o DPkg::Options::="--force-confdef" install nmap finger hydra nikto whatweb nbtscan nfs-common rpcbind smbclient sra-toolkit ldap-utils sslscan rwho medusa x11-apps cutycapt leafpad xvfb imagemagick eog hping3 sqlmap wapiti libqt5core5a python-pip python-impacket ruby perl dnsmap urlscan git xsltproc diff --git a/deps/installPythonLibs.sh b/deps/installPythonLibs.sh index b8123336..90e91797 100644 --- a/deps/installPythonLibs.sh +++ b/deps/installPythonLibs.sh @@ -3,5 +3,5 @@ source ./deps/detectPython.sh # Setup Python deps -${PIP3BIN} install -r requirements.txt -${PIP3BIN} install service_identity --upgrade +${PIP3BIN} install -r requirements.txt --upgrade +${PIP3BIN} install service-identity --upgrade diff --git a/legion.conf b/legion.conf index e8e5ad53..bff5e3b1 100644 --- a/legion.conf +++ b/legion.conf @@ -9,7 +9,7 @@ store-cleartext-passwords-on-exit=True username-wordlist-path=/usr/share/wordlists/ [GUISettings] -process-tab-column-widths="125,0,74,92,67,0,124,130,0,0,0,0,0,0,0,964,100" +process-tab-column-widths="125,0,74,92,67,0,124,130,0,0,0,0,0,0,0,554,100" process-tab-detail=False [GeneralSettings] @@ -29,6 +29,8 @@ nmap-fast-tcp=Run nmap (fast TCP), nmap -Pn -sV -sC -F -T4 -vvvv [IP] -oA \"[OUT nmap-fast-udp=Run nmap (fast UDP), "nmap -n -Pn -sU -F --min-rate=1000 -vvvvv [IP] -oA \"[OUTPUT]\"" nmap-full-tcp=Run nmap (full TCP), nmap -Pn -sV -sC -O -p- -T4 -vvvvv [IP] -oA \"[OUTPUT]\" nmap-full-udp=Run nmap (full UDP), nmap -n -Pn -sU -p- -T4 -vvvvv [IP] -oA \"[OUTPUT]\" +nmap-script-Shodan=Run nmap script - Shodan, "nmap -sn -Pn -n --script=./scripts/nmap/shodan-api.nse --script-args shodan-api.apikey=SNYEkE0gdwNu9BRURVDjWPXePCquXqht [IP] -vvvv -oA [OUTPUT]" +nmap-script-Shodan-HQ=Run nmap script - Shodan HQ, "nmap -sn -Pn -n --script=./scripts/nmap/shodan-hq.nse --script-args apikey=SNYEkE0gdwNu9BRURVDjWPXePCquXqht [IP] -vvvv -oA [OUTPUT]" nmap-script-Vulners=Run nmap script - Vulners, "nmap -sV --script=./scripts/nmap/vulners.nse -vvvv [IP] -oA \"[OUTPUT]\"" nmap-udp-1000=Run nmap (top 1000 quick UDP), "nmap -n -Pn -sU --min-rate=1000 -vvvvv [IP] -oA \"[OUTPUT]\"" unicornscan-full-udp=Run unicornscan (full UDP), unicornscan -mU -Ir 1000 [IP]:a -v diff --git a/parsers/CVE.py b/parsers/CVE.py index 0e1b3e40..41736923 100644 --- a/parsers/CVE.py +++ b/parsers/CVE.py @@ -10,6 +10,9 @@ class CVE: url = '' source = '' severity = '' + exploitId = '' + exploit = '' + exploitUrl = '' def __init__(self, cveData): self.name = cveData['id'] @@ -18,3 +21,6 @@ def __init__(self, cveData): self.url = cveData['url'] self.source = cveData['source'] self.severity = cveData['severity'] + self.exploitId = cveData['exploitId'] + self.exploit = cveData['exploit'] + self.exploitUrl = cveData['exploitUrl'] diff --git a/parsers/Host.py b/parsers/Host.py index 631ca434..145e7039 100644 --- a/parsers/Host.py +++ b/parsers/Host.py @@ -13,132 +13,133 @@ import xml.dom.minidom class Host: - ipv4 = '' - ipv6 = '' - macaddr = '' - status = 'none' - hostname = '' - vendor = '' - uptime = '' - lastboot = '' - distance = 0 - state = '' - count = '' - - def __init__( self, HostNode ): - self.host_node = HostNode - self.status = HostNode.getElementsByTagName('status')[0].getAttribute('state') - for e in HostNode.getElementsByTagName('address'): - if e.getAttribute('addrtype') == 'ipv4': - self.ipv4 = e.getAttribute('addr') - elif e.getAttribute('addrtype') == 'ipv6': - self.ipv6 = e.getAttribute('addr') - elif e.getAttribute('addrtype') == 'mac': - self.macaddr = e.getAttribute('addr') - self.vendor = e.getAttribute('vendor') - #self.ip = HostNode.getElementsByTagName('address')[0].getAttribute('addr'); - self.ip = self.ipv4 # for compatibility with the original library - if len(HostNode.getElementsByTagName('hostname')) > 0: - self.hostname = HostNode.getElementsByTagName('hostname')[0].getAttribute('name') - if len(HostNode.getElementsByTagName('uptime')) > 0: - self.uptime = HostNode.getElementsByTagName('uptime')[0].getAttribute('seconds') - self.lastboot = HostNode.getElementsByTagName('uptime')[0].getAttribute('lastboot') - if len(HostNode.getElementsByTagName('distance')) > 0: - self.distance = int(HostNode.getElementsByTagName('distance')[0].getAttribute('value')) - if len(HostNode.getElementsByTagName('extraports')) > 0: - self.state = HostNode.getElementsByTagName('extraports')[0].getAttribute('state') - self.count = HostNode.getElementsByTagName('extraports')[0].getAttribute('count') - - def get_OS(self): - oss = [] - - for OS_node in self.host_node.getElementsByTagName('osclass'): - os = OS.OS(OS_node) - oss.append(os) - - for OS_node in self.host_node.getElementsByTagName('osmatch'): - os = OS.OS(OS_node) - oss.append(os) - - return oss - - def all_ports( self ): - - ports = [ ] - - for port_node in self.host_node.getElementsByTagName('port'): - p = Port.Port(port_node) - ports.append(p) - - return ports - - def get_ports( self, protocol, state ): - '''get a list of ports which is in the special state''' - - open_ports = [ ] - - for port_node in self.host_node.getElementsByTagName('port'): - if port_node.getAttribute('protocol') == protocol and port_node.getElementsByTagName('state')[0].getAttribute('state') == state: - open_ports.append( port_node.getAttribute('portid') ) - - return open_ports - - def get_scripts( self ): - - scripts = [ ] - - for script_node in self.host_node.getElementsByTagName('script'): - scr = Script.Script(script_node) - scripts.append(scr) - - return scripts - - def get_hostscripts( self ): - - scripts = [ ] - for hostscript_node in self.host_node.getElementsByTagName('hostscript'): - for script_node in hostscript_node.getElementsByTagName('script'): - scr = Script.Script(script_node) - scripts.append(scr) - - return scripts - - def get_service( self, protocol, port ): - '''return a Service object''' - - for port_node in self.host_node.getElementsByTagName('port'): - if port_node.getAttribute('protocol') == protocol and port_node.getAttribute('portid') == port: - if (len(port_node.getElementsByTagName('service'))) > 0: - service_node = port_node.getElementsByTagName('service')[0] - service = Service.Service( service_node ) - return service - return None + ipv4 = '' + ipv6 = '' + macaddr = '' + status = 'none' + hostname = '' + vendor = '' + uptime = '' + lastboot = '' + distance = 0 + state = '' + count = '' + + def __init__( self, HostNode ): + self.hostNode = HostNode + self.status = HostNode.getElementsByTagName('status')[0].getAttribute('state') + for e in HostNode.getElementsByTagName('address'): + if e.getAttribute('addrtype') == 'ipv4': + self.ipv4 = e.getAttribute('addr') + elif e.getAttribute('addrtype') == 'ipv6': + self.ipv6 = e.getAttribute('addr') + elif e.getAttribute('addrtype') == 'mac': + self.macaddr = e.getAttribute('addr') + self.vendor = e.getAttribute('vendor') + #self.ip = HostNode.getElementsByTagName('address')[0].getAttribute('addr'); + self.ip = self.ipv4 # for compatibility with the original library + if len(HostNode.getElementsByTagName('hostname')) > 0: + self.hostname = HostNode.getElementsByTagName('hostname')[0].getAttribute('name') + if len(HostNode.getElementsByTagName('uptime')) > 0: + self.uptime = HostNode.getElementsByTagName('uptime')[0].getAttribute('seconds') + self.lastboot = HostNode.getElementsByTagName('uptime')[0].getAttribute('lastboot') + if len(HostNode.getElementsByTagName('distance')) > 0: + self.distance = int(HostNode.getElementsByTagName('distance')[0].getAttribute('value')) + if len(HostNode.getElementsByTagName('extraports')) > 0: + self.state = HostNode.getElementsByTagName('extraports')[0].getAttribute('state') + self.count = HostNode.getElementsByTagName('extraports')[0].getAttribute('count') + + def getOs(self): + oss = [] + + for osNode in self.hostNode.getElementsByTagName('osclass'): + os = OS.OS(osNode) + oss.append(os) + + for osNode in self.hostNode.getElementsByTagName('osmatch'): + os = OS.OS(osNode) + oss.append(os) + + return oss + + def all_ports( self ): + + ports = [] + + for portNode in self.hostNode.getElementsByTagName('port'): + p = Port.Port(portNode) + ports.append(p) + + return ports + + def getPorts( self, protocol, state ): + '''get a list of ports which is in the special state''' + + open_ports = [] + + for portNode in self.hostNode.getElementsByTagName('port'): + if portNode.getAttribute('protocol') == protocol and portNode.getElementsByTagName('state')[0].getAttribute('state') == state: + open_ports.append( portNode.getAttribute('portid') ) + + return open_ports + + def getScripts( self ): + + scripts = [] + + for scriptNode in self.hostNode.getElementsByTagName('script'): + scr = Script.Script(scriptNode) + scr.hostId = self.ipv4 + scripts.append(scr) + + return scripts + + def getHostScripts( self ): + + scripts = [] + for hostscriptNode in self.hostNode.getElementsByTagName('hostscript'): + for scriptNode in hostscriptNode.getElementsByTagName('script'): + scr = Script.Script(scriptNode) + scripts.append(scr) + + return scripts + + def getService( self, protocol, port ): + '''return a Service object''' + + for portNode in self.hostNode.getElementsByTagName('port'): + if portNode.getAttribute('protocol') == protocol and portNode.getAttribute('portid') == port: + if (len(portNode.getElementsByTagName('service'))) > 0: + service_node = portNode.getElementsByTagName('service')[0] + service = Service.Service( service_node ) + return service + return None if __name__ == '__main__': dom = xml.dom.minidom.parse('/tmp/test_pwn01.xml') - host_nodes = dom.getElementsByTagName('host') + hostNodes = dom.getElementsByTagName('host') - if len(host_nodes) == 0: + if len(hostNodes) == 0: sys.exit( ) - host_node = dom.getElementsByTagName('host')[0] + hostNode = dom.getElementsByTagName('host')[0] - h = Host( host_node ) + h = Host( hostNode ) log.info('host status: ' + h.status) log.info('host ip: ' + h.ip) - for port in h.get_ports( 'tcp', 'open' ): + for port in h.getPorts( 'tcp', 'open' ): log.info(port + " is open") log.info("script output:") - for scr in h.get_scripts(): + for scr in h.getScripts(): log.info("script id:" + scr.scriptId) log.info("Output:") log.info(scr.output) log.info("service of tcp port 80:") - s = h.get_service( 'tcp', '80' ) + s = h.getService( 'tcp', '80' ) if s == None: log.info("\tno service") diff --git a/parsers/OS.py b/parsers/OS.py index 602deb14..01808ac2 100644 --- a/parsers/OS.py +++ b/parsers/OS.py @@ -11,7 +11,7 @@ class OS: name = '' family = '' generation = '' - os_type = '' + osType = '' vendor = '' accuracy = 0 @@ -20,7 +20,7 @@ def __init__(self, OSNode): self.name = OSNode.getAttribute('name') self.family = OSNode.getAttribute('osfamily') self.generation = OSNode.getAttribute('osgen') - self.os_type = OSNode.getAttribute('type') + self.osType = OSNode.getAttribute('type') self.vendor = OSNode.getAttribute('vendor') self.accuracy = OSNode.getAttribute('accuracy') @@ -37,7 +37,7 @@ def __init__(self, OSNode): log.info(os.name) log.info(os.family) log.info(os.generation) - log.info(os.os_type) + log.info(os.osType) log.info(os.vendor) log.info(str(os.accuracy)) @@ -45,6 +45,6 @@ def __init__(self, OSNode): log.info(os.name) log.info(os.family) log.info(os.generation) - log.info(os.os_type) + log.info(os.osType) log.info(os.vendor) log.info(str(os.accuracy)) diff --git a/parsers/Parser.py b/parsers/Parser.py index cea4eee5..bc050e60 100644 --- a/parsers/Parser.py +++ b/parsers/Parser.py @@ -24,48 +24,48 @@ def __init__( self, xml_input): self.__dom = xml.dom.minidom.parse(xml_input) self.__session = None self.__hosts = { } - for host_node in self.__dom.getElementsByTagName('host'): - __host = Host.Host(host_node) + for hostNode in self.__dom.getElementsByTagName('host'): + __host = Host.Host(hostNode) self.__hosts[__host.ip] = __host except Exception as ex: log.info("Parser error! Invalid nmap file!") #logging.error(ex) raise - def get_session( self ): + def getSession( self ): '''get this scans information, return a Session object''' run_node = self.__dom.getElementsByTagName('nmaprun')[0] hosts_node = self.__dom.getElementsByTagName('hosts')[0] finish_time = self.__dom.getElementsByTagName('finished')[0].getAttribute('timestr') - nmap_version = run_node.getAttribute('version') - start_time = run_node.getAttribute('startstr') - scan_args = run_node.getAttribute('args') + nmapVersion = run_node.getAttribute('version') + startTime = run_node.getAttribute('startstr') + scanArgs = run_node.getAttribute('args') - total_hosts = hosts_node.getAttribute('total') - up_hosts = hosts_node.getAttribute('up') - down_hosts = hosts_node.getAttribute('down') + totalHosts = hosts_node.getAttribute('total') + upHosts = hosts_node.getAttribute('up') + downHosts = hosts_node.getAttribute('down') MySession = { 'finish_time': finish_time, - 'nmap_version' : nmap_version, - 'scan_args' : scan_args, - 'start_time' : start_time, - 'total_hosts' : total_hosts, - 'up_hosts' : up_hosts, - 'down_hosts' : down_hosts } + 'nmapVersion' : nmapVersion, + 'scanArgs' : scanArgs, + 'startTime' : startTime, + 'totalHosts' : totalHosts, + 'upHosts' : upHosts, + 'downHosts' : downHosts } self.__session = Session.Session( MySession ) return self.__session - def get_host( self, ipaddr ): + def getHost( self, ipaddr ): '''get a Host object by ip address''' return self.__hosts.get(ipaddr) - def all_hosts( self, status = '' ): + def getAllHosts( self, status = '' ): '''get a list of Host object''' @@ -82,7 +82,7 @@ def all_hosts( self, status = '' ): return __tmp_hosts - def all_ips( self, status = '' ): + def getAllIps( self, status = '' ): '''get a list of ip address''' __tmp_ips = [ ] @@ -105,24 +105,24 @@ def all_ips( self, status = '' ): parser = Parser( 'a-full.xml' ) log.info('\nscan session:') - session = parser.get_session() - log.info("\tstart time:\t" + session.start_time) + session = parser.getSession() + log.info("\tstart time:\t" + session.startTime) log.info("\tstop time:\t" + session.finish_time) - log.info("\tnmap version:\t" + session.nmap_version) - log.info("\tnmap args:\t" + session.scan_args) - log.info("\ttotal hosts:\t" + session.total_hosts) - log.info("\tup hosts:\t" + session.up_hosts) - log.info("\tdown hosts:\t" + session.down_hosts) + log.info("\tnmap version:\t" + session.nmapVersion) + log.info("\tnmap args:\t" + session.scanArgs) + log.info("\ttotal hosts:\t" + session.totalHosts) + log.info("\tup hosts:\t" + session.upHosts) + log.info("\tdown hosts:\t" + session.downHosts) - for h in parser.all_hosts(): + for h in parser.getAllHosts(): log.info('host ' +h.ip + ' is ' + h.status) - for port in h.get_ports( 'tcp', 'open' ): + for port in h.getPorts( 'tcp', 'open' ): print(port) log.info("\t---------------------------------------------------") log.info("\tservice of tcp port " + port + ":") - s = h.get_service( 'tcp', port ) + s = h.getService( 'tcp', port ) if s == None: log.info("\t\tno service") @@ -135,7 +135,7 @@ def all_ips( self, status = '' ): log.info("\t\t" + s.fingerprint) log.info("\tscript output:") - sc = port.get_scripts() + sc = port.getScripts() if sc == None: log.info("\t\tno scripts") diff --git a/parsers/Port.py b/parsers/Port.py index c1f0e415..ae8cc120 100644 --- a/parsers/Port.py +++ b/parsers/Port.py @@ -15,14 +15,14 @@ class Port: def __init__(self, PortNode): if not (PortNode is None): - self.port_node = PortNode + self.portNode = PortNode self.portId = PortNode.getAttribute('portid') self.protocol = PortNode.getAttribute('protocol') self.state = PortNode.getElementsByTagName('state')[0].getAttribute('state') - def get_service(self): + def getService(self): - service_node = self.port_node.getElementsByTagName('service') + service_node = self.portNode.getElementsByTagName('service') if len(service_node) > 0: return Service.Service(service_node[0]) @@ -32,7 +32,7 @@ def get_service(self): # def get_cpe(self): # cpes = [] - # cpe = self.port_node.getElementsByTagName('cpe') + # cpe = self.portNode.getElementsByTagName('cpe') # print(cpe) # if len(cpe) > 0: @@ -40,12 +40,12 @@ def get_service(self): # return None - def get_scripts(self): + def getScripts(self): scripts = [ ] - for script_node in self.port_node.getElementsByTagName('script'): - scr = Script.Script(script_node) + for scriptNode in self.portNode.getElementsByTagName('script'): + scr = Script.Script(scriptNode) scripts.append(scr) return scripts diff --git a/parsers/Script.py b/parsers/Script.py index 6a332fe6..76e48ec4 100644 --- a/parsers/Script.py +++ b/parsers/Script.py @@ -7,6 +7,7 @@ import sys import xml.dom.minidom import parsers.CVE as CVE +from db.database import * from pyExploitDb import PyExploitDb class Script: @@ -18,11 +19,16 @@ def __init__(self, ScriptNode): self.scriptId = ScriptNode.getAttribute('id') self.output = ScriptNode.getAttribute('output') - def getExploitDataFromCves(self, cveSet): - for cveEntry in cveSet: - print("CVE Entry: {0}".format(cveEntry)) - cveExploitData = self.pyExploitDb.searchCve(cveEntry(0)) - print("CVE Exploit Data: {0}".format(cveExploitData)) + def processShodanScriptOutput(self, shodanOutput): + output = shodanOutput.replace('\t\t\t','\t') + output = output.replace('\t\t','\t') + output = output.replace('\t',';') + output = output.replace('\n;','\n') + output = output.replace(' ','') + output = output.split('\n') + output = [entry for entry in output if len(entry) > 1] + print(str(output)) + def processVulnersScriptOutput(self, vulnersOutput): output = vulnersOutput.replace('\t\t\t','\t') @@ -35,6 +41,7 @@ def processVulnersScriptOutput(self, vulnersOutput): pyExploitDb = PyExploitDb() pyExploitDb.debug = False + pyExploitDb.autoUpdate = False pyExploitDb.openFile() cpeList = [] @@ -70,11 +77,11 @@ def processVulnersScriptOutput(self, vulnersOutput): resultCveDict['severity'] = resultCveData[1] resultCveDict['url'] = resultCveData[2] exploitResults = pyExploitDb.searchCve(resultCveData[0]) - print("-----------------{0}".format(exploitResults)) + print(exploitResults) if exploitResults: - resultCveDict['exploitid'] = exploitResults['edbid'] + resultCveDict['exploitId'] = exploitResults['edbid'] resultCveDict['exploit'] = exploitResults['exploit'] - resultCveDict['exploiturl'] = "https://www.exploit-db.com/exploits/{0}".format(resultCveDict['exploit']) + resultCveDict['exploitUrl'] = "https://www.exploit-db.com/exploits/{0}".format(resultCveDict['exploit']) resultCvesProcessed.append(resultCveDict) resultCpeDetails['cves'] = resultCvesProcessed resultsDict[resultCpeData[3]] = resultCpeDetails @@ -82,7 +89,7 @@ def processVulnersScriptOutput(self, vulnersOutput): return resultsDict - def get_cves(self): + def getCves(self): cveOutput = self.output cveObjects = [] @@ -102,11 +109,30 @@ def get_cves(self): cveData['version'] = cpeVersion cveData['source'] = cpeSource cveData['product'] = cpeProduct + print("NEW CVE: {0}".format(cveData)) cveObj = CVE.CVE(cveData) cveObjects.append(cveObj) return cveObjects return None + def scriptSelector(self, host): + scriptId = str(self.scriptId).lower() + results = [] + if 'vulners' in scriptId: + print("------------------------VULNERS") + cveResults = self.getCves() + for cveEntry in cveResults: + t_cve = cve(name = cveEntry.name, url = cveEntry.url, source = cveEntry.source, severity = cveEntry.severity, product = cveEntry.product, version = cveEntry.version, hostId = host.id, exploitId = cveEntry.exploitId, exploit = cveEntry.exploit, exploitUrl = cveEntry.exploitUrl) + results.append(t_cve) + return results + elif 'shodan-api' in scriptId: + print("------------------------SHODAN") + #self.processShodanScriptOutput(self.output) + return results + else: + print("-----------------------*{0}".format(scriptId)) + return results + if __name__ == '__main__': dom = xml.dom.minidom.parse('a-full.xml') diff --git a/parsers/Session.py b/parsers/Session.py index daf8a06f..f09b5fc6 100644 --- a/parsers/Session.py +++ b/parsers/Session.py @@ -8,27 +8,27 @@ class Session: def __init__( self, SessionHT ): - self.start_time = SessionHT.get('start_time', '') + self.startTime = SessionHT.get('startTime', '') self.finish_time = SessionHT.get('finish_time', '') - self.nmap_version = SessionHT.get('nmap_version', '') - self.scan_args = SessionHT.get('scan_args', '') - self.total_hosts = SessionHT.get('total_hosts', '') - self.up_hosts = SessionHT.get('up_hosts', '') - self.down_hosts = SessionHT.get('down_hosts', '') + self.nmapVersion = SessionHT.get('nmapVersion', '') + self.scanArgs = SessionHT.get('scanArgs', '') + self.totalHosts = SessionHT.get('totalHosts', '') + self.upHosts = SessionHT.get('upHosts', '') + self.downHosts = SessionHT.get('downHosts', '') if __name__ == '__main__': dom = xml.dom.minidom.parse('i.xml') dom.getElementsByTagName('finished')[0].getAttribute('timestr') - MySession = { 'finish_time': dom.getElementsByTagName('finished')[0].getAttribute('timestr'), 'nmap_version' : '4.79', 'scan_args' : '-sS -sV -A -T4', 'start_time' : dom.getElementsByTagName('nmaprun')[0].getAttribute('startstr'), 'total_hosts' : '1', 'up_hosts' : '1', 'down_hosts' : '0' } + MySession = { 'finish_time': dom.getElementsByTagName('finished')[0].getAttribute('timestr'), 'nmapVersion' : '4.79', 'scanArgs' : '-sS -sV -A -T4', 'startTime' : dom.getElementsByTagName('nmaprun')[0].getAttribute('startstr'), 'totalHosts' : '1', 'upHosts' : '1', 'downHosts' : '0' } s = Session( MySession ) - log.info('start_time:' + s.start_time) + log.info('startTime:' + s.startTime) log.info('finish_time:' + s.finish_time) - log.info('nmap_version:' + s.nmap_version) - log.info('nmap_args:' + s.scan_args) - log.info('total hosts:' + s.total_hosts) - log.info('up hosts:' + s.up_hosts) - log.info('down hosts:' + s.down_hosts) + log.info('nmapVersion:' + s.nmapVersion) + log.info('nmap_args:' + s.scanArgs) + log.info('total hosts:' + s.totalHosts) + log.info('up hosts:' + s.upHosts) + log.info('down hosts:' + s.downHosts) diff --git a/precommit.sh b/precommit.sh index e39c694d..d196d5e0 100644 --- a/precommit.sh +++ b/precommit.sh @@ -25,4 +25,4 @@ find . -name \*.pyo -delete rm -Rf ./scripts/CloudFail/ # Removed backups -rm -Rf ./backups/* +rm -Rf ./backup/*.conf diff --git a/requirements.txt b/requirements.txt index a814949c..5ef51ed0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,17 +1,17 @@ asyncio aiohttp aioredis -six==1.11.0 -Quamash==0.6.1 +six>=1.11.0 +Quamash>=0.6.1 SQLAlchemy==1.3.0b1 -aiomonitor==0.3.1 -APScheduler==3.5.3 -PyQt5==5.11.3 -sanic==0.8.3 +aiomonitor>=0.3.1 +APScheduler>=3.5.3 +PyQt5>=5.11.3 +sanic>=0.8.3 sanic_swagger -requests==2.20.1 +requests>=2.20.1 pyfiglet colorama termcolor win_inet_pton -pyExploitDb==0.1.7 +pyExploitDb>=0.1.8 diff --git a/scripts/nmap/shodan-api.nse b/scripts/nmap/shodan-api.nse new file mode 100644 index 00000000..8dab2298 --- /dev/null +++ b/scripts/nmap/shodan-api.nse @@ -0,0 +1,223 @@ +local http = require "http" +local io = require "io" +local ipOps = require "ipOps" +local json = require "json" +local nmap = require "nmap" +local stdnse = require "stdnse" +local string = require "string" +local tab = require "tab" +local table = require "table" +local openssl = stdnse.silent_require "openssl" + + +-- Set your Shodan API key here to avoid typing it in every time: +local apiKey = "" + +author = "Glenn Wilkinson (idea: Charl van der Walt )" +license = "Same as Nmap--See https://nmap.org/book/man-legal.html" +categories = {"discovery", "safe", "external"} + +description = [[ +Queries Shodan API for given targets and produces similar output to +a -sV nmap scan. The ShodanAPI key can be set with the 'apikey' script +argument, or hardcoded in the .nse file itself. You can get a free key from +https://developer.shodan.io + +N.B if you want this script to run completely passively make sure to +include the -sn -Pn -n flags. +]] + +--- +-- @usage +-- nmap --script shodan-api x.y.z.0/24 -sn -Pn -n --script-args 'shodan-api.outfile=potato.csv,shodan-api.apikey=SHODANAPIKEY' +-- nmap --script shodan-api --script-args 'shodan-api.target=x.y.z.a,shodan-api.apikey=SHODANAPIKEY' +-- +-- @output +-- | shodan-api: Report for 2600:3c01::f03c:91ff:fe18:bb2f (scanme.nmap.org) +-- | PORT PROTO PRODUCT VERSION +-- | 80 tcp Apache httpd +-- | 3306 tcp MySQL 5.5.40-0+wheezy1 +-- | 22 tcp OpenSSH 6.0p1 Debian 4+deb7u2 +-- |_443 tcp +-- +--@args shodan-api.outfile Write the results to the specified CSV file +--@args shodan-api.apikey Specify the ShodanAPI key. This can also be hardcoded in the nse file. +--@args shodan-api.target Specify a single target to be scanned. +-- +--@xmloutput +-- +-- scanme.nmap.org +--
+-- +--
+-- tcp +-- 22 +--
+-- +-- 2.4.7 +-- Apache httpd +-- tcp +-- 80 +--
+-- + +-- ToDo: * Have an option to complement non-banner scans with shodan data (e.g. -sS scan, but +-- grab service info from Shodan +-- * Have script arg to include extra host info. e.g. Coutry/city of IP, datetime of +-- scan, verbose port output (e.g. smb share info) +-- * Warn user if they haven't set -sn -Pn and -n (and will therefore actually scan the host +-- * Accept IP ranges via the script argument 'target' parameter + + +-- Begin +if not nmap.registry[SCRIPT_NAME] then + nmap.registry[SCRIPT_NAME] = { + apiKey = stdnse.get_script_args(SCRIPT_NAME .. ".apikey") or apiKey, + count = 0 + } +end +local registry = nmap.registry[SCRIPT_NAME] +local outFile = stdnse.get_script_args(SCRIPT_NAME .. ".outfile") +local arg_target = stdnse.get_script_args(SCRIPT_NAME .. ".target") + +local function lookup_target (target) + local response = http.get("api.shodan.io", 443, "/shodan/host/".. target .."?key=" .. registry.apiKey, {any_af = true}) + if response.status == 404 then + stdnse.debug1("Host not found: %s", target) + return nil + elseif (response.status ~= 200) then + stdnse.debug1("Bad response from Shodan for IP %s : %s", target, response.status) + return nil + end + + local stat, resp = json.parse(response.body) + if not stat then + stdnse.debug1("Error parsing Shodan response: %s", resp) + return nil + end + + return resp +end + +local function format_output(resp) + if resp.error then + return resp.error + end + + if resp.data then + registry.count = registry.count + 1 + local out = { hostnames = resp.hostnames, ports = {} } + local ports = out.ports + local tab_out = tab.new() + tab.addrow(tab_out, "PORT", "PROTO", "PRODUCT", "VERSION") + + for key, e in ipairs(resp.data) do + ports[#ports+1] = { + number = e.port, + protocol = e.transport, + product = e.product, + version = e.version, + } + tab.addrow(tab_out, e.port, e.transport, e.product or "", e.version or "") + end + return out, tab.dump(tab_out) + else + return "Unable to query data" + end +end + +prerule = function () + if (outFile ~= nil) then + local file = io.open(outFile, "w") + io.output(file) + io.write("IP,Port,Proto,Product,Version\n") + end + + if registry.apiKey == "" then + registry.apiKey = nil + end + + if not registry.apiKey then + stdnse.verbose1("Error: Please specify your ShodanAPI key with the %s.apikey argument", SCRIPT_NAME) + return false + end + + local response = http.get("api.shodan.io", 443, "/api-info?key=" .. registry.apiKey, {any_af=true}) + if (response.status ~= 200) then + stdnse.verbose1("Error: Your ShodanAPI key (%s) is invalid", registry.apiKey) + -- Prevent further stages from running + registry.apiKey = nil + return false + end + + if arg_target then + local is_ip, err = ipOps.expand_ip(arg_target) + if not is_ip then + stdnse.verbose1("Error: %s.target must be an IP address", SCRIPT_NAME) + return false + end + return true + end +end + +generic_action = function(ip) + local resp = lookup_target(ip) + if not resp then return nil end + local out, tabular = format_output(resp) + if type(out) == "string" then + -- some kind of error + return out + end + local result = string.format( + "Report for %s (%s)\n%s", + ip, + table.concat(out.hostnames, ", "), + tabular + ) + if (outFile ~= nil) then + for _, port in ipairs(out.ports) do + io.write( string.format("%s,%s,%s,%s,%s\n", + ip, port.number, port.protocol, port.product or "", port.version or "") + ) + end + end + return out, result +end + +preaction = function() + return generic_action(arg_target) +end + +hostrule = function(host) + return registry.apiKey and not ipOps.isPrivate(host.ip) +end + +hostaction = function(host) + return generic_action(host.ip) +end + +postrule = function () + return registry.apiKey +end + +postaction = function () + local out = { "Shodan done: ", registry.count, " hosts up." } + if outFile then + io.close() + out[#out+1] = "\nWrote Shodan output to: " + out[#out+1] = outFile + end + return table.concat(out) +end + +local ActionsTable = { + -- prerule: scan target from script-args + prerule = preaction, + -- hostrule: look up a host in Shodan + hostrule = hostaction, + -- postrule: report results + postrule = postaction +} + +-- execute the action function corresponding to the current rule +action = function(...) return ActionsTable[SCRIPT_TYPE](...) end diff --git a/scripts/nmap/shodan-hq.nse b/scripts/nmap/shodan-hq.nse new file mode 100644 index 00000000..c11eddb7 --- /dev/null +++ b/scripts/nmap/shodan-hq.nse @@ -0,0 +1,135 @@ +local http = require "http" +local io = require "io" +local json = require "json" +local stdnse = require "stdnse" +local openssl = stdnse.silent_require "openssl" + + +-- Set your Shodan API key here to avoid typing it in every time: +local apiKey = "" + +author = "Glenn Wilkinson <@glennzw> (idea: Charl van der Walt <@charlvdwalt> )" +license = "Same as Nmap--See https://nmap.org/book/man-legal.html" +categories = {"discovery", "safe"} +url = "https://github.com/glennzw/shodan-hq-nse" + +description = [[ +Queries Shodan API for given targets and produces similar output to +a -sV nmap scan. The ShodanAPI key can be set with the 'apikey' script +argument, or hardcoded in the .nse file itself. + +N.B if you want this script to run completely passively make sure to +include the -sn -Pn -n flags. + +Example usage: + +nmap --script shodan-hq.nse x.y.z.0/24 -sn -Pn -n --script-args 'outfile=potato.csv,apikey=SHODANAPIKEY' + + +You can also specify a single target with a script argument: + +nmap --script shodan-hq.nse --script-args 'target=x.y.z.a' + +Contact: [glenn|charl]@sensepost.com +Code : https://github.com/glennzw/shodan-hq-nse +]] + +--- +-- @output +-- | +-- | PORT STATE SERVICE VERSION +-- | 80/tcp open Apache httpd +-- | 3306/tcp open MySQL 5.5.40-0+wheezy1 +-- | 22/tcp open OpenSSH 6.0p1 Debian 4+deb7u2 +-- +--@args outfile Write the results to the specified CSV file +--@args apiKey Specify the ShodanAPI key. This can also be hardcoded in the nse file. +--@args target Specify a single target to be scanned. + +-- ToDo: * Have an option to compliment non banner scans with shodan data (e.g. -sS scan, but +-- grab service info from Shodan +-- * Have script arg to include extra host info. e.g. Coutry/city of IP, datetime of +-- scan, verbose port output (e.g. smb share info) +-- * Warn user if they haven't set -sn -Pn and -n (and will therefore actually scan the host +-- * Accept IP ranges via the script argument 'target' parameter + + +-- Begin +local scriptApiKey = stdnse.get_script_args("apikey") +if (scriptApiKey ~= nil) then apiKey = scriptApiKey end +local outFile = stdnse.get_script_args("outfile") +local target = stdnse.get_script_args("target") + +function ts(v) + if v == nil then return "" end + return v +end + +hostrule = function() return true end + + +prerule = function () + if (outFile ~= nil) then + file = io.open(outFile, "w") io.output(file) io.write("IP, Port, Service\n") + end + + if (apiKey == "") then + print("\nError: Please specify your ShodanAPI key with --script-args='apikey=', or set it in the .nse file. You can get a free key from https://developer.shodan.io\n") + end + if (target ~= nil) then + print("Scanning single host ".. target) + return true + end +end + +postrule = function () + nmap.registry.count = (nmap.registry.count or 0) + print("+ Shodan done: " .. nmap.registry.count .. " hosts up.") + if (outFile ~= nil) then io.close() print ("+ Wrote Shodan output to '" .. outFile .. "'\n") end +end + +action = function(host) + if (apiKey == "") then return nil end + + if (target == nil) then target=host.ip end + + local response = http.get("api.shodan.io", 443, "/shodan/host/".. target .."?key=" .. apiKey) + if (response.status == 401) then + return "Received 'Unauthorized' from Shodan API. Double check your API key." + elseif (response.status == 404) then + return "No information for IP " .. target + elseif (response.status ~= 200) then + return "Bad response from Shodan for IP " .. target .. " : " .. response.status + end + + local stat, resp = json.parse(response.body) + if (resp.error ~= nil) then + return resp.error + end + + if (resp.data ~= nil) then + nmap.registry.count = (nmap.registry.count or 0) + 1 + hostnames = "" + for k, h in pairs(resp.hostnames) + do + hostnames = h .. " " .. hostnames + end + local result = "Report for " .. target + if (string.len(hostnames) > 0) + then + result = result .. " (" .. hostnames .. ")" + end + result = result .. "\n\nPORT\t\tSTATE\tSERVICE\tVERSION\n" + for key,e in ipairs(resp.data) + do + result = result .. ts(e.port) .. "/" .. ts(e.transport) .. "\topen" .. ts(e.service) .. "\t" .. ts(e.product) .. "\t" .. ts(e.version) .. "\n" + if (outFile ~= nil) then + out = target .. ", " .. ts(e.port) .. ", " .. ts(e.service) .. " " .. ts(e.product) .. "\n" + io.write(out) + end + end + return result + else + return "Unable to query data for IP " .. target + end +end diff --git a/ui/view.py b/ui/view.py index 504ff77a..25dfbd69 100644 --- a/ui/view.py +++ b/ui/view.py @@ -632,25 +632,12 @@ def rightTableDoubleClick(self, signal): index = signal.sibling(row, 0) index_dict = model.itemData(index) index_value = index_dict.get(0) - print( - 'Row {}, Column {} clicked - value: {}\nColumn 1 contents: {}'.format(row, column, cell_value, index_value)) - df=pd.DataFrame([cell_value]) - df.to_clipboard(index=False,header=False) - - #def rightTableDoubleClick(self): - # tab = self.ui.ServicesTabWidget.tabText(self.ui.ServicesTabWidget.currentIndex()) - # print(tab) - # - # if tab == 'CVEs': - # row = self.ui.CvesTableView.selectionModel().selectedRows()[len(self.ui.CvesTableView.selectionModel().selectedRows())-1].row() - # selectedRowData = self.CvesTableModel.getCveForRow(row) - # print(row) - # print(selectedRowData) - # column = self.ui.CvesTableView.selectionModel().selectedColumns()[len(self.ui.CvesTableView.selectionModel().selectedRows())-1].column() - # print(column) - # - # else: - # return + log.info('Row {}, Column {} clicked - value: {}\nColumn 1 contents: {}'.format(row, column, cell_value, index_value)) + + ## Does not work under WSL! + df = pd.DataFrame([cell_value]) + df.to_clipboard(index = False, header = False) + def tableDoubleClick(self): tab = self.ui.HostsTabWidget.tabText(self.ui.HostsTabWidget.currentIndex()) @@ -1073,7 +1060,7 @@ def updateInformationView(self, hostIP): else: counterFiltered = 65535 - counterOpen - counterClosed - self.hostInfoWidget.updateFields(status=host.status, openPorts=counterOpen, closedPorts=counterClosed, filteredPorts=counterFiltered, ipv4=host.ipv4, ipv6=host.ipv6, macaddr=host.macaddr, osMatch=host.os_match, osAccuracy=host.os_accuracy) + self.hostInfoWidget.updateFields(status=host.status, openPorts=counterOpen, closedPorts=counterClosed, filteredPorts=counterFiltered, ipv4=host.ipv4, ipv6=host.ipv6, macaddr=host.macaddr, osMatch=host.osMatch, osAccuracy=host.osAccuracy) def updateScriptsView(self, hostIP): headers = ["Id", "Script", "Port", "Protocol"] @@ -1103,7 +1090,6 @@ def updateScriptsView(self, hostIP): def updateCvesByHostView(self, hostIP): headers = ["ID", "CVSS Score", "Product", "Version", "URL", "Source", "Exploit ID", "Exploit", "Exploit URL"] cves = self.controller.getCvesFromDB(hostIP) - print("CVES: {0}".format(str(cves))) self.CvesTableModel = CvesTableModel(self, cves, headers) self.ui.CvesTableView.horizontalHeader().resizeSection(0,175) @@ -1286,17 +1272,17 @@ def updateInterface(self): # this function creates a new tool tab for a given host # TODO: refactor/review, especially the restoring part. we should not check if toolname=nmap everywhere in the code # ..maybe we should do it here. rethink - def createNewTabForHost(self, ip, tabtitle, restoring=False, content='', filename=''): + def createNewTabForHost(self, ip, tabTitle, restoring=False, content='', filename=''): - if 'screenshot' in str(tabtitle): # TODO: use regex otherwise tools with 'screenshot' in the name are screwed. + if 'screenshot' in str(tabTitle): # TODO: use regex otherwise tools with 'screenshot' in the name are screwed. tempWidget = ImageViewer() - tempWidget.setObjectName(str(tabtitle)) + tempWidget.setObjectName(str(tabTitle)) tempWidget.open(str(filename)) tempTextView = tempWidget.scrollArea - tempTextView.setObjectName(str(tabtitle)) + tempTextView.setObjectName(str(tabTitle)) else: tempWidget = QtWidgets.QWidget() - tempWidget.setObjectName(str(tabtitle)) + tempWidget.setObjectName(str(tabTitle)) tempTextView = QtWidgets.QPlainTextEdit(tempWidget) tempTextView.setReadOnly(True) if self.controller.getSettings().general_tool_output_black_background == 'True': @@ -1312,13 +1298,13 @@ def createNewTabForHost(self, ip, tabtitle, restoring=False, content='', filenam tempTextView.appendPlainText(content) if restoring == False: # if restoring tabs (after opening a project) don't show the tab in the ui - tabindex = self.ui.ServicesTabWidget.addTab(tempWidget, str(tabtitle)) + tabindex = self.ui.ServicesTabWidget.addTab(tempWidget, str(tabTitle)) hosttabs = [] # fetch tab list for this host (if any) if str(ip) in self.hostTabs: hosttabs = self.hostTabs[str(ip)] - if 'screenshot' in str(tabtitle): + if 'screenshot' in str(tabTitle): hosttabs.append(tempWidget.scrollArea) # add the new tab to the list else: hosttabs.append(tempWidget) # add the new tab to the list @@ -1328,10 +1314,10 @@ def createNewTabForHost(self, ip, tabtitle, restoring=False, content='', filenam return tempTextView - def createNewConsole(self, tabtitle, content='Hello\n', filename=''): + def createNewConsole(self, tabTitle, content='Hello\n', filename=''): tempWidget = QtWidgets.QWidget() - tempWidget.setObjectName(str(tabtitle)) + tempWidget.setObjectName(str(tabTitle)) tempTextView = QtWidgets.QPlainTextEdit(tempWidget) tempTextView.setReadOnly(True) if self.controller.getSettings().general_tool_output_black_background == 'True': @@ -1414,13 +1400,13 @@ def restoreToolTabs(self): self.tick.emit(int(totalprogress)) for t in tools: - if not t.tabtitle == '': - if 'screenshot' in str(t.tabtitle): - imageviewer = self.createNewTabForHost(t.hostip, t.tabtitle, True, '', str(self.controller.getOutputFolder())+'/screenshots/'+str(t.outputfile)) - imageviewer.setObjectName(str(t.tabtitle)) + if not t.tabTitle == '': + if 'screenshot' in str(t.tabTitle): + imageviewer = self.createNewTabForHost(t.hostIp, t.tabTitle, True, '', str(self.controller.getOutputFolder())+'/screenshots/'+str(t.outputfile)) + imageviewer.setObjectName(str(t.tabTitle)) imageviewer.setProperty('dbId', str(t.id)) else: - self.createNewTabForHost(t.hostip, t.tabtitle, True, t.output).setProperty('dbId', str(t.id)) # True means we are restoring tabs. Set the widget's object name to the DB id of the process + self.createNewTabForHost(t.hostIp, t.tabTitle, True, t.output).setProperty('dbId', str(t.id)) # True means we are restoring tabs. Set the widget's object name to the DB id of the process totalprogress += progress # update the progress bar self.tick.emit(int(totalprogress)) @@ -1495,7 +1481,7 @@ def resetBruteTabs(self): self.ui.BruteTabWidget.removeTab(count -i -1) self.createNewBruteTab('127.0.0.1', '22', 'ssh') - # TODO: show udp in tabtitle when udp service + # TODO: show udp in tabTitle when udp service def callHydra(self, bWidget): if validateNmapInput(bWidget.ipTextinput.text()) and validateNmapInput(bWidget.portTextinput.text()) and validateCredentials(bWidget.usersTextinput.text()) and validateCredentials(bWidget.passwordsTextinput.text()): # check if host is already in scope