###### tags: `writeups` # Writeup for Zakukozh in CyBRICS ## Description 题目描述如下图: ![](https://i.imgur.com/mU1hsd2.png) 意思是说,这是一个被`Affine Cipher`(仿射密码)加密过的一个图片文件,试着解密。 ## Analysis 仿射密码是个什么东西? [wiki](https://zh.wikipedia.org/wiki/%E4%BB%BF%E5%B0%84%E5%AF%86%E7%A2%BC) ![](https://i.imgur.com/xcahiuN.png) 说白了,就是一个线性变换。 看到只是mod 26,心里一喜,爆破分分钟啊。瞬间又意识到这是个二进制文件,应该不会是mod 26这么简单,估计是mod 256,但这个爆破也分分钟(后面可以看到,其实都不要用1秒)。 题目里面另外一个信息:**图片** 图片格式也就那么几种,能说的上来的也就`png`,`jpg`,... 好吧,说不出来了。 那么。。直接拖进`WinHex`,再把一个真正的`png`图片拖进来,对比分析一下: ![](https://i.imgur.com/cIBktJV.png) 仿射密码就说明,映射是一一对应的。这可以从上图看出,`png`里面一样的byte,在映射后的`bin`中也是一样的!由此推断:是`png`格式的图片没错了。 开始写脚本喽! ## Script 这肯定是mod 256了,有两个未知数`a, b`,那么就有256*256=65536种可能,爆破起来肯定不要太快。其实,仿射密码里的`a`是有限制的,要满足`gcd(a, 256) == 1`,这样还可以减少点计算量。 爆破`a, b`: ```python from Crypto.Util.number import GCD, inverse # d^-1(x) = a^-1 (x - b) % 256 pre = [0x89, 0x50, 0x4e] post = [0x60, 0x09, 0xeb] for a in range(256): if GCD(a,256)!=1: continue inv_a = inverse(a, 256) for b in range(256): q = 1 for i in range(3): if (inv_a * (post[i] - b) ) % 256 != pre[i]: q=0 break if(q): print(a, b) # 15, 89 ``` 结果瞬间就有了,`a = 15, b = 89`。那么接下来只需要一个一个解密就行了: ```python a = 15 inv_a = 239 b = 89 with open("zakukozh.bin", "rb") as f1: t = f1.read() with open("flag.png", "wb") as f2: for c in t: p = inv_a * (c - b) % 256 f2.write(bytes[p]) ``` 打开写好的文件,获得`flag`: ![](https://i.imgur.com/WB77S4d.png) ## Summary 还是需要再深入了解下图片文件的格式,这样分析起来就更有感觉了。