re和crypto结合的一题,记录一下。

This vendor claims they have figured out a way to preserve the integrity and confidentiality of a message using signing instead of encryption. We only have a binary pycache file and a message off the wire – can you find the content of the message?

大概的意思是本题是关于某种签名算法。
题目本身没有源代码,反编译pyc可执行程序以后可以得到以下代码:

# uncompyle6 version 3.7.4
# Python bytecode 3.7 (3394)
# Decompiled from: Python 3.8.7 (tags/v3.8.7:6503f05, Dec 21 2020, 17:59:51) [MSC v.1928 64 bit (AMD64)]
# Embedded file name: /home/david/Projects/BSidesCTF/2020/challenges/haystack/challenge/chaffing.py
# Compiled at: 2020-01-22 09:37:26
# Size of source mod 2**32: 2094 bytes
import hmac, hashlib, random, struct
CHAFF_SIZE = 32
SIG_SIZE = 16
ALL_BYTES = set((c for c in range(256)))
KEY = 'af5f76f605a700ae8c0895c3e6175909'def byte(v):return bytes([v])def sign_byte(val, key):return hmac.new(key,val, digestmod=(hashlib.sha256)).digest()[:SIG_SIZE]def chaff_byte(val, key):msgs = {}msgs[val[0]] = sign_byte(val, key)while len(msgs) < CHAFF_SIZE:vals = list(ALL_BYTES - set(msgs.keys()))c = random.choice(vals)if c == val:raise ValueError('Chose duplicate!')fake_sig = bytes(random.choices((list(ALL_BYTES)), k=SIG_SIZE))msgs[c] = fake_sigpieces = []for k, v in msgs.items():pieces.append('%s%s' % (byte(k), v))random.shuffle(pieces)return ''.join(pieces)def chaff_msg(val, key):if not isinstance(val, bytes):val = val.encode('utf-8')msg_out = []for b in val:msg_out.append(chaff_byte(byte(b), key))outval = ''.join(msg_out)return struct.pack('>I', len(val)) + outvaldef winnow_msg(val, key):if not isinstance(val, bytes):val = val.encode('utf-8')msglen = struct.unpack('>I', val[:4])[0]val = val[4:]chunk_len = (SIG_SIZE + 1) * CHAFF_SIZEexpected_len = chunk_len * msglenif len(val) != expected_len:raise ValueError('Expected length %d, saw %d.' % (expected_len, len(val)))pieces = []for c in range(msglen):chunk = val[chunk_len * c:chunk_len * (c + 1)]res = winnow_byte(chunk, key)pieces.append(res)return ''.join(pieces)def winnow_byte(val, key):while val:c = byte(val[0])sig = val[1:SIG_SIZE + 1]if sign_byte(c, key) == sig:return cval = val[SIG_SIZE + 1:]raise ValueError('No valid sig found!')def main():inp = 'This is a test message!'msg = chaff_msg(inp, KEY)ret = winnow_msg(msg, KEY)if inp != ret:print('Wrong ret: %s' % ret)if __name__ == '__main__':main()
# okay decompiling chaffing.pyc

另外题目还提供了一个pcap抓包文件,里面有两个tcp流,将比较大的流内容二进制stream.raw保存下来待用。wireshark保存raw数据的方法参考这里

题目分析

加密部分

  1. 消息通过chaff_msg进行加密,对明文的每个字节进行chaff_byte操作
  2. 每个字节进行一次 sha256 带密钥key的签名,取签名结果前16字节保存在msgs集合中
  3. 然后取另外31个随机字节,每个随机字节生成一个随机假签名也保存在msgs集合中
  4. 最后32对 字节+签名 组合进行随机打乱顺序,输出成为密文

解密部分

  1. 解析出32对 字节+签名 组合
  2. 针对每一对组合,计算当前字节对应的sha256签名,如果计算结果与保存签名不一致的说明不是真实字节值

解题思路

在破译过程中我们不掌握sha256签名时用的key值,所以不能直接计算每个字节的签名值。但是在每个明文字符加密的过程中,特定字符例如字符 a 的签名结果 sig(a) 是不变的,而其他的 假签名 值是完全随机的。
于是我们可以将抓包获取的 字节+签名 组合情况进行统计,真实字符和签名值出现的比例肯定显著高于假字符签名组合。

