VolgaCTF2015之lcg的writeup
来源:互联网 发布:女生脚的味道知乎 编辑:程序博客网 时间:2024/06/05 02:32
题目描述:
Check out our brand-new cipher. It’s super-fast and moderately secure.
#!/usr/bin/pythonimport structimport osM = 65521class LCG(): def __init__(self, s): self.m = M (self.a, self.b, self.state) = struct.unpack('<3H', s[:6]) def round(self): self.state = (self.a*self.state + self.b) % self.m return self.state def generate_gamma(self, length): n = (length + 1) / 2 gamma = '' for i in xrange(n): gamma += struct.pack('<H', self.round()) return gamma[:length]def encrypt(data, key): assert(len(key) >= 6) lcg = LCG(key[:6]) gamma = lcg.generate_gamma(len(data)) return ''.join([chr(d ^ g) for d,g in zip(map(ord, data), map(ord, gamma))])def decrypt(ciphertext, key): return encrypt(ciphertext, key)def sanity_check(): data = 'A'*100 key = os.urandom(6) ciphertext = encrypt(data, key) decrypted_data = decrypt(ciphertext, key) assert(data == decrypted_data)if __name__ == '__main__': with open('flag.png', 'rb') as f: data = f.read() key = os.urandom(6) enc_data = encrypt(data, key) with open('flag.enc.bin', 'wb+') as f: f.write(enc_data)
本题给出了一份python加密程序的源码和一个密文文件,需要通过源码逆向出密钥key来破解以获得flag。
解题的关键点如下:
1、通过加密文件名flag.png.bin可知原文件为png图片,从而可知明文的前8个字节为0x89504E470D0A1A0A,即png图片的固定文件头。而密文的前8个字节为0x5FC79CA8BCE94A78。这两组8字节是逆向出密钥key的基础。
2、加密过程实际是一个XOR过程,在破解出密钥key后,只需利用原加密程序重新XOR一次即可,无需自行编写程序。
3、理解python的struct库的pack和unpack函数。Struct库是python用来解析数据的工具:
struct.pack(‘H’, x)表示(H前有个<符号,不知为啥就是显示不出来?),将x按照H格式,以小端优先的规则解析。其中,H表示无符号短整型(两字节),网上有完整的类型表,可查阅;而“<”表示little-endian,即小端优先。举例如下:
gamma = struct.pack('<H', 38870)#38870的16进制为97d6print "gamma : ", binascii.b2a_hex(gamma)#结果为d697
struct.unpack(‘<3H’, x)表示,将x以小端优先的规则还原成H格式,结果以tuple形式输出。其中,3表示需还原3个无符号短整型(相当于6字节)。举例如下:
p = struct.unpack('<3H', "0d1d0a") #共分成三个元素,即0d、1d、0a,每个元素按照小端优先(即d0、d1、a0)的原则还原为H格式print p #结果为(25648,25649,24880),相当于16进制的(6430,6431,6130),即(d0, d1,a0)
4、加密程序本质上就是,将明文数据与通过密钥key生成的gamma字符串按字节XOR得到密文,而gamma字符串的计算过程可简写为:
self.state = (self.a*self.state + self.b) % self.m (*)n = (datalength + 1) / 2gamma = ''for i in xrange(n): gamma += struct.pack('<H', self.state)
其中,m是常数65521。a、b和state是6字节密钥key通过struct.unpack(‘<3H’, x)获得的三元tuple,而state会根据(*)式迭代更新,每一轮的state会带入下一轮的计算。
同时,尽管n仅为明文数据长度的一半,但由于struct.pack解析出的数据均为H格式(双字节),故gamma的长度与明文长度是一致的。
5、根据1可知,gamma字符串的前8字节为明文与密文的XOR结果:
明文:0x89504E470D0A1A0A
密文:0x99CE83E95DE0D8E0
Gamma:0x109ecdae50eac2ea
故可得下面等式:
65521 * x + 40464 = a * s + b (40464即109e的小端优先9e10的对应整数)
65521 * y + 44749 = a * 40464 + b (上一轮的余数40464作为s带入下一轮)
65521 * z + 59984 = a * 44749 + b
65521 * w + 60098 = a * 59984 + b
从而可得:
65521 * (w-z) + 114 = a * 15235
又知a的取值范围为(0,65535),可通过以下代码爆破出a,计算可得唯一解a=44882。
同理可得b=50579,s=37388。
for a in range(0, 65535): tmp = a * 15235 - 114 if tmp % 65521 == 0: print "a : ", a
6、由a、b、s,根据struct的规则可得:
a=44882->AF52->52AF
b=50579->C593->93C5
s=37388->920C->0C92
密钥key为:52AF93C50C92
带入原加密程序即可还原图片得到flag。
Flag:{linear_congruential_generator_isn’t_good_for_crypto}
- VolgaCTF2015之lcg的writeup
- LCG外汇交易的要点介绍
- HackIM web的writeup
- pwnable.kr writeup之unlink
- Xss挑战之旅writeup
- CTF writeup之pwn2own warehouse
- asis-ctf的writeup收集
- Lcg框架介绍
- Lcg框架组件说明
- 三个白帽之来自星星的你(一)writeup
- pwnable.kr writeup之simple login
- 170611 逆向-gctf的debug的writeup
- 求助:LCG随机数序列分析
- 线性同余算法 (LCG)
- CUIT CTF WriteUp-女神的秘密
- CUIT CTF WriteUp-最简单的题目
- 韩国wargame v2.0的一些writeup
- 2099年的flag——writeup
- android入门系列之 编译android源代码以及ramdisk.img system.img userdata.img 介绍
- 黑马程序员—C语言—函数小结
- 开始刷题leetcode day3: Path Sum
- VC++动态链接库(DLL)编程深入浅出(zz)
- 延伸的正则表达式
- VolgaCTF2015之lcg的writeup
- 否定先生的第一个CSDN博客
- css 利用table 及 noWrap 实现一列优先使用宽度,另外一列自适应
- linux安装jdk
- 定时任务-quartz的使用,实现可页面化管理
- 根据内核来创建线程--SetThreadAffinityMask函数的使用
- android 自带压力测试工具monkey
- Java List ArrayList用法详解
- 系统引导源码分析bootsect.s