1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-09 22:21:29 +00:00
Files
nmap/nselib/anyconnect.lua
dmiller 9450cb725a Avoid boolean tautologies of the form 'not x == y'
Lua operator 'not' has higher precedence than '==', so the statement

    not x == "something"

is equivalent to:

    (not x) == "something"

which will always be false, since the value of 'not x' will be either
'true' or 'false' and the string "something" is not the boolean 'true'
or 'false'. This is usually resolved by using the '~=' operator.
2016-05-23 04:30:06 +00:00

151 lines
4.5 KiB
Lua

---
-- This library implements HTTP requests used by the Cisco AnyConnect VPN Client
--
-- @author "Patrik Karlsson <patrik@cqure.net>"
--
-- @args anyconnect.group AnyConnect tunnel group (default: VPN)
-- @args anyconnect.mac MAC address of connecting client (default: random MAC)
-- @args anyconnect.version Version of connecting client (default: 3.1.05160)
-- @args anyconnect.ua User Agent of connecting client (default: AnyConnect Darwin_i386 3.1.05160)
local http = require('http')
local stdnse = require('stdnse')
local url = require('url')
local math = require('math')
local table = require('table')
local os = require('os')
local args_group= stdnse.get_script_args('anyconnect.group') or "VPN"
local args_mac= stdnse.get_script_args('anyconnect.mac')
local args_ver = stdnse.get_script_args('anyconnect.version') or "3.1.05160"
local args_ua = stdnse.get_script_args('anyconnect.ua') or ("AnyConnect Darwin_i386 %s"):format(args_ver)
_ENV = stdnse.module("anyconnect", stdnse.seeall)
Cisco = {
Util = {
generate_mac = function()
math.randomseed(os.time())
local mac = {}
for i=1,6 do
mac[#mac + 1] = (("%x"):format(math.random(255))):gsub(' ', '0');
end
return table.concat(mac,':')
end,
},
AnyConnect = {
new = function(self, host, port)
local o = { host = host, port = port }
setmetatable(o, self)
self.__index = self
return o
end,
-- generate a random hex-string of length 'length'
--
generate_random = function(length)
return stdnse.generate_random_string(length * 2, '0123456789ABCDEF')
end,
connect = function(self)
args_mac = args_mac or Cisco.Util.generate_mac()
local headers = {
['User-Agent'] = args_ua,
['Accept'] = '*/*',
['Accept-Encoding'] = 'identity',
['X-Transcend-Version'] = 1,
['X-Aggregate-Auth'] = 1,
['X-AnyConnect-Platform'] = 'mac-intel'
}
local data = ([[<?xml version="1.0" encoding="UTF-8"?>
<config-auth client="vpn" type="init" aggregate-auth-version="2">
<version who="vpn">%s</version>
<device-id device-type="MacBookAir4,1" platform-version="10.9.2" unique-id="%s">mac-intel</device-id>
<mac-address-list>
<mac-address>%s</mac-address></mac-address-list>
<group-select>%s</group-select>
<group-access>https://%s:%s</group-access>
</config-auth>]]):format(args_ver, self.generate_random(64), args_mac, args_group, self.host.ip, self.port.number)
local options = { header=headers , no_cache=true, redirect_ok = function(host,port)
local c = 5
return function(url)
if ( c==0 ) then return false end
c = c - 1
return true
end
end
}
local path = '/'
local response = http.head(self.host, self.port, path, options)
-- account for redirects
if response.status ~= 200 then
return false, "Failed to connect to SSL VPN server"
elseif response.location then
local u = url.parse(response.location[#response.location])
if u.host then
self.host = u.host
end
if u.path then
path = u.path
end
end
response = http.post(self.host, self.port, path, options, nil, data)
if response.status ~= 200 or response.body == nil then
return false, "Not a Cisco ASA or unsupported version"
end
local xmltags = {
'version',
'tunnel-group',
'group-alias',
'config-hash',
'host-scan-ticket',
'host-scan-token',
'host-scan-base-uri',
'host-scan-wait-uri',
'banner'
}
self.conn_attr = {}
for _, tag in ipairs(xmltags) do
local body = response.body:gsub('\r?\n', '')
local filter = ("<%s.->(.*)</%s>"):format(tag:gsub('-', '%%-'), tag:gsub('-', '%%-'))
local m = body:match(filter)
if m then
self.conn_attr[tag] = m
end
end
if not self.conn_attr['version'] then
return false, "Not a Cisco ASA or unsupported version"
end
-- in case we were redirected
self.conn_attr['host'] = stdnse.get_hostname(self.host)
return true
end,
---
-- Returns the version of the remote SSL VPN concentrator
-- @return table containing major, minor and rev numeric values
get_version = function(self)
local ver = {}
ver['major'], ver['minor'], ver['rev'] = self.conn_attr['version']:match('^(%d-)%.(%d-)%((.*)%)$')
return ver
end
}
}
return _ENV