[HFCTF2020]虎符部分web

/ 0评 / 0

昨天看了一下题,大概有些简单的思路,BUU上了复现环境,今天及时来复现一下,顺便学一些新的知识

[HFCTF2020]EasyLogin

打开靶机,一个登录界面

查看页面源代码,看到 app.js 中有以下注释

猜测有任意文件读取,经过队内师傅提醒,有一个 controllers/api.js 尤其重要
读一下代码逻辑

我们发现传入 username 和 password,先判断 username 不为 admin,然后生成一个 秘钥 ,生成一个 jwt 令牌

登录页面中进行JWT的验证,如果通过就登录

flag中,如果登录的用户名是admin,就输出flag
所以我们的思路是---构造用户名为admin拿到flag
JSNOTE也是一门弱语言,根据之前PHP和JWT的经验
如果我们设置secretid为数组,加密算法为空

<span class="hljs-keyword">const</span> jwt=<span class="hljs-built_in">require</span>(<span class="hljs-string">'jsonwebtoken'</span>);
<span class="hljs-keyword">const</span> secretid=[];
<span class="hljs-keyword">const</span> username=<span class="hljs-string">'admin'</span>;
<span class="hljs-keyword">const</span> password=<span class="hljs-string">'123456'</span>;
<span class="hljs-built_in">console</span>.log(jwt.sign({secretid,username,password}, <span class="hljs-literal">null</span>, {<span class="hljs-attr">algorithm</span>: <span class="hljs-string">'none'</span>});

能不能绕过呢
再试亿次
尝试过以后发现我们需要先随意注册一个用户,在登录的时候将username和password设置成jwt中的数据,更改Authorization为我们伪造的jwt,forward到本地,即可登录

然后访问一下flag地址即可获得flag


[HFCTF2020]JustEscape

打开靶机

随意fuzz一下(fuzz一天),发现是一个notejs的代码
传入var err = new Error();err.stack;出现错误信息

Error
at vm.js:1:11
at Script.runInContext (vm.js:131:20)
at VM.run (/app/node_modules/vm2/lib/main.js:219:62)
at /app/server.js:51:33
at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)
at next (/app/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/app/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)
at /app/node_modules/express/lib/router/index.js:281:22
at Function.process_params (/app/node_modules/express/lib/router/index.js:335:12)

发现一个VM2,需要沙盒逃逸
到github找一下VM2逃逸的payload
https://github.com/patriksimek/vm2/issues/225
代码复制过来
过滤了部分字符。用数组就可以绕过
发现还过滤了return

执行命令就行了
在guoke师傅的WP中还写道

js中. 可以用[]代替.
TypeError.prototype==TypeError[\xxx\xxx\xxx\xxx]
``反引号代替双引号

所以在VM2的那个github中

这个也可以代替使用,
在赵师傅的博客中使用了占位符来拼接字符串

比如这里 prototype 被过滤了,我们可以这样书写
<code>${${prototyp}e}

https://www.zhaoj.in/read-6512.html


[HFCTF2020]BabyUpload

这题是最难的了,当时是完全不会,赛后看着WP复现下
咕咕咕来了
给了源码

<?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['usernmae']==='admin' 并且检测var/babyctf/success.txt是否存在
如果存在删除该文件并直接输出flag
然后的代码我就看不懂了

$direction 参数决定是download还是upload
可以发现,attr会直接拼接在babyctf/的后面,如果attr==='orivate'则会直接把用户名拼接
然后来看一下这个upload功能
我们审计后可以发现,文件名拼接在后面,加上 _ 和这个文件内容的 sha256 摘要值,文件是我们上传的,文件内容的sha256可以在本地算出。然后判断是否有路径穿越,逐级创建目录,将文件储存到下面
再看看下载操作
读取文件名,返回文件内容。
所以我们现在可以知道想要读取文件需要伪造session为admin,并且在babyctf目录下创建一个success.txt,即可返回flag
首先我们来读取一下当前session是什么内容吧
发现返回了username:guest
根据之前的题意,就构造一下吧
然后算一下sha256
php -r "echo hash_file('sha256', '1.php');"
得到:
432b8b09e30c4a75986b719d1312b63a69f1b833ab602c9ad5f0299d1d76a5a4
然后将这个改名为 sess,上传
尝试访问一下
发现返回了admin
那么第一步就完成了
然后构造success.txt
用 file_exists 函数判断文件是否存在的。
官方手册说到这个函数是判断文件或者目录是否存在,文件名不可控但目录可控呀
我们将其改为 success.txt,即可创建一个 success.txt 目录。
然后再次刷新页面就存在flag啦

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注