Sekiro Environment Basic Setup for WSS

1. Server Deployment

Project Repository: https://github.com/yint-tech/sekiro-open

Official Documentation: https://sekiro.iinti.cn/sekiro-doc/01_manual/4.server_install.html

The deployment environment is Ubuntu 20.

Installation Steps:

  1. Install Docker, you can refer to this article: https://blog.csdn.net/qq_44732146/article/details/121207737

  2. Install docker-compose: sudo pip install docker-compose

  3. Install Sekiro:

    After starting Docker, execute the following command:

    curl https://oss.iinti.cn/sekiro/quickstart.sh | bash
    
  4. Open the URL http://(server's IP):5612 and register an account (the first registered account is the super administrator).

img.png

2. Client Connecting to the Server

You can refer to the official documentation for details on connecting the client to the server.

If your injected website has same-origin policy interception for wss, even if a wss connection can be created, it may be blocked due to same-origin issues.
Assuming the website being accessed is: https://xxx.abc.com
Using wss to connect to Sekiro: wss://sekiro.iinti.cn/business/register?group=ws-group&clientId=1221
If www.abc.com has a same-origin policy interception, it may result in an error: refused to connect to 'wss://sekiro.iinti.cn/business/register?group=ws-group&clientId=1221' because of it violates the following Content Security Policy directive: xxxxxx

Pre-installation of CA Certificate

Click here for the pem format or the crt format to download the certificate, and follow the system prompts to install the root certificate.

Method 1: Using a Proxy to Solve CSP

Sekiro’s port service implements an HTTP/HTTPS proxy, allowing you to directly set Sekiro’s port as the proxy for your browser.

If your injected website has same-origin policy interception for wss, you can set your browser’s proxy to the Sekio server. At this point, since all traffic passes through the Sekiro server, and Sekiro has the CA root certificate to decrypt and forge traffic, wss connections can be directly constructed using the corresponding main webpage domain. Sekiro can perceive that this connection needs to be forwarded to the Sekiro server and will automatically handle it internally.

This method can perfectly solve the wss same-origin interception problem.

Please note that when accessing Sekiro through a proxy, Sekiro must have SSL decryption enabled. At this point, it is essential to install Sekiro’s CA certificate (as mentioned above). Otherwise, HTTPS web pages will be blocked due to the certificate being untrusted.

Method 2: Constructing Subdomain to Solve CSP

If the entire Sek

function FindProxyForURL(url, host) {
  if (shExpMatch(url, "wss://*")) {
    // 只要是wss协议,则代理到sekiro.iinti.cn:5612
    // 这里实现比较粗暴,具体规则可根据网站实际调整
    return "PROXY sekiro.iinti.cn:5612";
  }
  return "DIRECT";
}
  1. Constructing a WebSocket connection with the exact same domain as the target website.
var client = new SekiroClient(
  "wss://xxx.abc.com/business/register?group=test-ws&clientId=" + Math.random()
);
client.registerAction("testAction", function (request, resolve, reject) {
  resolve("ok");
});
  1. Constructing Subdomain to Resolve CSP

    1. Assuming the website “sekiro” is deployed at: 47.93.16.121:443
    2. Configuring the hosts file: sekrio.xxx.abc.com 47.93.16.121 to resolve the domain sekiro.xxx.abc.com to 47.93.16.121 (effectively simulating the acquisition of a domain name, binding it to the sekiro server, and ensuring that this domain name is a subdomain of the target website)
    3. Installing the CA certificate, ensuring the system root certificate is installed, and setting trust for the sekiro certificate
    4. Using the constructed subdomain for the wss connection: wss://sekiro.xxx.abc.com/business/register?group=ws-group&clientId=1221 to establish a connection

    Condition: It requires support for wss in the CSP rule: connect-src wss:, otherwise, only proxy mode can be used. This is because the CSP rule considers that HTTP pages should not be loaded by WebSockets: https://csplite.com/csp118/

wss Injection

Copy the official code:

