diff --git a/CHANGELOG b/CHANGELOG index adaa10a30..c344f45db 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,15 @@ # Nmap Changelog ($Id$); -*-text-*- +o [NSE] Added scripts by Toni Ruotto communicating with the NetBus + remote administration/backdoor program. + - netbus-info: gets configuration information. + - netbus-brute: guesses passwords. + - netbus-version: distinguishes NetBus from NetBuster, a program + that mimics the protocol but doesn't actually allow any + operations. + - netbus-auth-bypass: Checks for a bug in the server that allows + connecting without a password. + o [NSE] Added stuxnet-detect.nse by Mak Kolybabi, which detects infections of the Sutxnet worm and can optionally download the Stuxnet executable. diff --git a/scripts/netbus-auth-bypass.nse b/scripts/netbus-auth-bypass.nse new file mode 100644 index 000000000..ecae5dd72 --- /dev/null +++ b/scripts/netbus-auth-bypass.nse @@ -0,0 +1,55 @@ +description = [[ +Checks if a NetBus server is vulnerable to authentication bypass. +Servers with this vulnerability can be accessed without knowing +the password. + +For example a server running on TCP port 12345 on localhost with +this vulnerability is accessible to anyone. An attacker could +simply form a connection to the server ( ncat -C 127.0.0.1 12345 ) +and login to the service by typing Password;1; into the console. +]] + +--- +-- @output +-- 12345/tcp open netbus +-- |_netbus-auth-bypass: Vulnerable + +author = "Toni Ruottu" +license = "Same as Nmap--See http://nmap.org/book/man-legal.html" +categories = {"default", "vuln", "safe"} + +require("nmap") +require("stdnse") +require("shortport") + +dependencies = {"netbus-version", "netbus-brute", "netbus-info"} + +portrule = shortport.port_or_service (12345, "netbus", {"tcp"}) + +action = function( host, port ) + + local socket = nmap.new_socket() + local status, err = socket:connect(host.ip, port.number) + if not status then + return + end + local buffer, _ = stdnse.make_buffer(socket, "\r") + buffer() --discard banner + + -- The first argument of Password is the super-login bit. + -- On vulnerable servers any password will do as long as + -- we send the super-login bit. Regular NetBus has only + -- one password. Thus, if we can login with two different + -- passwords using super-login, the server is vulnerable. + + socket:send("Password;1;\r") --password: empty + if buffer() ~= "Access;1" then + return + end + socket:send("Password;1; \r") --password: space + if buffer() == "Access;1" then + return "Vulnerable" + end + return +end + diff --git a/scripts/netbus-brute.nse b/scripts/netbus-brute.nse new file mode 100644 index 000000000..1d84806d1 --- /dev/null +++ b/scripts/netbus-brute.nse @@ -0,0 +1,48 @@ +description = [[ +Tries to retrieve NetBus password by guessing. +]] + +--- +-- @output +-- 12345/tcp open netbus +-- |_netbus-brute: password123 + +author = "Toni Ruottu" +license = "Same as Nmap--See http://nmap.org/book/man-legal.html" +categories = {"auth", "intrusive"} + +require("nmap") +require("stdnse") +require("shortport") +require("unpwdb") + +dependencies = {"netbus-version"} + +portrule = shortport.port_or_service (12345, "netbus", {"tcp"}) + +action = function( host, port ) + local try = nmap.new_try() + local passwords = try(unpwdb.passwords()) + local socket = nmap.new_socket() + local status, err = socket:connect(host.ip, port.number) + if not status then + return + end + local buffer, err = stdnse.make_buffer(socket, "\r") + local _ = buffer() --skip the banner + for password in passwords do + local foo = string.format("Password;0;%s\r", password) + socket:send(foo) + local login = buffer() + if login == "Access;1" then + -- Store the password for other netbus scripts + nmap.registry.netbuspassword=password + + return string.format("%s", password) + end + end + socket:close() + +end + + diff --git a/scripts/netbus-info.nse b/scripts/netbus-info.nse new file mode 100644 index 000000000..599a09e35 --- /dev/null +++ b/scripts/netbus-info.nse @@ -0,0 +1,166 @@ +description = [[ +Opens a connection to a NetBus server and extracts information about +the host and the NetBus service itself. + +The extracted host information includes a list of running +applications, and the hosts sound volume settings. + +The extracted service information includes it's access control list +(acl), server information, and setup. The acl is a list of IP +addresses permitted to access the service. Server information +contains details about the server installation path, restart +persistence, user account that the server is running on, and the +amount of connected NetBus clients. The setup information contains +configuration details, such as the services TCP port number, traffic +logging setting, password, an email address for receiving login +notifications, an email address used for sending the notifications, +and an smtp-server used for notification delivery. +]] + +--- +-- @output +-- 12345/tcp open netbus +-- | netbus-info: +-- | ACL +-- | 127.0.0.1 +-- | APPLICATIONS +-- | PuTTY Configuration +-- | INFO +-- | Program Path: Z:\home\joeuser\Desktop\Patch.exe +-- | Restart persistent: Yes +-- | Login ID: joeuser +-- | Clients connected to this host: 1 +-- | SETUP +-- | TCP-port: 12345 +-- | Log traffic: 1 +-- | Password: password123 +-- | Notify to: admin@example.com +-- | Notify from: spoofed@example.org +-- | SMTP-server: smtp.example.net +-- | VOLUME +-- | Wave: 0 +-- | Synth: 0 +-- |_ Cd: 0 + +author = "Toni Ruottu" +license = "Same as Nmap--See http://nmap.org/book/man-legal.html" +categories = {"default", "discovery", "safe"} + +require("nmap") +require("comm") +require("stdnse") +require("shortport") + +dependencies = {"netbus-version", "netbus-brute"} + +portrule = shortport.port_or_service (12345, "netbus", {"tcp"}) + +local function format_acl(acl) + if acl == nil then + return {} + end + local payload = string.sub(acl, 9) --skip header + local fields = stdnse.strsplit("|", payload) + table.remove(fields, (# fields)) + fields["name"] = "ACL" + return fields +end + +local function format_apps(apps) + if apps == nil then + return {} + end + local payload = string.sub(apps, 10) --skip header + local fields = stdnse.strsplit("|", payload) + table.remove(fields, (# fields)) + fields["name"] = "APPLICATIONS" + return fields +end + +local function format_info(info) + if info == nil then + return {} + end + local payload = string.sub(info, 6) --skip header + local fields = stdnse.strsplit("|", payload) + fields["name"] = "INFO" + return fields +end + +local function format_setup(setup) + local formatted = {} + if setup == nil then + return formatted + end + local fields = stdnse.strsplit(";", setup) + if # fields < 7 then + return formatted + end + formatted["name"] = "SETUP" + table.insert(formatted, string.format("TCP-port: %s", fields[2])) + table.insert(formatted, string.format("Log traffic: %s", fields[3])) + table.insert(formatted, string.format("Password: %s", fields[4])) + table.insert(formatted, string.format("Notify to: %s", fields[5])) + table.insert(formatted, string.format("Notify from: %s", fields[6])) + table.insert(formatted, string.format("SMTP-server: %s", fields[7])) + return formatted +end + +local function format_volume(volume) + local formatted = {} + if volume == nil then + return formatted + end + local fields = stdnse.strsplit(";", volume) + if # fields < 4 then + return formatted + end + formatted["name"] = "VOLUME" + table.insert(formatted, string.format("Wave: %s", fields[2])) + table.insert(formatted, string.format("Synth: %s", fields[3])) + table.insert(formatted, string.format("Cd: %s", fields[4])) + return formatted +end + +action = function( host, port ) + + local password = nmap.registry.netbuspassword + if password == nil then + password = "" + end + + local socket = nmap.new_socket() + socket:set_timeout(5000) + local status, err = socket:connect(host.ip, port.number) + local buffer, err = stdnse.make_buffer(socket, "\r") + local _ = buffer() + socket:send(string.format("Password;1;%s\r", password)) + local gotin = buffer() + if gotin == "Access;0" then + return + end + + socket:send("GetInfo\r") + local info = buffer() + socket:send("GetSetup\r") + local setup = buffer() + socket:send("GetACL\r") + local acl = buffer() + socket:send("GetApps\r") + local apps = buffer() + socket:send("GetVolume\r") + local volume = buffer() + socket:close() + + local response = {} + table.insert(response, "") + table.insert(response, format_acl(acl)) + table.insert(response, format_apps(apps)) + table.insert(response, format_info(info)) + table.insert(response, format_setup(setup)) + table.insert(response, format_volume(volume)) + + return stdnse.format_output(true, response) +end + + diff --git a/scripts/netbus-version.nse b/scripts/netbus-version.nse new file mode 100644 index 000000000..6ff2425ff --- /dev/null +++ b/scripts/netbus-version.nse @@ -0,0 +1,46 @@ +description = [[ +Extends version detection to cover NetBuster, a honeypot service +that mimes NetBus. +]] + +--- +-- @output +-- 12345/tcp open netbus Netbuster (honeypot) + +author = "Toni Ruottu" +license = "Same as Nmap--See http://nmap.org/book/man-legal.html" +categories = {"version"} + +require("nmap") +require("stdnse") +require("shortport") + +portrule = shortport.port_or_service (12345, "netbus", {"tcp"}) + +action = function( host, port ) + + local socket = nmap.new_socket() + socket:set_timeout(5000) + local status, err = socket:connect(host.ip, port.number) + if not status then + return + end + local buffer, _ = stdnse.make_buffer(socket, "\r") + buffer() --discard banner + socket:send("Password;0;\r") + + --NetBus answers to auth + if buffer() ~= nil then + return + end + + --NetBuster does not + port.version.name = "netbus" + port.version.product = "Netbuster" + port.version.extrainfo = "honeypot" + port.version.version = nil + nmap.set_port_version(host, port, "hardmatched") + return +end + + diff --git a/scripts/script.db b/scripts/script.db index 59b383948..1d27e46b7 100644 --- a/scripts/script.db +++ b/scripts/script.db @@ -97,6 +97,10 @@ Entry { filename = "mysql-users.nse", categories = { "discovery", "intrusive", } Entry { filename = "mysql-variables.nse", categories = { "discovery", "intrusive", } } Entry { filename = "nat-pmp-info.nse", categories = { "default", "discovery", "safe", } } Entry { filename = "nbstat.nse", categories = { "default", "discovery", "safe", } } +Entry { filename = "netbus-auth-bypass.nse", categories = { "default", "safe", "vuln", } } +Entry { filename = "netbus-brute.nse", categories = { "auth", "intrusive", } } +Entry { filename = "netbus-info.nse", categories = { "default", "discovery", "safe", } } +Entry { filename = "netbus-version.nse", categories = { "version", } } Entry { filename = "nfs-ls.nse", categories = { "discovery", "safe", } } Entry { filename = "nfs-showmount.nse", categories = { "discovery", "safe", } } Entry { filename = "nfs-statfs.nse", categories = { "discovery", "safe", } }