i春秋 第二届春秋欢乐赛 Misc 题目名称:CryMisc

i春秋 第二届春秋欢乐赛

分值:300分 类型:Misc题目名称:CryMisc

题目内容:Download

 

下载链接:

http://static2.ichunqiu.com/icq/resources/fileupload/CTF/icqhappyctf/CryMisc_E1C844B98C4CAC14060994BD1933AF9F.zip

 

审题发现题目只给了一个下载链接,

1,点击Download下载了一个压缩包,解压后有两个文件,crypto.zip和jiami.py

打开jiami.py文件内容如下:

# -*- coding:utf8 -*-

import pyminizip
from hashlib import md5
import os
          
def create(files, zfile):
    password = os.urandom(15)#随机产生一个15字节的字符串
    password = md5(password).hexdigest()#获取这个字符串的md5值
    pyminizip.compress_multiple(files, zfile, password, 0)#这是一个压缩文件的方法把files参数中文件压缩成zfile指定的文件,压缩密码是password,0可以理解为复杂程度值为1~9,默认是0
    pass
      
if __name__ == '__main__':
    files = ['jiami.py','gogogo.zip']
    zfile = 'crypto.zip'#就是把jiami.py和gogogo.zip两个文件压缩成crypto.zip密码是上面随机字符串的md5值
    create(files, zfile)

 

 

接下来打开crypto.zip提示有密码,也就是上述md5值,这个密码我们是不知道的。

因为crypto.zip压缩包中有jiami.py文件,而jiami.py这个文件是已知的,因此我们可以用zip明文攻击。

明文攻击需要利用两个压缩包(已知文件的压缩包,和加密的需要破解的压缩包),这两个压缩包压缩方式要相同,直接对jiami.py文件进行压缩是不行的,也要用python 的pyminizip模块进行压缩,脚本如下:

# -*- coding: cp936 -*-
import pyminizip
pyminizip.compress(r"jiami.py","",r"jiami.zip","",0)#没有密码

 

然后进行明文攻击,利用一个工具apzr

爆破成功保存为压缩包UnEncrypted.zip解压后得到gogogo.zip,

解压得到AES.encryt、AESencrypt.py和RSA.encrypt三个文件

2,打开AESencrypt.py文件如下:

# -*- coding:utf8 -*-
from Crypto.Cipher import AES

s=open('next.zip','rb').read()
BS=16
pad_len=BS-len(s)%BS
padding=chr(pad_len)*pad_len
s+=padding#把最后不满16个字节的用所缺字节个数值ASCII码对应的字符补足16个字节,如缺5个字节就补5个ascii码为5的字符,因为AES明文是128bit的倍数

key='我后来忘了'#AES秘钥(未知)
n=0x48D6B5DAB6617F21B39AB2F7B14969A7337247CABB417B900AE1D986DB47D971#两个大素数p与q乘积
e=0x10001#RSA公钥65537
m=long(key.encode('hex'),16)#秘钥key转16进制转整型,作为RSA的明文
c=pow(m,e,n)#c是RSA加密后的密文
c='0{:x}'.format(c).decode('hex')
with open('RSA.encrypt','wb') as f:
    f.write(c)

#RSA.encrypt文件的16进制就是RSA的密文,即就是AES秘钥key加密后的密文,已知
obj=AES.new(key,AES.MODE_ECB)
with open('AES.encryt','wb') as f:
    f.write(obj.encrypt(s))#对next.zip进行AES加密,秘钥为key,AES.encryt文件中的内容即为AES加密后的密文已知。

 

整合已有信息就是,已知AES加密后的密文要解出AES的明文;但是AES秘钥不知道,要先求出AES秘钥key

key就是RSA的明文,已知RSA的密文c,两个大素数乘积n也已知可以求出p,q,然后求出RSA私钥,然后根据私钥,密文,n可以求出RSA明文(就是AES的秘钥key),然后根据AES密文和秘钥key就能解除AES的明文。

 

首先n转成10进制为 32945885482421841602167475970472000545315534895409154025267147105384142461297