所以可以用以下方法将每个32对 字节+签名 组合解析出来:

def extract(val):if not isinstance(val, bytes):val = val.encode('utf-8')msglen = struct.unpack('>I', val[:4])[0]val = val[4:]chunk_len = (SIG_SIZE + 1) * CHAFF_SIZEexpected_len = chunk_len * msglenif len(val) != expected_len:raise ValueError('Expected length %d, saw %d.' % (expected_len, len(val)))pieces = []for c in range(msglen):chunk = val[chunk_len * c:chunk_len * (c + 1)]res = extract_byte_sig_pairs(chunk)pieces.extend(res)return pieces
def extract_byte_sig_pairs(val):res = []while val:c = byte(val[0])sig = val[1:SIG_SIZE + 1]res.append((c, sig))val = val[SIG_SIZE + 1:]return res

然后取所有组合中出现比例最高的256组,作为真实的 字节+签名 组合对照表:

msg = open('data.bin', 'rb').read()
ret = extract(msg)
c = Counter(ret)
real = c.most_common(256)
print(real)

接下来解密逻辑就很简单了。
构造一个映射关系 d = {s: b for (b, s), c in real} 从32对 字节+签名 中选择真实的一对:

def decode(val, d):if not isinstance(val, bytes):val = val.encode('utf-8')msglen = struct.unpack('>I', val[:4])[0]val = val[4:]chunk_len = (SIG_SIZE + 1) * CHAFF_SIZEexpected_len = chunk_len * msglenif len(val) != expected_len:raise ValueError('Expected length %d, saw %d.' % (expected_len, len(val)))pieces = []for c in range(msglen):chunk = val[chunk_len * c:chunk_len * (c + 1)]res = decode_byte(chunk, d)pieces.append(res)return b''.join(pieces)
def decode_byte(val, d):while val:c = byte(val[0])sig = val[1:SIG_SIZE + 1]if sig in d and d[sig] == c:return cval = val[SIG_SIZE + 1:]raise ValueError("WTF")

最终exp:

#20221216
import hmac, hashlib, random, struct
from collections import Counter
CHAFF_SIZE = 32
SIG_SIZE = 16
ALL_BYTES = set((c for c in range(256)))
def extract(val):if not isinstance(val, bytes):val = val.encode('utf-8')msglen = struct.unpack('>I', val[:4])[0]val = val[4:]chunk_len = (SIG_SIZE + 1) * CHAFF_SIZEexpected_len = chunk_len * msglenif len(val) != expected_len:raise ValueError('Expected length %d, saw %d.' % (expected_len, len(val)))pieces = []for c in range(msglen):chunk = val[chunk_len * c:chunk_len * (c + 1)]res = extract_byte_sig_pairs(chunk)pieces.extend(res)return piecesdef extract_byte_sig_pairs(val):res = []while val:c = (val[0])sig = val[1:SIG_SIZE + 1]res.append((c, sig))val = val[SIG_SIZE + 1:]return resmsg = open('stream.raw', 'rb').read()
ret = extract(msg)
c = Counter(ret)
real = c.most_common(256)
print(real)def decode(val, d):if not isinstance(val, bytes):val = val.encode('utf-8')msglen = struct.unpack('>I', val[:4])[0]val = val[4:]chunk_len = (SIG_SIZE + 1) * CHAFF_SIZEexpected_len = chunk_len * msglenif len(val) != expected_len:raise ValueError('Expected length %d, saw %d.' % (expected_len, len(val)))pieces = []for c in range(msglen):chunk = val[chunk_len * c:chunk_len * (c + 1)]res = decode_byte(chunk, d)pieces.append(res)return ''.join(chr(i) for i in pieces)def decode_byte(val, d):while val:c = (val[0])sig = val[1:SIG_SIZE + 1]if sig in d and d[sig] == c:return cval = val[SIG_SIZE + 1:]raise ValueError("WTF")d = {s: b for (b, s), c in real}
print('\n')
print('\n')
print('\n')
print(d)
print(decode(msg,d))

