Assistance Required with GL.iNet Router Authentication API

Dear GL.iNet Support Team,

We are working with a GL.iNet router running firmware version 4.5.17 and attempting to connect to it through our mobile application, which is intended for IoT device communication.

We are currently using the following API calls for authentication:

  1. Challenge Request

bash curl -X POST http://192.168.8.1/rpc -d '{"jsonrpc":"2.0","id":1,"method":"challenge","params":{"username":"root"}}'

  1. Login Request

bash

curl 'http://192.168.8.1/rpc' \

  -H 'Accept: application/json, text/plain, */*' \
  -H 'Accept-Language: en-US,en;q=0.9' \
  -H 'Connection: keep-alive' \
  -H 'Content-Type: application/json' \
  -H 'Origin: http://192.168.8.1' \
  -H 'Referer: http://192.168.8.1/' \
  -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36' \
  --data-raw '{"jsonrpc":"2.0","id":2,"method":"login","params":{"username":"root","hash":"0f14baf69fa5420c7ed0e7d0643c9cb5"}}' \
  --insecure

Despite using these endpoints, we are receiving the following error:

{"id":2,"jsonrpc":"2.0","error":{"message":"Access denied","code":-32000}}

We have reviewed the documentation provided at: GL.iNet HTTP RESTful API Documentation, but unfortunately, it hasn’t resolved the issue.

Could you please provide any updated documentation, guidance, or examples on how to successfully authenticate using these APIs?

Thank you very much for your assistance, and we look forward to your response.

best,
Fahad Baig
Technical Lead Manager

My first thought when I started reading your post was, 'how the hash was generated?'.

And this is exactly the problem. That's not router API documentation and actually the router API uses a different hash algorithm.

If you trace the browser request, you will find that the router API uses the unixpass library. Not HmacSHA256.

I recommend to run Burp Suite to catch all requests: Download Burp Suite Community Edition - PortSwigger

There is no official API documentation anymore and I highly doubt it will come back.

1 Like

Thanks Quidn. I am working in Swift language. Can you share a swift example to generate hash with salt, nonce and alg using username and password of the router? Would be a huge help.

1 Like

I know nothing about Swift, but aren't there a built-in function or libraries?
Also openssl passwd will do the same thing.
It's pretty common, but yeah usually needs polyfills nowadays.

I have found the below algorithm in which Hash is being produced but we are not able to replicate it in python or swift:

methods: {
          async handleLogin() {
            if (this.isLoading) return;
            (await this.$refs.loginForm.validate()) &&
              ((this.isLoading = !0),
              c.challenge({ username: this.form.username }).then(
                (t) => {
                  if (!t || !t.err_msg) {
                    const { alg: e, nonce: r, salt: n } = t,
                      o = this.$up.crypt(this.form.password, ⁠ $${e}$${n}$ ⁠),
                      i = this.$md5(this.form.username + ":" + o + ":" + r);
                    this.login({ username: this.form.username, hash: i });
                  }
                },
                (t) => {
                  this.isLoading = !1;
                  const e = JSON.parse(t);
                  "Login fail number over limit" === e.error.message &&
                    (this.$message.closeAll(),
                    this.$message.error(
                      this.$t("login.retry_after").replace(
                        "$$$$",
                        e.error.data.wait,
                      ),
                    ));
                },
              ));
          },
          login(t) {
            c.login(t)
              .then((t) => {
                (this.isLoading = !1),
                  (t && t.err_msg) ||
                    this.$loadMenuRoute().then(() => {
                      this.$route.params.goBack &&
                      "process" !== this.$route.params.goBack
                        ? this.$router.replace({
                            name: this.$route.params.goBack,
                          })
                        : this.$router.replace({ name: "internet" });
                    });
              })
              .catch((t) => {
                this.isLoading = !1;
                "Access denied" === JSON.parse(t).error.message &&
                  (this.$message.closeAll(),
                  this.$message.error(this.$t("login.err_msg")));
              });
          },

Also openssl passwd will do the same thing.

As I said,

  • Basically it's same as the IoT API, but up.crypt rather than the CryptoJS.HmacSHA256.
  • The up.crypt(unixpass) results standard Unix-compatible password hash, also openssl passwd(doc) will do the same.

And what you found is proving it.

I know how to mimic that with JavaScript(unixpass), PHP(crypt), and shell script(openssl), but no idea with Swift or Python.

However it seems there are solutions for Python including built-in one:

And also for Swift:

I don't know if those will work but you will find a solution in any way.