boxmoe_header_banner_img

hello, cyberspace security!

文章导读

Sapido RB-1732 路由器命令执行漏洞


avatar
ra1ny 2026年1月13日 66

binwalk查看固件信息

➜  fw binwalk RB-1732_TC_v2.0.43.bin     

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
24207         0x5E8F          LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 3410896 bytes
1004185       0xF5299         Squashfs filesystem, little endian, version 4.0, compression:lzma, size: 5705880 bytes, 1361 inodes, blocksize: 131072 bytes, created: 2038-02-10 09:21:04

未加密固件,Squashfs文件系统。提取固件:

➜  fw binwalk -Me RB-1732_TC_v2.0.43.bin 

Scan Time:     2026-01-13 08:35:55
Target File:   /home/ra1ny/fw/RB-1732_TC_v2.0.43.bin
MD5 Checksum:  27b91f4216466031eaa7b039a7717b93
Signatures:    411

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
24207         0x5E8F          LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 3410896 bytes

WARNING: Extractor.execute failed to run external extractor 'sasquatch -p 1 -le -d 'squashfs-root-0' '%e'': [Errno 2] No such file or directory: 'sasquatch', 'sasquatch -p 1 -le -d 'squashfs-root-0' '%e'' might not be installed correctly

...

WARNING: Symlink points outside of the extraction directory: /home/ra1ny/fw/_RB-1732_TC_v2.0.43.bin.extracted/squashfs-root/etc/TZ -> /var/TZ; changing link target to /dev/null for security purposes.
1004185       0xF5299         Squashfs filesystem, little endian, version 4.0, compression:lzma, size: 5705880 bytes, 1361 inodes, blocksize: 131072 bytes, created: 2038-02-10 09:21:04


Scan Time:     2026-01-13 08:35:55
Target File:   /home/ra1ny/fw/_RB-1732_TC_v2.0.43.bin.extracted/5E8F
MD5 Checksum:  cf81f813aa695140d701f8a042a1a610
Signatures:    411

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
1212600       0x1280B8        Certificate in DER format (x509 v3), header length: 4, sequence length: 31
2818464       0x2B01A0        Linux kernel version 2.6.30
2854064       0x2B8CB0        CRC32 polynomial table, little endian
2943479       0x2CE9F7        HTML document header
2943642       0x2CEA9A        HTML document footer
3232608       0x315360        AES S-Box

system.asp文件中存在:

➜  squashfs-root find ./ -name "syscmd.asp"

审计该文件,可以看出,对form表单中的action指向的是formSyscmd

<form action=/goform/formSysCmd method=POST name="formSysCmd">
<table border=0 width="500" cellspacing=0 cellpadding=0>
  <tr><font size=2>
 This page can be used to run target system command.
  </tr>
  <tr><hr size=1 noshade align=top></tr>
  <tr>
      <td>System Command: </td>
    <td><input type="text" name="sysCmd" value="" size="20" maxlength="50"></td>
    <td> <input type="submit" value="Apply" name="apply" onClick='return saveClick()'></td>

  </tr>
</table>
  <input type="hidden" value="/syscmd.asp" name="submit-url">
</form>

接下来跟进formSyscmd文件。使用grep命令搜索formSyscmd字符串

➜  squashfs-root grep -riE "formSyscmd" ./
./web/obama.asp:        field = document.formSysCmd.sysCmd ;
./web/obama.asp:<form action=/goform/formSysCmd method=POST name="formSysCmd">
./web/obama.asp:  <form method="post" action="goform/formSysCmd" enctype="multipart/form-data" name="writefile">
./web/obama.asp:  <form action="/goform/formSysCmd" method=POST name="readfile">
./web/syscmd.asp:        field = document.formSysCmd.sysCmd ;
./web/syscmd.asp:<form action=/goform/formSysCmd method=POST name="formSysCmd">
grep: ./bin/webs: binary file matches

可以发现匹配到一个二进制文件匹配到了,名为webs
![[Pasted image 20260113085153.png]]
反编译这个函数,ida反编译后的代码:

