• 2020天翼杯--APITest


    时间是真的紧

    源码

    const express = require("express"); 
    const cors = require("cors"); 
    const app = express(); 
    const uuidv4 = require("uuid/v4"); 
    const md5 = require("md5"); 
    const jwt = require("express-jwt"); 
    const jsonwebtoken = require("jsonwebtoken"); 
    const server = require("http").createServer(app); 
    const { flag, secret, jwtSecret } = require("./flag"); 
    const config = { 
        port: process.env.PORT || 8081, 
        adminValue: 1000, 
        message: "Can you get flag?", 
        secret: secret, 
        adminUsername: "kirakira_dokidoki", 
        whitelist: ["/", "/login", "/init", "/source"], 
    }; 
    let users = { 
        0: { 
            username: config.adminUsername, 
            isAdmin: true, 
            rights: Object.keys(config) 
        } 
    }; 
    app.use(express.json()); 
    app.use(cors()); 
    app.use( 
        jwt({ secret: jwtSecret }).unless({ 
            path: config.whitelist 
        }) 
    ); 
    app.use(function(error, req, res, next) { 
        if (error.name === "UnauthorizedError") { 
            res.json(err("Invalid token or not logged in.")); 
        } 
    }); 
    function sign(o) { 
        return jsonwebtoken.sign(o, jwtSecret); 
    } 
    function ok(data = {}) { 
        return { status: "ok", data: data }; 
    } 
    function err(msg = "Something went wrong.") { 
        return { status: "error", message: msg }; 
    } 
    function isValidUser(u) { 
        return ( 
            u.username.length >= 6 && 
            u.username.toUpperCase() !== config.adminUsername.toUpperCase() && u.username.toUpperCase() !== config.adminUsername.toLowerCase() 
        ); 
    } 
    function isAdmin(u) { 
        return (u.username.toUpperCase() === config.adminUsername.toUpperCase() && u.username.toUpperCase() === config.adminUsername.toLowerCase()) || u.isAdmin; 
    } 
    function checkRights(arr) { 
        let blacklist = ["secret", "port"]; 
        if(blacklist.includes(arr)) { 
            return false; 
        } 
        for (let i = 0; i < arr.length; i++) { 
            const element = arr[i]; 
            if (blacklist.includes(element)) { 
                return false; 
            } 
        } 
        return true; 
    } 
    app.get("/", (req, res) => { 
        res.json(ok({ hint:  "You can get source code from /source"})); 
    }); 
    app.get("/source", (req, res) => { 
        res.sendFile( __dirname + "/" + "app.js"); 
    }); 
    app.post("/login", (req, res) => { 
        let u = { 
            username: req.body.username, 
            id: uuidv4(), 
            value: Math.random() < 0.0000001 ? 100000000 : 100, 
            isAdmin: false, 
            rights: [ 
                "message", 
                "adminUsername" 
            ] 
        }; 
        if (isValidUser(u)) { 
            users[u.id] = u; 
            res.send(ok({ token: sign({ id: u.id }) })); 
        } else { 
            res.json(err("Invalid creds")); 
        } 
    }); 
    app.post("/init", (req, res) => { 
        let { secret } = req.body; 
        let target = md5(config.secret.toString());//config 
        let adminId = md5(secret) 
            .split("") 
            .map((c, i) => c.charCodeAt(0) ^ target.charCodeAt(i)) 
            .reduce((a, b) => a + b); 
        res.json(ok({ token: sign({ id: adminId }) })); 
    }); 
    

    // Get server info
    app.get("/serverInfo", (req, res) => {
    let user = users[req.user.id] || { rights: [] };
    let info = user.rights.map(i => ({ name: i, value: config[i] }));
    res.json(ok({ info: info }));
    });
    app.post("/becomeAdmin", (req, res) => {
    let {value} = req.body;
    let uid = req.user.id;
    let user = users[uid];
    let maxValue = [value, config.adminValue].sort()[1];//0x30
    if(value >= maxValue && user.value >= value) {
    user.isAdmin = true;
    res.send(ok({ isAdmin: true }));
    }else{
    res.json(err("You need pay more!"));
    }
    });
    // only admin can update user
    app.post("/updateUser", (req, res) => {
    let uid = req.user.id;
    let user = users[uid];
    if (!user || !isAdmin(user)) {
    res.json(err("You're not an admin!"));
    return;
    }
    let rights = req.body.rights || [];
    if (rights.length > 0 && checkRights(rights)) {
    users[uid].rights = user.rights.concat(rights).filter((value, index, self)=>{
    return self.indexOf(value) === index;
    });
    }
    res.json(ok({ user: users[uid] }));
    });
    // only uid===0 can get the flag
    app.get("/flag", (req, res) => {
    if (req.user.id == 0) {
    res.send(ok({ flag: flag }));
    } else {
    res.send(err("Unauthorized"));
    }
    });
    server.listen(config.port, () =>
    console.log(Server listening on port ${config.port}!)
    );

    /login路由用来登陆获取token,不过这里用户验证严格不能直接成为admin
    /init 输入secret,并和config中的secret做异或操作,并赋值给id

    /flag id=0即输出flag

    /serverInfo用来输出用户信息,包括权限等,但是有waf不能查看secret

    /updateUser用来向用户添加权限

    /becomeAdmin输入value,满足条件就成为admin

    思路:先随便用个名字登陆,拿token

    图片

    然后在becomeAdmin出传value=30,sort排序后会令maxvalue=30,绕过验证成为admin

    图片

    成为admin之后去updateUser添加secret权限

    这里的rights可用如下来绕

    {"rights": [["secret"]]} 

    图片

    serverInfo中使用的是config[i]

    图片

    如下依然能获取到值

    图片

    而 这样check函数中得到的就是[secret]

    现在再去serverInfo就会看到config中secret的值了

    图片

    此时在init中我们只要让secret等于这个value,就能让异或结果为0,达到让用户id=0

    图片

    查看flag

    图片

  • 相关阅读:
    nginx.conf中配置laravel框架站点
    centos6.4下安装php7+nginx+mariadb环境
    Windows Terminal 安装和运行
    微软 WSL 重装操作系统
    Pulumi 如何在 Windows 环境中设置
    Ubuntu 20.04 安装 JDK
    代码的 Lint 是什么意思
    CentOS 8 手动安装 Go 1.16 版本
    Raspberry Pi 安装 go 后提示错误 Exec format error
    系统管理--查看网卡、内存等
  • 原文地址:https://www.cnblogs.com/W4nder/p/13520129.html
Copyright © 2020-2023  润新知