function SekiroClient(e) {
  if (((this.wsURL = e), (this.handlers = {}), (this.socket = {}), !e))
    throw new Error("wsURL can not be empty!!");
  (this.webSocketFactory = this.resolveWebSocketFactory()), this.connect();
}
(SekiroClient.prototype.resolveWebSocketFactory = function () {
  if ("object" == typeof window) {
    var e = window.WebSocket ? window.WebSocket : window.MozWebSocket;
    return function (o) {
      function t(o) {
        this.mSocket = new e(o);
      }
      return (
        (t.prototype.close = function () {
          this.mSocket.close();
        }),
        (t.prototype.onmessage = function (e) {
          this.mSocket.onmessage = e;
        }),
        (t.prototype.onopen = function (e) {
          this.mSocket.onopen = e;
        }),
        (t.prototype.onclose = function (e) {
          this.mSocket.onclose = e;
        }),
        (t.prototype.send = function (e) {
          this.mSocket.send(e);
        }),
        new t(o)
      );
    };
  }
  if ("object" == typeof weex)
    try {
      console.log("test webSocket for weex");
      var o = weex.requireModule("webSocket");
      return (
        console.log("find webSocket for weex:" + o),
        function (e) {
          try {
            o.close();
          } catch (t) {}
          return o.WebSocket(e, ""), o;
        }
      );
    } catch (t) {
      console.log(t);
    }
  if ("object" == typeof WebSocket)
    return function (o) {
      return new e(o);
    };
  throw new Error("the js environment do not support websocket");
}),
  (SekiroClient.prototype.connect = function () {
    console.log("sekiro: begin of connect to wsURL: " + this.wsURL);
    var e = this;
    try {
      this.socket = this.webSocketFactory(this.wsURL);
    } catch (o) {
      console.log("sekiro: create connection failed,reconnect after 2s"),
        setTimeout(function () {
          e.connect();
        }, 2e3);
    }
    this.socket.onmessage(function (o) {
      e.handleSekiroRequest(o.data);
    }),
      this.socket.onopen(function (e) {
        console.log("sekiro: open a sekiro client connection");
      }),
      this.socket.onclose(function (o) {
        console.log("sekiro: disconnected ,reconnection after 2s"),
          setTimeout(function () {
            e.connect();
          }, 2e3);
      });
  }),
  (SekiroClient.prototype.handleSekiroRequest = function (e) {
    console.log("receive sekiro request: " + e);
    var o = JSON.parse(e),
      t = o.__sekiro_seq__;
    if (!o.action)
      return void this.sendFailed(t, "need request param {action}");
    var n = o.action;
    if (!this.handlers[n])
      return void this.sendFailed(t, "no action handler: " + n + " defined");
    var s = this.handlers[n],
      i = this;
    try {
      s(
        o,
        function (e) {
          try {
            i.sendSuccess(t, e);
          } catch (o) {
            i.sendFailed(t, "e:" + o);
          }
        },
        function (e) {
          i.sendFailed(t, e);
        }
      );
    } catch (r) {
      console.log("error: " + r), i.sendFailed(t, ":" + r);
    }
  }),
  (SekiroClient.prototype.sendSuccess = function (e, o) {
    var t;
    if ("string" == typeof o)
      try {
        t = JSON.parse(o);
      } catch (n) {
        (t = {}), (t.data = o);
      }
    else "object" == typeof o ? (t = o) : ((t = {}), (t.data = o));
    (Array.isArray(t) || "string" == typeof t) && (t = { data: t, code: 0 }),
      t.code ? (t.code = 0) : t.status ? (t.status = 0) : (t.status = 0),
      (t.__sekiro_seq__ = e);
    var s = JSON.stringify(t);
    console.log("response :" + s), this.socket.send(s);
  }),
  (SekiroClient.prototype.sendFailed = function (e, o) {
    "string" != typeof o && (o = JSON.stringify(o));
    var t = {};
    (t.message = o), (t.status = -1), (t.__sekiro_seq__ = e);
    var n = JSON.stringify(t);
    console.log("sekiro: response :" + n), this.socket.send(n);
  }),
  (SekiroClient.prototype.registerAction = function (e, o) {
    if ("string" != typeof e) throw new Error("an action must be string");
    if ("function" != typeof o) throw new Error("a handler must be function");
    return (
      console.log("sekiro: register action: " + e), (this.handlers[e] = o), this
    );
  });

var client = new SekiroClient(
  "wss://www.linkedin.cn/business/register?group=ws-group&clientId=" +
    Math.random()
);
client.registerAction("testAction", function (request, resolve, reject) {
  c = undefined;
  resolve(window.ja("d_incareer2_profile_homepage", c));
});

Browser calls the interface, successful

img_1.png