本次参赛,我团队由R0s1e师傅代表出战,秉持着“以赛促学、以赛促练、以赛促战”的理念,全力以赴投入到竞赛中。经过8小时的紧张角逐,最终取得了优异的成绩。
我团队在竞赛中展现出了坚韧不拔的毅力和顽强拼搏的精神。积极应对各种挑战,通过比赛积累了宝贵的经验,进一步提升了团队的技术水平和实战能力。
此次参赛,不仅是一次技术的较量,更是一次团队精神的锤炼。我们将以此为契机,继续加强学习和训练,不断提升自身实力,争取在未来的竞赛中取得更好的成绩,为网络安全事业贡献力量。
以下由团队整理的Write-UP
开源情报==>ez-college
获取到了一张图片
看起来比较像国内,直接使用baidu识图
与题目提供的图片完全吻合,baidu搜索成都大学
flag为:MOCSCTF{chengdu_university}
开源情报==>macau-threat-ops
StopInfo-Stealer——澳门行动,这貌似是一场关于网络安全威胁打击行动,开源情报收集
其中包括澳门警方打击了291台服务器
该题flag为:MOCSCTF{291}
开源情报==>ez-o3int
该题目描述的是:吃完炸鸡,去美容院护肤一下!请找到距离附近最近的美容院,flag 为店铺名称,格式为 MOCSCTF{momo_salon}。(全部小写,空格替换为下划线)
得到一张kfc门店照片
看环境不像是国内 甚至有点东南亚的味道
google识图开始溯源
看到很多是在facebook上的信息,经过多层筛选最终锁定了一条facebook生活社交动态。
文中作者描述一家KFC入驻了Bandar Seri Impian
谷歌地图搜索:Bandar Seri Impian
这个地方是在西马的柔佛州
搜索附近的KFC
全景查看门店,与题目提供的照片达到100%吻合
寻找最近的美容院,最终锁定一家名为:Adiratna Muslimah Salon 的美容沙龙
最终flag是:MOCSCTF{adiratna_muslimah_salon}
逆向==>easysys
深入分析 DriverEntry 函数的伪代码。
DbgPrint(aFlagIsHereYouK);: 这行代码打印了一个字符串。虽然我们没有 aFlagIsHereYouK 的具体内容,但从命名上看,它很可能是一个提示性的字符串,比如 "Flag is here, you know..."。
char v3[48]; 和后续的赋值操作: 程序声明了一个 48 字节的字符数组 v3,并用一系列负整数(-127, -125, -113...)对其进行了初始化。这些负整数很可能是经过某种编码或加密的 Flag 的字节数据。总共有 39 个字节被赋值。
sub_140001030(v3, 204i64);: 这是最关键的一步!程序调用了 sub_140001030 函数,并将 v3 数组和常量 204 传给了它。这个函数很可能就是用来解码或解密 v3 数组中数据的解密函数。 204 这个常量也可能是解密密钥、循环次数或某种偏移量。
DbgPrint("[+] Flag is: %s", v3);: 在调用 sub_140001030 之后,程序立即使用 DbgPrint 打印 v3 数组的内容,并提示 "[+] Flag is: %s"。这意味着,在 sub_140001030 函数执行之后,v3 数组中存储的就应该是解密或解码后的 Flag 字符串!
解密逻辑分析:
这个函数是一个简单的 XOR (异或) 解密函数。
a1是指向待解密字符串 (也就是我们之前在 DriverEntry中看到的v3数组) 的指针。a2是异或的密钥。 函数在一个循环中遍历 a1数组的每个字节,并将其与a2进行异或操作。
encrypted_data =-127, -125, -113, -97, -113, -104, -118, -73, -117, -4, -4, -88, -109,-107, -4, -71, -109, -121, -126, -93, -69, -109, -65, -75, -65, -109,-72, -92, -91, -65, -109, -3, -65, -109, -86, -96, -115, -85, -79]key = 204decrypted_bytes =for byte_val in encrypted_data:unsigned_byte_val = byte_val & 0xFFdecrypted_byte = unsigned_byte_val ^ keydecrypted_bytes.append(decrypted_byte)flag = bytes(decrypted_bytes).decode('ascii')print("The Flag is:", flag)
逆向==>ez-element
获取一个名为main.c文件 进行代码审计
逆转 base64_custom_encode: 将 expected_result 中的汉字序列还原成原始的字节数据。
逆转 rc4: RC4 算法的特性是加密和解密使用相同的过程。所以,对步骤 1 得到的字节数据再次使用 RC4 算法,传入相同的 key = "Mitsuha",就可以得到原始的 Flag 字符串。
破解脚本如下:
import struct# --- 定义 chinese_table 和 padding_char ---chinese_table = ["氢", "氦", "锂", "铍", "硼", "碳", "氮", "氧", "氟", "氖", "钠","镁", "铝", "硅", "磷", "硫", "氯", "氩", "钾", "钙", "钪", "钛","钒", "铬", "锰", "铁", "钴", "镍", "铜", "锌", "镓", "锗", "砷","硒", "溴", "氪", "铷", "锶", "钇", "锆", "铌", "钼", "锝", "钌","铑", "钯", "银", "镉", "铟", "锡", "锑", "碲", "碘", "氙", "铯","钡", "镧", "铈", "镨", "钕", "钷", "钐", "铕", "钆"]padding_char = "金"# 构建汉字到索引的映射chinese_to_index = {char: i for i, char in enumerate(chinese_table)}# --- RC4 解密函数 ---def rc4_decrypt(data_bytes, key_str):S = list(range(256))key_len = len(key_str)j = 0for i in range(256):j = (j + S[i] + ord(key_str[i % key_len])) % 256S[i], S[j] = S[j], S[i] # Swapi = j = 0output_bytes = bytearray(len(data_bytes)) # Use bytearray for mutable sequencefor idx in range(len(data_bytes)):i = (i + 1) % 256j = (j + S[i]) % 256S[i], S[j] = S[j], S[i] # Swapk = S[(S[i] + S[j]) % 256]output_bytes[idx] = data_bytes[idx] ^ kreturn output_bytes# --- Custom Base64 解码函数 ---def base64_custom_decode(encoded_str):decoded_bytes = []# 移除末尾的填充字符 '金'# 注意:如果 Flag 长度恰好是 3 的倍数,可能没有填充# 如果原始加密数据长度不是3的倍数,但汉字末尾没有金,则可能要根据长度推算# 将汉字转换为索引列表indices = []for char in encoded_str:if char == padding_char:indices.append(-1) # 用 -1 标记填充字符elif char in chinese_to_index:indices.append(chinese_to_index[char])else:print(f"Error: Unknown character '{char}' in encoded string. Aborting decode.")return None# 每 4 个索引一组进行解码for i in range(0, len(indices), 4):chunk_indices = indices[i:i+4]# 确定填充的数量pad_count = chunk_indices.count(-1)# 将 -1 (填充标记) 替换为 0,以便进行位运算numeric_indices = [idx if idx != -1 else 0 for idx in chunk_indices]n = (numeric_indices[0] << 18) |(numeric_indices[1] << 12) |(numeric_indices[2] << 6) |numeric_indices[3]# 根据填充的数量,写入对应的字节数decoded_bytes.append((n >> 16) & 0xFF) # 第一个字节总是存在if pad_count < 2: # 如果填充小于2个,说明第二个字节存在decoded_bytes.append((n >> 8) & 0xFF)if pad_count < 1: # 如果填充小于1个,说明第三个字节存在decoded_bytes.append(n & 0xFF)return bytes(decoded_bytes) # 返回字节串# --- 主解密逻辑 ---expected_result_str = "锝钆镨钌镨氙钯钡铕硼铟碘钪锆砷锌砷铁硒镍钐氯硼""铑铍镉钛镁氙氮氦硫铷铟金金"rc4_key = "Mitsuha"print("Starting custom Base64 decode...")rc4_encrypted_data_bytes = base64_custom_decode(expected_result_str)if rc4_encrypted_data_bytes is None:print("Base64 Custom Decode failed.")else:print(f"Base64 Custom Decoded {len(rc4_encrypted_data_bytes)} bytes.")# print(f"Decoded Bytes (RC4 encrypted): {list(rc4_encrypted_data_bytes)}") # 可选:打印中间字节print("Starting RC4 decrypt...")final_flag_bytes = rc4_decrypt(rc4_encrypted_data_bytes, rc4_key)# 尝试多种编码方式,Flag 通常是 ASCII 或 UTF-8try:flag = final_flag_bytes.decode('ascii')print("n[+] The Flag (ASCII) is:", flag)except UnicodeDecodeError:try:flag = final_flag_bytes.decode('utf-8')print("n[+] The Flag (UTF-8) is:", flag)except UnicodeDecodeError:print("n[+] Could not decode Flag with ASCII or UTF-8. Raw bytes:", final_flag_bytes)
逆向==>easysys2
DriverEntry函数初始化一个硬编码字节数组v3,然后调用 sub_140001030 函数(实为XOR解密),传入密钥为0。因XOR 0不改变数据,v3 数组的原始字节即为加密后的Flag。直接解码发现不可读,说明Flag在被硬编码前已通过单字节XOR加密。解题思路:提取v3数组的十六进制原始字节,编写Python脚本,对所有256种可能的单字节XOR密钥进行暴力破解,然后尝试ASCII或UTF-8解码,匹配Flag格式即可。
import sysdef solve_easysys2():# 从 DriverEntry 函数中提取的 v3 数组的原始字节值 (汇编中显示为十六进制)# 之前 Python 脚本中已经正确转换为无符号字节raw_encrypted_bytes = bytes([0xE7, 0xE5, 0xE9, 0xF9, 0xE9, 0xFE, 0xEC, 0xD1, 0xF3, 0x9A, 0xDF, 0xF5, 0xED,0xC5, 0xDE, 0xF5, 0xFE, 0xC2, 0x99, 0xF5, 0xC1, 0x99, 0xF3, 0xF5, 0xF9,0xD3, 0xD9, 0x99, 0xD8, 0xD7])print(f"原始字节流长度: {len(raw_encrypted_bytes)} 字节")print(f"原始字节流 (十六进制): {raw_encrypted_bytes.hex()}")# 尝试所有可能的单字节XOR密钥 (0-255)for key_byte in range(256):decrypted_candidate_bytes = bytearray()for byte_val in raw_encrypted_bytes:decrypted_candidate_bytes.append(byte_val ^ key_byte)# 尝试解码,优先ASCII和UTF-8,因为Flag通常是可读文本try:flag_candidate = decrypted_candidate_bytes.decode('ascii')# 检查 Flag 常见格式if "FLAG{" in flag_candidate or "MOCSCTF{" in flag_candidate or "EASY{" in flag_candidate.upper():print(f"n[+] 找到可能的 Flag (ASCII) with key 0x{key_byte:02x}:")print(f" {flag_candidate}")# 如果找到,可以停止并退出# returnexcept UnicodeDecodeError:pass # 继续尝试其他编码或密钥try:flag_candidate = decrypted_candidate_bytes.decode('utf-8')if "FLAG{" in flag_candidate or "MOCSCTF{" in flag_candidate or "EASY{" in flag_candidate.upper():print(f"n[+] 找到可能的 Flag (UTF-8) with key 0x{key_byte:02x}:")print(f" {flag_candidate}")# returnexcept UnicodeDecodeError:pass # 继续尝试其他编码或密钥print("n单字节XOR暴力破解完成,未能找到明显的 Flag 格式。")print("这可能意味着 Flag 是通过多字节XOR,或其他更复杂的位操作加密的。")# 运行解密函数if __name__ == "__main__":solve_easysys2()
密码学==>ez-klepto
关键验证点
第一部分:直接使用已知素数p1快速分解n1
第二部分:利用相邻素数特性(q2 = next_prime(p2)),通过平方根逼近分解n2
第三部分:小指数攻击(e3=3)且m3^3 < n3,直接开立方恢复明文
第四部分:共模攻击(相同n4不同e),通过扩展欧几里得合并密文
from Crypto.Util.number import long_to_bytesimport gmpy2# ===== 第一部分破解(已知p攻击) =====def part1_decrypt():n1 = 6812896682529270617889699041268397231216344502100994418898483090399363050725238802825519610890413646309466494321918636827383749031784541498873387892731639p1 = 83018022170775357156881992679804004613671250493281300137495505566721083549673e1 = 65537c1 = 4427729071087402462891221302870960264377546560852404414763265602889920597278631371895561554533422266459579128710764143355754615245149034250540901716118396q1 = n1 // p1phi1 = (p1-1)*(q1-1)d1 = pow(e1, -1, phi1) # 计算私钥m1 = pow(c1, d1, n1)return long_to_bytes(m1).decode()# ===== 第二部分破解(相邻素数攻击) =====def part2_decrypt():n2 = 8618941019390135762450560251440447449812344988348002904674567734387521342905027779518989812368861070593805164745239666403382823700616097172234834567736147e2 = 65537c2 = 5090157394401735030895991956180326655655690673641213577889910602055845449426923727333236685488219458241927620516575355892867356153466992699239192192910803sqrt_n2 = gmpy2.isqrt(n2) # 平方根逼近p2 = gmpy2.next_prime(sqrt_n2 - 1000) # 在平方根附近搜索while n2 % p2 != 0:p2 = gmpy2.next_prime(p2)q2 = n2 // p2phi2 = (p2-1)*(q2-1)d2 = pow(e2, -1, phi2)m2 = pow(c2, d2, n2)return long_to_bytes(m2).decode()# ===== 第三部分破解(小指数攻击) =====def part3_decrypt():c3 = 345422409558921105091064923418692102360936093114398968000e3 = 3m3 = gmpy2.iroot(c3, e3)[0] # 直接开立方根return long_to_bytes(m3).decode()# ===== 第四部分破解(共模攻击) =====def part4_decrypt():n4 = 8050202063335318202668477773676061807230884209991655693527143039730083343444420055444708024772406517257344636757261685775610919720030730312364281795306843e4a, e4b = 65537, 65539c4a = 5944697746898769084130690069563137465626689325180948580645355816012208942196895961186706314322689146225405184339425445878469418993890870252122256787094490c4b = 590873621149745423995166880880817186889129377479311590030588253033344142558245476231076545393071246375504750217939956792516706707037717951120503693278372# 扩展欧几里得求系数 [8](@ref)gcd, x, y = gmpy2.gcdext(e4a, e4b)if x < 0: # 负指数处理c4a = gmpy2.invert(c4a, n4)x = -xif y < 0:c4b = gmpy2.invert(c4b, n4)y = -ym4 = (pow(c4a, x, n4) * pow(c4b, y, n4)) % n4return long_to_bytes(m4).decode()# ===== 主程序 =====if __name__ == "__main__":flag_part1 = part1_decrypt()flag_part2 = part2_decrypt()flag_part3 = part3_decrypt()flag_part4 = part4_decrypt()full_flag = flag_part1 + flag_part2 + flag_part3print("="*50)print(f"破解结果: {full_flag}")print("="*50)print("组件验证: ")print(f"Part1: {flag_part1}nPart2: {flag_part2}nPart3: {flag_part3}nPart4: {flag_part4} (应为空)")
密码学==>ez-klepto
该题目的核心漏洞在于连续素数生成和后门密钥构造机制,可恢复私钥并解密flag
from Crypto.Util.number import *from hashlib import sha256import gmpy2# 题目给定参数Y = xxxn = xxxc = xxxe = xxxdef recover_s(Y, n):# 分解Y:利用连续素数漏洞sqrtY = gmpy2.isqrt(Y)P = gmpy2.next_prime(sqrtY)Q = prev = P# 在sqrtY附近搜索连续素数while P * Q != Y:if P * Q > Y:Q = gmpy2.prev_prime(Q)else:P = gmpy2.next_prime(P)if prev == P: # 避免死循环breakprev = P# 计算φ(Y)和d_Yphi_Y = (P-1) * (Q-1)d_Y = gmpy2.invert(e, phi_Y)# 计算c的近似值(通过n右移1024位)T = n >> 1024 # T = floor(n / 2^1024)# 遍历三个候选c值(T-1, T, T+1)for candidate in [T-1, T, T+1]:if candidate <= 0:continue# 解密s:s = c^d_Y mod Ys_candidate = pow(candidate, int(d_Y), Y)# 计算p = next_prime(sha256(str(s) * 4)s_bytes = str(s_candidate).encode() * 4p_candidate = gmpy2.next_prime(int(sha256(s_bytes).hexdigest(), 16))# 验证p是否整除nif n % p_candidate == 0:q_candidate = n // p_candidatereturn s_candidate, p_candidate, q_candidatereturn None# 执行攻击s_val, p_val, q_val = recover_s(Y, n)# 解密flagphi_n = (p_val-1) * (q_val-1)d_flag = gmpy2.invert(e, phi_n)m = pow(c, int(d_flag), n)flag = long_to_bytes(m).decode()print(f"Recovered s: {s_val}")print(f"Recovered p: {p_val}")print(f"Recovered q: {q_val}")print(f"Flag: {flag}")
感谢澳门网络安全暨夺旗竞赛协会举办此次竞赛,为我们提供了学习交流的平台。感谢每一位参赛选手,让这场赛事精彩纷呈。感谢团队的支持与鼓励,让我们在比赛中无惧挑战,砥砺前行。未来,我们将继续努力,不负期望。
推荐站内搜索:最好用的开发软件、免费开源系统、渗透测试工具云盘下载、最新渗透测试资料、最新黑客工具下载……




还没有评论,来说两句吧...