int __fastcall formSysCmd(int a1)
{
  int Var; // $s4
  const char *v3; // $s1
  _BYTE *v4; // $s5
  int v5; // $s6
  const char *p_writepath; // $s3
  _BYTE *v7; // $s7
  int v8; // $v0
  _DWORD *v9; // $s0
  int v10; // $a0
  const char *Var_1; // $a1
  int v12; // $v0
  int v13; // $s1
  void (__fastcall *p_fputc)(int, _DWORD *); // $t9
  _BYTE *v15; // $a0
  _BYTE *v16; // $a3
  int v17; // $a0
  int v18; // $v0
  char p_writepath_1[104]; // [sp+20h] [-68h] BYREF

  Var = websGetVar(a1, "submit-url", &dword_47F498);
  v3 = (const char *)websGetVar(a1, "sysCmd", &dword_47F498);
  v4 = (_BYTE *)websGetVar(a1, "writeData", &dword_47F498);
  v5 = websGetVar(a1, "filename", &dword_47F498);
  p_writepath = (const char *)websGetVar(a1, "fpath", &dword_47F498);
  v7 = (_BYTE *)websGetVar(a1, "readfile", &dword_47F498);
  if ( *v3 )
  {
    snprintf(p_writepath_1, 100, "%s 2>&1 > %s", v3, "/tmp/syscmd.log");
    system(p_writepath_1);
  }

![[Pasted image 20260113113846.png]]
变量p_writepath是通过webGetVar函数获取sysCmd传递过来的。然后使用sprintf函数将得到的结果进行拼接并赋值给p_writepath。但是,这里没有对p_writepath变量进行过滤。因此,如果传递给v20参数中存在系统命令,则将会导致命令执行漏洞。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>

// 假设这是 GoAhead Web Server 的句柄类型
typedef void* webs_t;

// 模拟外部全局变量
extern char *dword_47F498; 
char writepath[256]; // 假设的全局变量,用于记录最后写入的路径

// 模拟 Web Server API
extern char* websGetVar(webs_t wp, char* var, char* defaultVal);
extern void websRedirect(webs_t wp, char* url);

int __fastcall formSysCmd(webs_t wp)
{
    char *redirect_url;    // Var ($s4)
    const char *cmd_val;   // v3 ($s1)
    const char *do_write;  // v4 ($s5)
    const char *filename;  // v5 ($s6)
    const char *base_path; // p_writepath ($s3)
    const char *do_read;   // v7 ($s7)

    FILE *fp;              // v8, v9
    int fd;                // v12
    int data_len;          // *(int *)(a1 + 240)
    char *post_data;       // *(int *)(a1 + 204)
    int i;                 // v13

    // 缓冲区非常小,存在高风险溢出
    char cmd_buffer[104];  // p_writepath_1 [sp+20h]

    // 1. 获取 URL 参数
    redirect_url = websGetVar(wp, "submit-url", ""); // 默认值猜测为空
    cmd_val      = websGetVar(wp, "sysCmd", "");
    do_write     = websGetVar(wp, "writeData", "");
    filename     = websGetVar(wp, "filename", "");
    base_path    = websGetVar(wp, "fpath", "");
    do_read      = websGetVar(wp, "readfile", "");

    // 2. 处理系统命令 (Command Injection 漏洞点)
    if ( cmd_val && *cmd_val )
    {
        // 构造命令字符串: "用户输入 2>&1 > /tmp/syscmd.log"
        snprintf(cmd_buffer, 100, "%s 2>&1 > %s", cmd_val, "/tmp/syscmd.log");
        system(cmd_buffer);
    }

    // 3. 处理文件写入 (Buffer Overflow & Arbitrary File Write 漏洞点)
    if ( do_write && *do_write )
    {
        // 危险:没有检查长度直接拼接
        strcpy(cmd_buffer, base_path);
        strcat(cmd_buffer, filename);

        fp = fopen(cmd_buffer, "w");
        if ( !fp )
        {
            printf("Open %s fail.\n", cmd_buffer);
            return websRedirect(wp, redirect_url);
        }

        // 修改文件权限为 0777
        fd = fileno(fp);
        fchmod(fd, 0777); // 511 decimal is 0777 octal

        // 获取 POST 数据长度和指针 (假设偏移量 240 是 len, 204 是 data)
        // 注意:这里反编译代码中使用了手动操作 FILE 结构体缓冲区的逻辑
        // 为可读性,这里还原为标准的 fwrite 逻辑
        data_len = *(int *)((char *)wp + 240);
        post_data = *(char **)((char *)wp + 204);

        if ( data_len > 0 )
        {
            // 原始代码是一个字节一个字节写的,或者通过 fputc_unlocked
            // 这里简化为标准写法,逻辑一致
            fwrite(post_data, 1, data_len, fp);
        }

        fclose(fp);
        printf("Write to %s\n", cmd_buffer);

        // 更新全局变量
        strcpy(writepath, base_path); 
    }

    // 4. 处理文件读取 (Arbitrary File Read & Command Injection 漏洞点)
    // 检查是否设置了读取标志,且文件是否存在
    if ( do_read && *do_read && (fp = fopen(base_path, "r")) != 0 )
    {
        fclose(fp); // 只是为了检查是否存在,所以立刻关闭

        // 构造命令: "cat [base_path] > /web/obama.dat"
        // 同样存在栈溢出和命令注入风险
        sprintf(cmd_buffer, "cat %s > /web/obama.dat", base_path);
        system(cmd_buffer);

        usleep(10000); // 等待文件系统同步

        // 重定向用户去下载这个文件
        // 这里原代码将 v10 = a1, Var_1 = "/obama.dat"
        websRedirect(wp, "/obama.dat");
        return 0; // 或者 return void
    }
    else
    {
        // 默认重定向回 submit-url
        websRedirect(wp, redirect_url);
        return 0;
    }
}

下面使用firmware-analysis-plus模拟固件

git clone https://github.com/liyansong2018/firmware-analysis-plus.git
cd firmware-analysis-plus
./setup.sh

然后修改 fap.config 文件中的密码,改为 root 系统用户的密码,即可使用。

然后模拟固件运行

➜  firmware-analysis-plus git:(master) ✗ ./fap.py -q ./qemu-builds/2.5.0/ ~/fw/RB-1732_TC_v2.0.43.bin 
/home/ra1ny/firmware-analysis-plus/./fap.py:19: SyntaxWarning: invalid escape sequence '\ '
  print ("""
/home/ra1ny/firmware-analysis-plus/./fap.py:154: SyntaxWarning: invalid escape sequence '\Q'
  cmd = 'sed -i "/QEMU=/c\QEMU={0}/qemu-system-{1}" "{2}"'.format(qemu_dir, arch, runsh_path)


            ______   _                ___                 
            |  ___| (_)              / _ \                
            | |_     _   _ __ ___   / /_\ \  _ __    ___  
            |  _|   | | | '_ ` _ \  |  _  | | '_ \  / __| ++
            | |     | | | | | | | | | | | | | | | | \__ \ 
            \_|     |_| |_| |_| |_| \_| |_/ |_| |_| |___/

            Welcome to the Firmware Analysis Plus - v2.3.1
 By lys - https://github.com/liyansong2018/firmware-analysis-plus

[+] Firmware: RB-1732_TC_v2.0.43.bin
[+] Extracting the firmware...
[+] Image ID: 2
[+] Identifying architecture...
[+] Architecture: mipseb
[+] Building QEMU disk image...
[+] Setting up the network connection, please standby...
[+] Network interfaces: [('br0', '192.168.1.1')]
[+] Using qemu-system-mips from /home/ra1ny/firmware-analysis-plus/qemu-builds/2.5.0
[+] All set! Press ENTER to run the firmware...
[+] When running, press Ctrl + A X to terminate qemu

此时回车,然后访问192.168.1.1admin\admin进入后台,然后访问192.168.1.1/syscmd.asp,此时只需要输入命令即可



评论(0)

查看评论列表

暂无评论


发表评论

表情 颜文字
插入代码