diff --git a/nselib/omp2.lua b/nselib/omp2.lua
index 83c38cdd2..bd64be146 100644
--- a/nselib/omp2.lua
+++ b/nselib/omp2.lua
@@ -13,15 +13,16 @@
-- website: http://www.openvas.org/omp-2-0.html
--
-- Sample use:
---
--- local session = omp2.Session:new()
--- local status, err = session:connect(host, port)
--- local status, err = session:authenticate(username, password)
--- ...
--- session:close()
---
+--
+-- local session = omp2.Session:new()
+-- local status, err = session:connect(host, port)
+-- local status, err = session:authenticate(username, password)
+-- ...
+-- session:close()
+--
--
-- @author Henri Doreau
+-- @author Sachin
-- @copyright Same as Nmap -- See https://nmap.org/book/man-legal.html
--
-- @args omp2.username The username to use for authentication.
@@ -31,150 +32,165 @@
local nmap = require "nmap"
local stdnse = require "stdnse"
local table = require "table"
+
+-- Escape XML special characters
+local function xml_escape(s)
+ if not s then return "" end
+ s = s:gsub("&", "&")
+ s = s:gsub("<", "<")
+ s = s:gsub(">", ">")
+ s = s:gsub("\"", """)
+ s = s:gsub("'", "'")
+ return s
+end
+
_ENV = stdnse.module("omp2", stdnse.seeall)
local HAVE_SSL = false
if pcall(require,'openssl') then
- HAVE_SSL = true
+ HAVE_SSL = true
end
--- A Session class holds connection and interaction with the server
Session = {
- --- Creates a new session object
- new = function(self, socket)
+ --- Creates a new session object
+ new = function(self, socket)
- local o = {}
- setmetatable(o, self)
- self.__index = self
+ local o = {}
+ setmetatable(o, self)
+ self.__index = self
- o.username = nmap.registry.args["omp2.username"]
- o.password = nmap.registry.args["omp2.password"]
- o.socket = socket or nmap.new_socket()
+ o.username = nmap.registry.args["omp2.username"]
+ o.password = nmap.registry.args["omp2.password"]
+ o.socket = socket or nmap.new_socket()
- return o
- end,
+ return o
+ end,
- --- Establishes the (SSL) connection to the remote server
- connect = function(self, host, port)
- if not HAVE_SSL then
- return false, "The OMP2 module requires OpenSSL support"
- end
+ --- Establishes the (SSL) connection to the remote server
+ connect = function(self, host, port)
+ if not HAVE_SSL then
+ return false, "The OMP2 module requires OpenSSL support"
+ end
- return self.socket:connect(host, port, "ssl")
- end,
+ return self.socket:connect(host, port, "ssl")
+ end,
- --- Closes connection
- close = function(self)
- return self.socket:close()
- end,
+ --- Closes connection
+ close = function(self)
+ return self.socket:close()
+ end,
- --- Attempts to authenticate on the current connection
- authenticate = function(self, username, password)
- local status, err, xmldata
+ --- Attempts to authenticate on the current connection
+ authenticate = function(self, username, password)
+ local status, err, xmldata
- -- TODO escape credentials
- status, err = self.socket:send(""
- .. "" .. username .. ""
- .. "" .. password .. ""
- .. "")
+ -- Escape credentials to prevent malformed XML
+ local safe_username = xml_escape(username)
+ local safe_password = xml_escape(password)
- if not status then
- stdnse.debug1("ERROR: %s", err)
- return false, err
- end
+ status, err = self.socket:send(""
+ .. "" .. safe_username .. ""
+ .. "" .. safe_password .. ""
+ .. "")
- status, xmldata = self.socket:receive()
- if not status then
- stdnse.debug1("ERROR: %s", xmldata)
- return false, xmldata
- end
+ if not status then
+ stdnse.debug1("ERROR: %s", err)
+ return false, err
+ end
- return xmldata:match('status="200"')
- end,
+ status, xmldata = self.socket:receive()
+ if not status then
+ stdnse.debug1("ERROR: %s", xmldata)
+ return false, xmldata
+ end
- --- Lists targets defined on the remote server
- ls_targets = function(self)
- local status, err, xmldata
- local res, target_names, target_hosts = {}, {}, {}
+ return xmldata:match('status="200"')
+ end,
- status, err = self.socket:send("")
+ --- Lists targets defined on the remote server
+ ls_targets = function(self)
+ local status, err, xmldata
+ local res, target_names, target_hosts = {}, {}, {}
- if not status then
- stdnse.debug1("ERROR: %s", err)
- return false, err
- end
+ status, err = self.socket:send("")
- status, xmldata = self.socket:receive()
- if not status then
- stdnse.debug1("ERROR: %s", xmldata)
- return false, xmldata
- end
+ if not status then
+ stdnse.debug1("ERROR: %s", err)
+ return false, err
+ end
- -- As NSE has no XML parser yet, we use regexp to extract the data from the
- -- XML output. Targets are defined as a name and the corresponding host(s).
- -- Thus we gather both and return an associative array, using names as keys
- -- and hosts as values.
+ status, xmldata = self.socket:receive()
+ if not status then
+ stdnse.debug1("ERROR: %s", xmldata)
+ return false, xmldata
+ end
- local i = 0
- for name in xmldata:gmatch("(.-)") do
- -- XXX this is hackish: skip the second and third "" tags, as they
- -- describe other components than the targets.
- -- see: http://www.openvas.org/omp-2-0.html#command_get_targets
- if i % 3 == 0 then
- table.insert(target_names, name)
- end
- i = i + 1
- end
+ -- As NSE has no XML parser yet, we use regexp to extract the data from the
+ -- XML output. Targets are defined as a name and the corresponding host(s).
+ -- Thus we gather both and return an associative array, using names as keys
+ -- and hosts as values.
- for hosts in xmldata:gmatch("(.-)") do
- table.insert(target_hosts, hosts)
- end
+ local i = 0
+ for name in xmldata:gmatch("(.-)") do
+ -- XXX this is hackish: skip the second and third "name" tags, as they
+ -- describe other components than the targets.
+ -- see: http://www.openvas.org/omp-2-0.html#command_get_targets
+ if i % 3 == 0 then
+ table.insert(target_names, name)
+ end
+ i = i + 1
+ end
- for i, _ in ipairs(target_names) do
- res[target_names[i]] = target_hosts[i]
- end
+ for hosts in xmldata:gmatch("(.-)") do
+ table.insert(target_hosts, hosts)
+ end
- return res
- end,
+ for i, _ in ipairs(target_names) do
+ res[target_names[i]] = target_hosts[i]
+ end
+
+ return res
+ end,
}
--- Registers OMP2 credentials for a given host
function add_account(host, username, password)
- if not nmap.registry[host.ip] then
- nmap.registry[host.ip] = {}
- end
+ if not nmap.registry[host.ip] then
+ nmap.registry[host.ip] = {}
+ end
- if not nmap.registry[host.ip]["omp2accounts"] then
- nmap.registry[host.ip]["omp2accounts"] = {}
- end
+ if not nmap.registry[host.ip]["omp2accounts"] then
+ nmap.registry[host.ip]["omp2accounts"] = {}
+ end
- table.insert(nmap.registry[host.ip]["omp2accounts"], {["username"] = username, ["password"] = password})
+ table.insert(nmap.registry[host.ip]["omp2accounts"], {["username"] = username, ["password"] = password})
end
--- Retrieves the list of accounts for a given host
function get_accounts(host)
- local accounts = {}
- local username, password
+ local accounts = {}
+ local username, password
- username = nmap.registry.args["omp2.username"]
- password = nmap.registry.args["omp2.password"]
+ username = nmap.registry.args["omp2.username"]
+ password = nmap.registry.args["omp2.password"]
- if username and password then
- table.insert(accounts, {["username"] = username, ["password"] = password})
- end
+ if username and password then
+ table.insert(accounts, {["username"] = username, ["password"] = password})
+ end
- if nmap.registry[host.ip] and nmap.registry[host.ip]["omp2accounts"] then
- for _, account in pairs(nmap.registry[host.ip]["omp2accounts"]) do
- table.insert(accounts, account)
- end
- end
+ if nmap.registry[host.ip] and nmap.registry[host.ip]["omp2accounts"] then
+ for _, account in pairs(nmap.registry[host.ip]["omp2accounts"]) do
+ table.insert(accounts, account)
+ end
+ end
- if #accounts > 0 then
- return accounts
- end
- return nil
+ if #accounts > 0 then
+ return accounts
+ end
+ return nil
end