登录网站http://factordb.com/,对n进行因数分解,解出p和q

 

 

脚本如下:

# -*- coding: cp936 -*-
from Crypto.PublicKey import RSA
from Crypto.Cipher import AES
def egcd(a,b):
    if a==0:
        return (b,0,1)
    else:
        g,y,x=egcd(b%a,a)
        return (g,x-(b//a)*y,y)
def modinv(a,m):
    g,x,y=egcd(a,m)
    if g!=1:
        raise Exception('modular inverse does not exist')
    else:
        return x%m

p=177334994338425644535647498913444186659
q=185783328357334813222812664416930395483
n=32945885482421841602167475970472000545315534895409154025267147105384142461297
e=65537#公钥

d=modinv(e,(p-1)*(q-1))#RSA私钥
c=open("RSA.encrypt","rb").read();
c=long(c.encode('hex'),16)
m=pow(c,d,n)#m是明文,转成字符串就是key="copy__white__key"
key="copy__white__key"
obj=AES.new(key,AES.MODE_ECB)
s=open("AES.encryt","rb").read()
str=obj.decrypt(s)
with open(r'next.zip','wb') as f:
    f.write(str)#解密后得到next.zip文件

 

3,解压next.zip文件得到encrypt.py、first、second三个文件。

打开encrypt.py内容如下:

# -*- coding:utf8 -*-
from base64 import *

s=open('flag.jpg','rb').read()
s='-'.join(map(b16encode,list(s)))

#list(s)每个字节(一个字符)作为列表的一项

#map(b16encode,list(s)),列表的每一项都执行b16encode(这个函数其实是得到字符对应的十六进制值),并将结果作为新列表中的项

#'-'.join(),列表中的每项都用‘-’分隔。

#最终的执行结果是flag.jpg文件的用‘-’分隔字节的十六进制数据

s=map(''.join,zip(*(s.split('-'))))

#zip(*(s.split('-')))得到两个元组,一个是每个字节的第一个16进制值组成的,一个是每个字节的第二个16进制值组成的

#然后作为一个新列表

with open('first','wb') as f:
    f.write(b16decode(s[0]))#把第一个列表元素转成字符串写入first文件
with open('second','wb') as f:
    f.write(b16decode(s[1]))#把第二个列表元素转成字符串写入second文件

 

代码分析完也就是把flag.jpg文件的16进制值分成了两部分,每个字节的前4位组合成first文件,后4位组合成second文件。写脚本如下:

# -*- coding: cp936 -*-
from base64 import *
s1=open(r'first','rb').read()
s2=open(r'second','rb').read()
s1=''.join(map(b16encode,list(s1)))#获取16进制数据
s2=''.join(map(b16encode,list(s2)))
str=""
for i in range(0,len(s1)):
    str+=s1[i]+s2[i];#得到flag.jpg16进制数据
str=str.decode('hex')
with open(r'flag.jpg','wb') as f:
    f.write(str)
  

得到flag.jpg图片

4,打开图片没有flag信息,用winhex(或010 Editor)打开查看16进制数据,在图片结尾(FFD9)后面还有内容,

16进制头为38 42 50 53,根据文件头可以知道这是psd(Photoshop Document)文件,利用formost分离文件失败,直接把第一个FFD9后面的所有16进制数据复制成一个新文件,打开010Editor,复制保存为flag.psd文件。用photoshop打开flag.psd文件(用fireworks也行),打开后图片上有一行字flag{少年,我看好你!}

我以为这是flag,提交好几遍都错误。再观察图层发现有一个空白的背景

其实最顶层的文字是假的,这里关键在于锁定的“背景”层,看似是新建图片时所留下的默认背景图,而本题就是把flag隐藏在里面,把上面2层隐藏掉,然后对背景色另存为png格式(这样才能完好的保留颜色),使用stegsolve打开,并按下向左的按钮 得到一个二维码,扫描得到flag

 

 

 

 

 

 

 

 

 

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

z2bns

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值