crypto-haystack(BSidesSF ctf 2020)相关推荐

  1. crypto-dirty laundry(zer0pts CTF 2020)

    来自 zer0pts CTF 2020 - crypto 636 官方WP感觉有点复杂,根据自己理解进行部分简化. 题目: Do you wanna air my dirty laundry? 源码: ...

  2. Zer0pts CTF 2020的web赛后记录+复现环境

    前言 打了Zer0pts CTF 2020感觉题目不错就总结一下. 复现环境地址: https://gitlab.com/zer0pts/zer0pts-ctf-2020/ 0x01 notepad ...

  3. BIT CTF 2020 (一)(BASIC+MISC)

    BIT CTF 2020 (一)(持续更新)(BASIC已更新完毕,MISC已更新完毕) 今天托福班休息,正好昨晚做了一波基本完成了basic和misc的题,股市今天也大跌,就想整理下题解换下心情(5 ...

  4. [Bugku][Crypto][CTF][2020]Crypto 1-20 write up

    工具:CaptEncoder https://www.freebuf.com/sectool/188397.html Convert:https://pan.baidu.com/s/17YPXfvBH ...

  5. Wust CTF 2020 黄金体验镇魂曲 writeup

    文章目录 前言 Misc 比赛规则 Space Club Welcome 爬 Find me girlfriend Shop Crypto 情书 B@se babyrsa Reverse Cr0ssF ...

  6. CTF 2020 第二届 网鼎杯 第一道 Misc 签到

    这是我在超正式的比赛(网鼎杯)中做出的第一道CTF题(甭提有多高兴了) 题目地址: http://29ec1ba945124a9b827414b38f4e29030d0e0910e64e466c.cl ...

  7. Chive CTF 2020 - Tiki

    文章目录 题目状态: 赛事信息: Web: index. | SLOVED | catchme | SLOVED | 勇者斗恶龙 | SLOVED | 勇者谎称斗恶龙| SLOVED | magicp ...

  8. [攻防世界][CTF][2020][MISC] 攻防世界 MISC writeup

    咕咕咕 新手练习区精选write up https://blog.csdn.net/weixin_43550772/article/details/106028357 https://www.cnbl ...

  9. Elon为2020网鼎杯准备之“CTF初体验!”

    为网鼎杯做准备的第一天 网鼎杯是网络安全领域的"奥林匹克",也是国内最大型高水平网络安全竞赛. 此次大赛将在5月展开所有的线上赛,并且将在6.19~6.21于广东省深圳市举行线下所 ...

最新文章

  1. python-如何解决python执行pip install 命令的时候出现 File“<stdin>“,line 1 pip install XXX的问题
  2. Eclipse上安装GIT插件EGit及使用
  3. IDEA微服务项目的application.yml没有绿色叶子的解决办法
  4. lost connection to MySQL server at waiting for initial communication packet,system error:o
  5. 数据结构之字典序全排列
  6. 元宵节正月十五|设计师正需要的图片素材看这里
  7. 从windows server的文件服务到分布式文件服务(九)
  8. 结构体与对象的联系与区别
  9. Java 中equals 与 == 的区别:
  10. 雕刻在LINUX内核中的LINUS故事
  11. Ubuntu18.04中安装virtualenv和virtualenvwrapper
  12. skywalking官方文档学习
  13. Ribbon 界面介绍(1)
  14. google账号已停用(已解决)
  15. 数据哪里找?200个源数据网站全给你!
  16. OLYMP‘ARTS 2023奥艺大会中国推介会在北京盛大举行
  17. 地图选择区域遮罩层自定义控件实现
  18. Android 音视频开发实践系列-04-Android WebRTC推流到SRS服务器实现直播功能
  19. 语法基础课——第二讲 习题
  20. Java(老白再次入门) - Java集合

热门文章

  1. Python实现 文本进度条展示(嵩天老师)
  2. 数据库必须具备的四个特性
  3. 《Reverse Engineering for Beginners》读书笔记(一):前言
  4. 爬取qq好友说说并对数据简单分析
  5. POJ 3165 最短路 floyd
  6. 基建互联 | 安霸与飞桨深度合作,高性能算法落地简单高效!
  7. k线顶分型 python_顶底分型-(K线分类及顶底分型的一种数学原理 源码 贴图)...
  8. 【JY】结构概念设计之(隔震概念设计)
  9. 中兴交换机vsc配置实例
  10. 计算机系统w10,win7和win10哪个占用内存? win7和win10中哪一个适合计算机系统?...