# 3. 遍历密文每一个字节进行解密 for byte in encrypted_bytes: # 生成加密时使用的同一个随机数 random_key = random.randint(0, 255) # 异或逆运算:A ^ B = C => C ^ B = A original_byte = byte ^ random_key decrypted_flag.append(original_byte)
# 4. 输出结果 print(bytes(decrypted_flag).decode())
FLAG
1
pascalCTF{1ts_4lw4ys_4b0ut_x0r1ng_4nd_s33d1ng}
Ice Cramer
Challenge
Elia’s swamped with algebra but craving a new ice-cream flavor, help him crack these equations so he can trade books for a cone!
这道题是一个典型的解线性方程组的编程题。
题目逻辑分析
Flag 转变量:题目将 flag 中的每个字符转换成其 ASCII 码值,这些值构成了方程组的未知数 x_0, x_1, ... x_n。
生成方程:
如果有 n 个未知数(即 flag 长度为 n),服务器会生成 n 个线性方程。
每个方程的形式为 k0*x_0 + k1*x_1 + ... = Solution,系数 k 是随机生成的整数。
目标:连接服务器,获取这 n 个方程,解出未知数 x_i(即字符的 ASCII 码),然后将它们拼回成 Flag。
解题思路
连接与接收:使用 pwntools 连接服务器,接收所有方程字符串。
解析数据:使用正则表达式从每个方程中提取系数矩阵 A 和结果向量 B。
求解方程:使用 numpy 或 scipy 的线性代数库解 Ax = B。
还原 Flag:将解出的 x 向量中的浮点数四舍五入转为整数,再转为 ASCII 字符拼接,最后加上 pascalCTF{} 包裹。
defsolve(): # 建立连接 r = remote(HOST, PORT) # 接收欢迎信息 r.recvuntil(b"Welcome to the Penguin's Challenge!") # 构建密文映射表 (Cipher -> Word) cipher_map = {} print("[*] Building encryption oracle dictionary...") # 我们有 7 轮,每轮发 4 个单词,正好发完 28 个 # 将单词列表分块,每块 4 个 chunk_size = 4 word_chunks = [words[i:i + chunk_size] for i inrange(0, len(words), chunk_size)] for chunk in word_chunks: # 等待服务器提示输入 r.recvuntil(b"Give me 4 words") # 依次发送 4 个单词 for word in chunk: r.sendlineafter(b": ", word.encode()) # 接收加密结果 # 服务器输出格式: "Encrypted words: hex1 hex2 hex3 hex4" r.recvuntil(b"Encrypted words: ") encrypted_line = r.recvline().decode().strip() encrypted_list = encrypted_line.split(' ') # 将结果存入映射表 for plain, cipher inzip(chunk, encrypted_list): cipher_map[cipher] = plain print(f" Mapped: {plain} -> {cipher[:8]}...")
# 此时我们已经耗尽了 7 轮机会,服务器会打印目标密文 print("[*] Dictionary built. Retrieving challenge ciphertext...") r.recvuntil(b"Ciphertext: ") challenge_ciphertext = r.recvline().decode().strip() target_ciphers = challenge_ciphertext.split(' ') print(f"[*] Target Ciphers: {target_ciphers}") # 解密(查找映射表) answers = [] for c in target_ciphers: if c in cipher_map: answers.append(cipher_map[c]) else: print(f"[-] Error: Cipher {c} not found in map!") return
print(f"[+] Decrypted words: {answers}") # 发送答案 # 题目要求依次输入 5 个猜测 for i, ans inenumerate(answers): r.sendlineafter(f"Guess the word {i+1}: ".encode(), ans.encode()) result = r.recvline().decode() if"Correct"in result: print(f"[+] Word {i+1} Correct!") else: print(f"[-] Word {i+1} Failed: {result}") return
# 获取 Flag flag = r.recvall().decode().strip() print("\n" + "="*40) print(flag) print("="*40) r.close()
if __name__ == "__main__": solve()
FLAG
1
pascalCTF{why_4r3_th3_bl0ck_4lw4ys_th3_s4m3???}
Curve Ball
Challenge
Our casino’s new cryptographic gambling system uses elliptic curves for provably fair betting.
We’re so confident in our implementation that we even give you an oracle to verify points!
# 2. 生成边框坐标 (逻辑完全复制自题目脚本) coords = [] # Top: (0,0) to (w-1, 0) for x inrange(width): coords.append((x, 0)) # Right: (w-1, 1) to (w-1, h-2) for y inrange(1, height-1): coords.append((width-1, y)) # Bottom: (w-1, h-1) to (0, h-1) if height > 1: for x inrange(width-1, -1, -1): coords.append((x, height-1)) # Left: (0, h-2) to (0, 1) if width > 1: for y inrange(height-2, 0, -1): coords.append((0, y))
# 3. 提取二进制位 binary_str = "" for coord in coords: r, g, b = img.getpixel(coord) # 判断颜色 # 黑色 (0,0,0) -> '0' # 白色 (255,255,255) -> '1' # JPG 可能有噪声,用亮度判断 if r + g + b > 382: # (255*3)/2 binary_str += "1" else: binary_str += "0" # 4. 转换二进制为文本 decoded_chars = [] # 每 8 位转一个字符 for i inrange(0, len(binary_str), 8): byte = binary_str[i:i+8] iflen(byte) < 8: break try: char_code = int(byte, 2) decoded_chars.append(chr(char_code)) except: pass full_text = "".join(decoded_chars) # 5. 寻找 Flag print("\n--- Extracted Text Preview ---") print(full_text[:200]) # 打印前 200 个字符预览 print("\n--- Searching for Flag ---") if"pascalCTF{"in full_text: start = full_text.find("pascalCTF{") end = full_text.find("}", start) if end != -1: print(f"Flag found: {full_text[start:end+1]}") else: print(f"Flag start found: {full_text[start:]}") else: # 有时候 Flag 可能会重复,我们尝试打印所有可能的重复段 print("Flag pattern not directly found. Printing raw text (check for repetitions):") print(full_text)
if __name__ == "__main__": solve_stego()
FLAG
1
pascalCTF{Wh41t_wh0_4r3_7h0s3_9uy5???}
Stinky Slim
Challenge
I don’t trust Patapim; I think he is hiding something from me.
Solution
1
OPEN A TICKET SAYING YOU LOVE BLAISE PRASCAL TO GET THE FLAG
print("[*] Checking inventory for Flag...") # 5. 查看库存 res = s.get(f"{TARGET_URL}/inventory") # 寻找 Flag if"pascalCTF{"in res.text: import re flag = re.search(r"pascalCTF\{.*?\}", res.text).group(0) print("\n" + "="*40) print(f"FLAG: {flag}") print("="*40) else: print("[-] Flag not found in inventory. Check response dump.") # print(res.text)
if __name__ == "__main__": exploit()
FLAG
1
pascalCTF{w3_l1v3_f0r_th3_z4z4}
Travel Playlist
Challenge
1 2 3
Nel mezzo del cammin di nostra vita mi ritrovai per una selva oscura, ché la diritta via era smarrita.
return encoded_phrase defquestions(name): gained_aura = 0 questions = [ "Do you believe in the power of aura? (yes/no)", "Do you a JerkMate account? (yes/no)", "Are you willing to embrace your inner alpha? (yes/no)", "Do you really like SHYNE from Travis Scott? (yes/no)", ] aura_values = [(150,-50), (-1000,50),(450,-80),(-100,50)] for i inrange(len(questions)): print(f"{name}, {questions[i]}") answer = input("> ").strip().lower() if answer == "yes": gained_aura += aura_values[i][0] elif answer == "no": gained_aura += aura_values[i][1] return gained_aura
defaura_test(name): print(f"{name}, you have reached the final AuraTest!") print("If you want to win your prize you need to decode this secret phrase:",encoder(phrase, steps))
guess = input("Type the decoded phrase to prove your worth:\n> ") if guess == phrase: print(f"Congratulations {name}! You have proven your worth and gained the ultimate aura!\nHere's your price:\n{flag}") exit() else: print(f"Dont waste my time {name}, you failed the AuraTest. Try again but this time use all your aura!")
print("Welcome to the AuraTester2000!\nHere, we will make sure you have enough aura to join our alpha gang.")
while(True): name = input("First of all, we need to know your name.\n> ") if(name.strip() == ""): print("You didn't start very well, I asked your named stupid npc.") else: print(f"Welcome {name} to the AuraTester2000!") print("""⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣦⣀⠀⠀⢀⣴⣷⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⢀⣿⡿⠟⠛⠛⠻⢿⣿⡄⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠈⢷⣦⣤⣤⡾⠋⠀⣴⣾⣷⣦⠀⠙⢿⣦⣤⣤⣾⠃⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠘⣿⣿⠟⠀⠀⢸⣿⣿⣿⣿⡇⠀⠀⠹⣿⣿⡏⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⣀⣴⣿⡏⠀⠀⠀⠘⢿⣿⣿⡿⠃⠀⠀⠀⠹⣿⣷⣀⠀⠀⠀⠀⠀ ⠀⠀⠲⣾⣿⣿⣿⣿⠀⠀⠀⢀⣤⣾⣿⣿⣷⣦⡀⠀⠀⠀⢿⣿⣿⣿⣿⠖⠂⠀ ⠀⠀⠀⠈⠙⢿⣿⡇⠀⠀⠀⣾⣿⣿⣿⣿⣿⣿⣿⡀⠀⠀⢸⣿⣿⠟⠁⠀⠀⠀ ⠀⠀⠀⠀⠀⢨⣿⡇⠀⠀⢰⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠘⣿⣏⠀⠀⠀⠀⠀ ⠀⠀⠀⢀⣠⣾⣿⡇⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⢰⣿⣿⣦⡀⠀⠀⠀ ⠀⠀⠺⠿⢿⣿⣿⣇⠀⠀⠘⠛⣿⣿⣿⣿⣿⣿⠛⠃⠀⠀⢸⣿⣿⡿⠿⠗⠂⠀ ⠀⠀⠀⠀⠀⠈⠻⣿⡀⠀⠀⠀⢹⣿⣿⣿⣿⣿⠀⠀⠀⠀⣿⡿⠉⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⢠⣿⣧⠀⠀⠀⢸⣿⣿⣿⣿⡏⠀⠀⠀⣼⣿⡇⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⣠⣾⣿⣿⣧⡀⠀⢸⣿⣿⣿⣿⡇⠀⠀⣼⣿⣿⣿⣄⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠓⠀⠘⠛⠛⠛⠛⠃⠀⠚⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀""") break
aura = 0
while(True): print("\n\n1. Answer questions to gain or lose aura.\n\n2. Check your current aura.\n\n3. Take the final AuraTest to prove your worth.\n\n4. Exit the AuraTester2000.") choice = input("What do you want to do little Beta?\n> ") if (choice == "1"): print("You choose to answer questions. Let's see how much aura you can gain!") gained_aura = questions(name) if(aura > 0): print(f"Congratulations {name}! You gained {gained_aura} aura points.") else: print(f"Sorry {name}, you lost {gained_aura} aura points. Learn how to be a real Sigma!") aura += gained_aura
elif(choice == "2"): print(f"Your current aura is {aura}.") elif(choice == "3"): if(aura < 500): print("You need more aura to even try the final AuraTest.") else: aura_test(name) elif(choice == "4"): print("Exiting the AuraTester2000. Goodbye!") exit() else: print("Invalid option. Please try again.")
获取足够的 “Aura” (光环值)
查看代码中的 questions 函数,我们需要达到 500 分以上才能进入最终测试。
四个问题的分值逻辑如下:
“Do you believe…”: Yes (+150), No (-50) -> 选 yes
“Do you a JerkMate…”: Yes (-1000), No (+50) -> 选 no
“Are you willing…”: Yes (+450), No (-80) -> 选 yes
“Do you really like…”: Yes (-100), No (+50) -> 选 no
总分:150 + 50 + 450 + 50 = 700 分 (> 500),满足条件。
解码加密字符串
进入 Option 3 后,服务器会给出一串加密的字符。
加密逻辑:
phrase 是从固定的 words 列表中随机抽取 3 到 5 个词组成的,用空格连接。
steps 是 2 到 5 之间的一个随机整数。
遍历字符串,如果索引 i 能被 steps 整除,将该字符转换为 ASCII 数值字符串;空格保持不变;其他字符保持不变。