本次参赛,我团队由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 = 204
decrypted_bytes =
for byte_val in encrypted_data:
unsigned_byte_val = byte_val & 0xFF
decrypted_byte = unsigned_byte_val ^ key
decrypted_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 = 0
for i in range(256):
j = (j + S[i] + ord(key_str[i % key_len])) % 256
S[i], S[j] = S[j], S[i] # Swap
i = j = 0
output_bytes = bytearray(len(data_bytes)) # Use bytearray for mutable sequence
for idx in range(len(data_bytes)):
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i] # Swap
k = S[(S[i] + S[j]) % 256]
output_bytes[idx] = data_bytes[idx] ^ k
return 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-8
try:
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 sys
def 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}")
# 如果找到,可以停止并退出
# return
except 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}")
# return
except 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_bytes
import gmpy2
# ===== 第一部分破解(已知p攻击) =====
def part1_decrypt():
n1 = 6812896682529270617889699041268397231216344502100994418898483090399363050725238802825519610890413646309466494321918636827383749031784541498873387892731639
p1 = 83018022170775357156881992679804004613671250493281300137495505566721083549673
e1 = 65537
c1 = 4427729071087402462891221302870960264377546560852404414763265602889920597278631371895561554533422266459579128710764143355754615245149034250540901716118396
q1 = n1 // p1
phi1 = (p1-1)*(q1-1)
d1 = pow(e1, -1, phi1) # 计算私钥
m1 = pow(c1, d1, n1)
return long_to_bytes(m1).decode()
# ===== 第二部分破解(相邻素数攻击) =====
def part2_decrypt():
n2 = 8618941019390135762450560251440447449812344988348002904674567734387521342905027779518989812368861070593805164745239666403382823700616097172234834567736147
e2 = 65537
c2 = 5090157394401735030895991956180326655655690673641213577889910602055845449426923727333236685488219458241927620516575355892867356153466992699239192192910803
sqrt_n2 = gmpy2.isqrt(n2) # 平方根逼近
p2 = gmpy2.next_prime(sqrt_n2 - 1000) # 在平方根附近搜索
while n2 % p2 != 0:
p2 = gmpy2.next_prime(p2)
q2 = n2 // p2
phi2 = (p2-1)*(q2-1)
d2 = pow(e2, -1, phi2)
m2 = pow(c2, d2, n2)
return long_to_bytes(m2).decode()
# ===== 第三部分破解(小指数攻击) =====
def part3_decrypt():
c3 = 345422409558921105091064923418692102360936093114398968000
e3 = 3
m3 = gmpy2.iroot(c3, e3)[0] # 直接开立方根
return long_to_bytes(m3).decode()
# ===== 第四部分破解(共模攻击) =====
def part4_decrypt():
n4 = 8050202063335318202668477773676061807230884209991655693527143039730083343444420055444708024772406517257344636757261685775610919720030730312364281795306843
e4a, e4b = 65537, 65539
c4a = 5944697746898769084130690069563137465626689325180948580645355816012208942196895961186706314322689146225405184339425445878469418993890870252122256787094490
c4b = 590873621149745423995166880880817186889129377479311590030588253033344142558245476231076545393071246375504750217939956792516706707037717951120503693278372
# 扩展欧几里得求系数 [8](@ref)
gcd, x, y = gmpy2.gcdext(e4a, e4b)
if x < 0: # 负指数处理
c4a = gmpy2.invert(c4a, n4)
x = -x
if y < 0:
c4b = gmpy2.invert(c4b, n4)
y = -y
m4 = (pow(c4a, x, n4) * pow(c4b, y, n4)) % n4
return 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_part3
print("="*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 sha256
import gmpy2
# 题目给定参数
Y = xxx
n = xxx
c = xxx
e = xxx
def 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: # 避免死循环
break
prev = P
# 计算φ(Y)和d_Y
phi_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 Y
s_candidate = pow(candidate, int(d_Y), Y)
# 计算p = next_prime(sha256(str(s) * 4)
s_bytes = str(s_candidate).encode() * 4
p_candidate = gmpy2.next_prime(int(sha256(s_bytes).hexdigest(), 16))
# 验证p是否整除n
if n % p_candidate == 0:
q_candidate = n // p_candidate
return s_candidate, p_candidate, q_candidate
return None
# 执行攻击
s_val, p_val, q_val = recover_s(Y, n)
# 解密flag
phi_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}")
感谢澳门网络安全暨夺旗竞赛协会举办此次竞赛,为我们提供了学习交流的平台。感谢每一位参赛选手,让这场赛事精彩纷呈。感谢团队的支持与鼓励,让我们在比赛中无惧挑战,砥砺前行。未来,我们将继续努力,不负期望。
推荐站内搜索:最好用的开发软件、免费开源系统、渗透测试工具云盘下载、最新渗透测试资料、最新黑客工具下载……
还没有评论,来说两句吧...