文章总结: 本文为SHCTF2026哈希碰撞题目WriteUp。hash1利用未过滤输入使用已知MD5碰撞值解题。hash2通过hashclash工具生成符合字母数字前缀限制的碰撞数据。hash3利用hashclash脚本构造前缀不同的TwinKeys碰撞。文章详细展示了针对不同限制条件利用MD5弱点解题的全过程,提供了具体命令与脚本,具有很强的可操作性。 综合评分: 95 文章分类: CTF,漏洞分析,安全工具,实战经验
SHCTF 2026 hash1-3 WriteUp
原创
Pirater Pirater
Pirater
2026年3月9日 19:43 广东
上个月在SHCTF2026出了几道题,都是关于哈希碰撞的题。比赛快结束的时候电脑坏了,所以官方WriteUp是让g0ubu1i师傅代写的,非常感谢!!!现在换新电脑了,特此补上这篇本来应该写的WriteUp。
hash1
题目代码
import hashlib
with open("/flag.txt","r") as f:
flag = f.read().strip()
msg = input(f"Give me both different apples (hex(apple1), hex(apple2)) : ")
try:
apples = msg.split(",")
apple1 = bytes.fromhex(apples[0])
apple2 = bytes.fromhex(apples[1])
hash_apple1 = hashlib.md5(apple1).hexdigest()
hash_apple2 = hashlib.md5(apple2).hexdigest()
if apple1 == apple2:
print(f"Oh snap, both apples are exactly the same")
elif hash_apple1 != hash_apple2:
print(f"Oh no, they taste different")
else:
print(f"Yeah, both apples are delicious!!! This is your prize: {flag}")
except:
print(f"format fault :(")
exit()
解题思路
题目的意思是让我们给出两个不同的字符串,使得md5(apple1) = md5(apple2)。那么这里一定有什么缺陷,能使得两个不同的字符串相同。
搜索一下hash,vulnerability类似的关键词,就能搜出类似collsion的字眼。
这里搜出了维基百科的哈希碰撞词条:https://en.wikipedia.org/wiki/MD5#Collision_vulnerabilities
由于题目并没有检查我们的输入,所以我们可以用前人已经搓出来的哈希值。而维基百科里面也给了两条现成的值,我们直接拿来用就行了。
hash1
这里结合pwntools写了一个交互脚本(建议学习pwntools的使用哦):
from pwn import *
hex_m1 = 'd131dd02c5e6eec4693d9a0698aff95c2fcab58712467eab4004583eb8fb7f8955ad340609f4b30283e488832571415a085125e8f7cdc99fd91dbdf280373c5bd8823e3156348f5bae6dacd436c919c6dd53e2b487da03fd02396306d248cda0e99f33420f577ee8ce54b67080a80d1ec69821bcb6a8839396f9652b6ff72a70'
hex_m2 = 'd131dd02c5e6eec4693d9a0698aff95c2fcab50712467eab4004583eb8fb7f8955ad340609f4b30283e4888325f1415a085125e8f7cdc99fd91dbd7280373c5bd8823e3156348f5bae6dacd436c919c6dd53e23487da03fd02396306d248cda0e99f33420f577ee8ce54b67080280d1ec69821bcb6a8839396f965ab6ff72a70'
io = remote("", ) # 填入网址和端口
entry = f"{hex_m1},{hex_m2}".encode()
io.sendlineafter(b" : ",entry)
flag = io.recvline().strip(b"\n").decode().split(": ")[-1]
io.close()
print(flag)
hash2
题目代码
import hashlib
import string
with open("/flag.txt","r") as f:
flag = f.read().strip()
msg = input(f"Give me both special apples (hex(apple1), hex(apple2)) : ")
try:
table = (string.ascii_letters + string.digits).encode()
apples = msg.split(",")
apple1 = bytes.fromhex(apples[0])
apple2 = bytes.fromhex(apples[1])
hash_apple1 = hashlib.md5(apple1).hexdigest()
hash_apple2 = hashlib.md5(apple2).hexdigest()
if len(apple1) <= 16 or len(apple2) <= 16:
print(f"Both apples are too small")
elif not all(ch in table for ch in apple1[:16]) or not all(ch in table for ch in apple2[:16]):
print(f"No, both apples are too ordinary")
elif apple1 == apple2:
print(f"Oh snap, both apples are exactly the same")
elif hash_apple1 != hash_apple2:
print(f"Oh no, they taste different")
else:
print(f"Yeah, both apples are delicious!!! This is your prize: {flag}")
except:
print(f"format fault :(")
exit()
解题思路
和上题相比,本题强制要求前十六个字符在大小写字母和数字的范围内,并且两条消息不能完全相等而哈希值得相等。
直接用维基百科的两条消息肯定是会失败的,所以这里我们选择自己生成两条消息。
哈希碰撞的工具并不难找:https://marc-stevens.nl/research/hashclash/
找Win32位可运行的版本即可,否则编译也要时间,有点麻烦。
hash2
将WelcometoSHCTF2025输入到1.txt保存,然后把它拖拽到exe文件,自动就会生成两个文件1_msg1.txt和1_msg2.txt。将两个文件的字节读取后再转十六进制,传给服务器即可得到flag。
from pwn import *
with open("1_msg1.txt","rb") as f:
m1 = f.read()
with open("1_msg2.txt", "rb") as f:
m2 = f.read()
hex_m1 = bytes.hex(m1)
hex_m2 = bytes.hex(m2)
io = remote("challenge-only-test-for-prepare.shc.tf", 31700)
entry = f"{hex_m1},{hex_m2}".encode()
io.sendlineafter(b" : ",entry)
flag = io.recvline().strip(b"\n").decode().split(": ")[-1]
io.close()
print(flag)
hash3
题目代码
import hashlib
import string
with open("/flag.txt","r") as f:
flag = f.read().strip()
msg = input(f"Give me both special apples (hex(apple1), hex(apple2)) : ")
try:
table = (string.ascii_letters + string.digits).encode()
apples = msg.split(",")
apple1 = bytes.fromhex(apples[0])
apple2 = bytes.fromhex(apples[1])
hash_apple1 = hashlib.md5(apple1).hexdigest()
hash_apple2 = hashlib.md5(apple2).hexdigest()
if len(apple1) <= 16 or len(apple1) <= 16:
print(f"Both apples are too small")
elif not all(ch in table for ch in apple1[:16]) or not all(ch in table for ch in apple2[:16]):
print(f"No, both apples are too ordinary")
elif apple1[:16] == apple2[:16]:
print(f"Oh snap, both apples are the same")
elif hash_apple1 != hash_apple2:
print(f"Oh no, they taste different")
else:
print(f"Yeah, both apples are delicious!!! This is your prize: {flag}")
except:
print(f"format fault :(")
exit()
解题思路
题目来源:https://cryptohack.org/challenges/hashes/的Twin Keys。
题意很简单,需要构造构造两个前缀不同且哈希值相同的明文。
找到这个工具并且下载:https://github.com/cr-marcstevens/hashclash/releases/tag/hashclash-static-release-v1.2b
输入以下命令:
mkdir hash3
cd hash3
echo "SHCTF2025ISFUNNY" > prefix.txt
../scripts/poc_no.sh prefix.txt
hexdump -v -e '/1 "%02X"' collision1.bin
hexdump -v -e '/1 "%02X"' collision2.bin
解题脚本(需要一点时间):
from pwn import *
hex_m1 = "534843544632303235495346554E4E592DA1C748F4B488F5CEB4DD3FEFB90404BDD1865069B4EE374D9D9F86D1B57CC48224E19BAA422DE18F47806702A6D17B05194901DFF4446D9D40DBD9DA84DC4A523A23C33FF3D4ECFC1564C16F999B5B2DADC97BB14ECA2A3185F8E53058D0CD3259A94AA7808A6A00281806250493D3" # 将hexdump后得到的十六进制串填上去
hex_m2 = "5348435446323032354A5346554E4E592DA1C748F4B488F5CEB4DD3FEFB90404BDD1865069B4EE374D9D9F86D1B57CC48224E19BAA422DE18F47806702A6D17B05194901DFF4446D9D3FDBD9DA84DC4A523A23C33FF3D4ECFC1564C16F999B5B2DADC97BB14ECA2A3185F8E53058D0CD3259A94AA7808A6A00281806250493D3"
io = remote("", )
entry = f"{hex_m1},{hex_m2}".encode()
io.sendlineafter(b" : ",entry)
flag = io.recvline().strip(b"\n").decode().split(": ")[-1]
io.close()
print(flag)
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:Pirater Pirater Pirater《SHCTF 2026 hash1-3 WriteUp》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论