SCTF2019 Crypto-warmup writeup
题外话
其实这道题在比赛过程中并没有解出来,思路完全想偏导致无解就放弃了,后来研究了大佬的writeup大半天才看懂。。。
正文
nc获取题目信息,返回一段明文和密文,要求输入一段明文和密文。
题目源码:
# server.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
from Crypto.Cipher import AES
from Crypto.Util.strxor import strxor
from Crypto.Random import get_random_bytes
from FLAG import flag
class MAC:
def __init__(self):
self.key = get_random_bytes(16)
self.iv = get_random_bytes(16)
def pad(self, msg):
pad_length = 16 - len(msg) % 16
return msg + chr(pad_length) * pad_length
def unpad(self, msg):
return msg[:-ord(msg[-1])]
def code(self, msg):
res = chr(0)*16
for i in range(len(msg)/16):
res = strxor(msg[i*16:(i+1)*16], res)
aes = AES.new(self.key, AES.MODE_CBC, self.iv)
return aes.encrypt(res).encode('hex')
def identity(self, msg, code):
if self.code(msg) == code:
msg = self.unpad(msg)
if msg == 'please send me your flag':
print 'remote: ok, here is your flag:%s' % flag
else:
print 'remote: I got it'
else:
print 'remote: hacker!'
if __name__ == '__main__':
mac = MAC()
message = 'see you at three o\'clock tomorrow'
print 'you seem to have intercepted something:{%s:%s}' %(mac.pad(message).encode('hex'), mac.code(mac.pad(message)))
print 'so send your message:'
msg = raw_input()
print 'and your code:'
code = raw_input()
mac.identity(msg.decode('hex'), code)
exit()
通过identity
函数可知,自己输入的明文在服务端加密后要等于自己输入的密文(也就是self.code(msg) == code
,才能得到flag。
同时题目的坑点(也是我思路想歪的地方)就在这地方, 因为要求你输入的明文加密后等于你输入的密文,同时,加密使用的AES的CBC模式,对你的明文的加密是使用的和返回的第一段明文密文相同的iv和key,因此自然想到要得到iv和key才能求出要输入的密文。但是iv和key是通过随机数生成的,所以就无法用这个方法。
那么换一种思路,我们看看加密函数code
如何工作的:
def code(self, msg):
res = chr(0)*16
for i in range(len(msg)/16):
res = strxor(msg[i*16:(i+1)*16], res)
aes = AES.new(self.key, AES.MODE_CBC, self.iv)
return aes.encrypt(res).encode('hex')
既然AES无法破解,那么先看一下送进AES加密前明文,是将原明文分为每16位一组然后接连异或得到的16位字符串res
,并且这个res
我们可以求出来,也就相当于知道“明文”了。
如果我们直接使用第一段返回的'code'作为自己输入的'code',那么我们只需要构造一串明文,使其通过code
函数中AES加密前的操作,得到的结果,等于第一段的'res',这样输入到服务端加密后的结果也等于了输入的'code'(即第一段code)。
好了,现在就开始考虑如何构造明文。
为了得到flag,我们倒着推明文,看identity
函数,满足msg == 'please send me your flag'
才能得到flag,其上一步是msg = self.unpad(msg)
要求输入的明文脱去填充后的字符串是“please send me your flag”,看一下unpad
函数,msg[:-ord(msg[-1])]
和填充函数pad
是相反的作用,即取末尾字符的ASCII码表示的范围之前的字符串。
现在我们将“please send me your flag”的长度记作len1 == 24
,由于AES加密的要求,字符串填充后的长度要满足为16的倍数,因此这里可填充8+16n个字符(n=0,1,2...)。根据unpad
函数,必须让填充后的字符串最末尾一个字符的ASCII码可表示填充的位数。
先跑一下code
函数中的一部分(就是AES加密前),得出第一段密文前一阶段的'res':
message = '73656520796f75206174207468726565206f27636c6f636b20746f6d6f72726f770f0f0f0f0f0f0f0f0f0f0f0f0f0f0f'
for i in range(len(msg)/16):
res = strxor(msg[i*16:(i+1)*16], res)
print(res.encode('hex'))
# res结果为24054d4c1a0f19444e0f4016080f1805
目标就是我们填充后的字符串异或处理后与上面的res(这里记作res1
)相等。
我们设“please send me your flag”加上8位填充的32位并进行16位分组后得到的两个16位字符串为m1和m2(暂时先不管填充是什么)。由异或运算的性质可知,a XOR b XOR b = a。设m3为一个能使m1 XOR m2 XOR m3 XOR m4== res1的16位分组,由此可知m3 == res1 XOR m1 XOR m2 XOR m4。同时要满足字符串最末尾一个字符的ASCII码可表示填充的位数,并且此时字符串总长度位48,因此就再加一个16位m4分组保证最后一位表示填充长度(这里是40)。
那么如何得到m3呢,就是用code
函数里的异或方式。
到此我们就完全知道要构造的输入明文了。
下面是解题的完整代码:
from Crypto.Cipher import AES
from Crypto.Util.strxor import strxor
from Crypto.Random import get_random_bytes
flag = 'test'
class MAC:
def __init__(self):
self.key = get_random_bytes(16)
self.iv = get_random_bytes(16)
def pad(self, msg):
pad_length = 16 - len(msg) % 16
return msg + chr(pad_length) * pad_length
def unpad(self, msg):
return msg[:-ord(msg[-1])]
def code(self, msg):
res = chr(0)*16
for i in range(len(msg)/16):
res = strxor(msg[i*16:(i+1)*16], res)
print(res.encode('hex')) # 输出res1
aes = AES.new(self.key, AES.MODE_CBC, self.iv)
return aes.encrypt(res).encode('hex')
def identity(self, msg, code):
if self.code(msg) == code:
msg = self.unpad(msg)
if msg == 'please send me your flag':
print 'remote: ok, here is your flag:%s' % flag
else:
print 'remote: I got it'
else:
print 'remote: hacker!'
if __name__ == '__main__':
mac = MAC()
message = 'see you at three o\'clock tomorrow'
print 'you seem to have intercepted something:{%s:%s}' %(mac.pad(message).encode('hex'), mac.code(mac.pad(message)))
print 'so send your message:'
msg = 'please send me your flag'
# 使用和pad函数一样的填充方式先构成64位
msg_p = msg + chr(64 - len(msg)) * (64 - len(msg))
# 生成m1 XOR m2 XOR m4
res = chr(0)*16
for i in range(len(msg_p)/16 - 1):
res = strxor(msg_p[i*16:(i+1)*16], res)
# 最终输入的明文字符串
# strxor("24054d4c1a0f19444e0f4016080f1805".decode('hex'), res) 即为上文的m3
msg_p = msg_p[:32] + strxor("24054d4c1a0f19444e0f4016080f1805".decode('hex'), res) + msg_p[32:38]
# 输出明文串
print(msg_p.encode('hex'))
print 'and your code:'
code = raw_input()
mac.identity(msg_p.encode('hex').decode('hex'), code)
exit()
将得到的明文字符串输入,再将服务端返回的密文输入,就得到flag了。
参考
我主要参考这篇文章写出来的,所以思路也大都汲取自这位大佬的:
SCTF2019 部分题目WriteUp
搞懂之后感觉这道题真是妙啊(虽然我没做出来)。
SCTF2019 Crypto-warmup writeup的更多相关文章
- 攻防世界 WEB 高手进阶区 HCTF 2018 warmup Writeup
攻防世界 WEB 高手进阶区 HCTF 2018 warmup Writeup 题目介绍 题目考点 PHP代码审计 Writeup 打开 http://220.249.52.134:37877 常规操 ...
- 实验吧Crypto题目Writeup
这大概是一篇不怎么更新的没什么用的网上已经有了很多差不多的东西的博客. 变异凯撒 忘记了2333 传统知识+古典密码 先查百度百科,把年份变成数字,然后猜测+甲子的意思,一开始以为是加1,后来意识到是 ...
- picoCTF2018记录
近期准备参加CTF 一头雾水 开始练练手 https://2018game.picoctf.com/ 这个网站挺适合新手的(据说面向高中生?? 惭愧惭愧) 前面几个比较简单 就从 Resources ...
- Crypto CTF 2019 writeup
Crypto CTF 2019 writeup roXen 题目 roXen Relationship with a cryptographer! The Girlfriend: All you ev ...
- 攻防世界-Crypto高手进阶区部分Writeup
1.flag_in_your_hand && flag_in_your_hand1 下载,解压后 打开index文件,直接点击get flag错误,输入其他点击也同样 打开js文件,在 ...
- 参加 Tokyo Westerns / MMA CTF 2nd 2016 经验与感悟 TWCTF 2016 WriteUp
洒家近期参加了 Tokyo Westerns / MMA CTF 2nd 2016(TWCTF) 比赛,不得不说国际赛的玩法比国内赛更有玩头,有的题给洒家一种一看就知道怎么做,但是做出来还需要洒家拍一 ...
- We Chall-Training: Crypto - Caesar I-Writeup
MarkdownPad Document html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,ab ...
- 网络信息安全攻防学习平台 上传,解密通关writeup
上传关 [1]查看源代码,发现JS代码.提交时onclick进行过验证.ctrl+shift+i 打开开发者工具,将conclick修改为 return True,即可以上传上传php文件,拿到KEY ...
- 2018国赛 - Writeup(待补充)
10.0.0.55 Writeup Web 0x01 easyweb 解题思路 题目很脑洞 用户名admin 密码123456进去可得到flag(密码现在换了) 解题脚本 无 Reverse 0x02 ...
随机推荐
- iOS开发之压缩与解压文件
ziparchive是基于开源代码”MiniZip”的zip压缩与解压的Objective-C 的Class,使用起来非常的简单 方法:从http://code.google.com/p/ziparc ...
- 一款简单的C++猜数字游戏(新手必学)
前言本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理.作者:1只小弛 废话不多说,直接上代码! #include<bits/s ...
- 基于 .NET Core 的简单文件服务器
Netnr.FileServer 基于 .NET Core 的简单文件服务器,数据库为SQLite 源码 https://github.com/netnr/blog https://gitee.com ...
- 1.使用大clob入库出错问题
在代码中调用pstm.setString(str) str>4000,这种大字符串插入时出现字符过长插入报错问题. 解决问题:用声明变量方式: <insert id ="inse ...
- 【spring boot】配置信息
======================================================================== 1.feign 超时配置 2.上传文件大小控制 3.J ...
- where和having区别
壹: where后面不能跟聚合函数(sum.avg.count.max.min) having后面可以跟 贰: where和having都能用: select goods_price,goods_na ...
- springcloud-微服务架构基础
一 前言 学习微服务要从基础的架构学起,首先你要有个微服务的概念才能学习对吧!!如果你都不知道啥是微服务,就一头扎进去学习,你自己也觉得自己也学不会对吧.本篇文章主要让大家快速了解基础的架构分格,以便 ...
- MIT-6.824 操作系统 汇总
MIT-6.828-JOS-环境搭建 ELF文件格式 lab1:C, Assembly, Tools, and Bootstrapping lab2:Memory management lab3:Us ...
- [ASP.NET Core 3框架揭秘] 跨平台开发体验: Mac OS
除了微软自家的Windows平台, .NET Core针对Mac OS以及各种Linux Distribution(RHEL.Ubuntu.Debian.Fedora.CentOS和SUSE等)都提供 ...
- C#程序编写高质量代码改善的157个建议【4-9】[TryParse比Parse、使用int?来确保值类型也可以为null、readonly和const、0值设为枚举的默认值、避免给枚举类型的元素提供显式的值、习惯重载运算符]
建议4.TryParse比Parse好 如果注意观察,除string之外的所有的基元类型.会发现它们都有两个将字符串转换为自身类型的方法:Parse和TryParse.以类型double为例. 两者最 ...