CTF Wiki
  • 简介
  • 如何使用 CTF Wiki
  • introduction
    • CTF 历史
    • CTF 竞赛模式简介
    • CTF 竞赛内容
    • 线下攻防经验小结
    • CGC 超级挑战赛
    • 学习资源
  • misc
    • 杂项简介
    • 取证隐写前置技术
    • 信息搜集技术
    • encode
      • 通信领域常用编码
      • 计算机相关的编码
      • 现实世界中常用的编码
    • picture
      • 图片分析简介
      • JPG
      • PNG
      • GIF
    • audio
      • 音频隐写
    • archive
      • RAR 格式
      • ZIP 格式
    • traffic
      • 流量包分析简介
      • 协议分析概述
        • Wireshark
        • DNS
        • HTTP
        • HTTPS
        • FTP
        • USB
        • WIFI
      • 数据提取
      • PCAP 文件修复
    • disk-memory
      • 磁盘内存分析
      • 题目
    • shellcode
    • other
      • pyc
  • web
    • Web 简介
    • XSS
    • php
      • PHP 代码审计
    • SQL 注入
      • sqlmap绕过脚本
      • 各版本数据库语句备忘
    • CSRF
    • SSRF
  • reverse
    • 软件逆向工程简介
    • identify-encode-encryption
      • 常见加密算法和编码识别
    • language
      • 简介
      • go
        • Golang 逆向入门
      • python
        • Python 逆向入门
      • rust
        • Rust 逆向入门
    • maze
      • 迷宫问题
    • obfuscate
      • 控制流平坦化
      • 花指令
      • movofuscator
      • Self-Modified Code
    • vm
      • 虚拟机分析
    • platform
      • linux
        • Detecting Breakpoints
        • Detecting debugging
        • False Disassembly
        • LD_PRELOAD
      • windows
        • anti-debug
          • CheckRemoteDebuggerPresent
          • 反调试技术例题
          • Heap Flags
          • Interrupt 3
          • IsDebuggerPresent
          • 花指令
          • NtGlobalFlag
          • NtQueryInformationProcess
          • The Heap
          • Thread Local Storage(TLS)
          • ZwSetInformationThread
        • unpack
          • 一步到达 OEP 法
          • ESP 定律法
          • DUMP 及 IAT 重建
          • 最后一次异常法
          • 手动查找 IAT 并使用 ImportREC 重建
          • 内存镜像法
          • 保护壳简介
          • SFX 法
          • 单步跟踪法
          • DLL 文件脱壳
    • tools
      • constraint
        • z3
      • debug
        • gdb
        • ollydbg
        • windbg
        • x64dbg/x32dbg
      • simulate-execution
        • angr
        • Unicorn Engine
      • static-analyze
        • dnspy
        • Ghidra
        • IDA Pro
        • jadx
  • crypto
    • 密码学简介
    • asymmetric
      • 介绍
      • discrete-log
        • 离散对数
        • ECC
        • ElGamal
      • knapsack
        • 背包加密
      • lattice
        • CVP
        • 基本介绍
        • 格基规约算法
        • 格概述
      • rsa
        • RSA 选择明密文攻击
        • RSA 复杂题目
        • Coppersmith 相关攻击
        • 公钥指数相关攻击
        • 模数相关攻击
        • Bleichenbacher's attack
        • RSA 侧信道攻击
        • RSA 介绍
        • d_attacks
          • 私钥 d 相关攻击
          • 扩展维纳攻击
    • attack-summary
      • 简介
      • 比特攻击
      • 中间相遇攻击 - MITM
    • basic
      • 基础数学知识
    • blockcipher
      • AES
      • ARX: Add-Rotate-Xor
      • DES
      • IDEA
      • 块加密
      • Simon and Speck Block Ciphers
      • mode
        • CBC
        • CFB
        • CTR
        • ECB
        • 分组模式
        • OFB
        • Padding Oracle Attack
        • 填充方式
        • PCBC
    • certificate
      • 证书格式
    • classical
      • 古典密码简介
      • 单表代换加密
      • 其它类型加密
      • 多表代换加密
      • 总结
    • hash
      • Hash Attack
      • 综合题目
      • Fowler–Noll–Vo hash function
      • 哈希函数
      • MD5
      • SHA1
    • signature
      • DSA
      • ElGamal
      • 数字签名
      • RSA 数字签名
    • streamcipher
      • 流密码
      • fsr
        • 反馈移位寄存器
        • 线性反馈移位寄存器 - LFSR
        • 非线性反馈移位寄存器
      • lcg
        • 题目
        • 线性同余生成器
      • prng
        • 密码安全伪随机数生成器
        • 伪随机数生成器介绍
        • 题目
      • special
        • RC4
  • pwn
    • MacOS
    • misc-os
    • 概述
      • stackoverflow
        • 执行 Shellcode
        • 栈介绍
        • 栈溢出原理
    • browser
      • Chrome
      • Firefox
      • Safari
    • hardware
      • 简介
        • side-channel
          • prefetch side-channel attack
      • trusted-computing
        • 可信执行环境
    • linux
      • kernel-mode
        • 基础知识
        • Introduction
          • DoS
          • Information Disclosure
          • Introduction
            • Change Others
            • Change Self
        • Introduction
          • Introduction
            • 信息泄漏
            • Misc
          • Introduction
            • Kernel Stack Canary
          • Introduction
            • inner-kernel
              • 内部隔离
            • Introduction
              • KPTI - Kernel Page Table Isolation
              • 用户代码不可执行
              • 用户数据不可访问
          • Introduction
            • FGKASLR
            • KASLR
        • Introduction
          • 编译内核驱动
          • 内核下载与编译
          • Qemu 模拟环境
          • Real Device
        • exploitation
          • heap
            • 内核堆概述
            • buddy
              • Cross-Cache Overflow & Page-level Heap Fengshui
              • Page-level UAF
            • slub
              • freelist 劫持
              • Heap Spray
              • kernel UAF
          • race
            • Double Fetch
            • userfaultfd 的使用
          • rop
            • bypass-smep
            • ret2dir
            • 利用 pt_regs 构造通用内核 ROP
            • ret2usr(已过时)
            • Kernel ROP
          • tricks
            • 在内存中直接搜索 flag
      • user-mode
        • environment
        • fmtstr
          • 检测
          • 例子
          • 利用
          • 原理介绍
        • integeroverflow
          • 整数溢出
        • io-file
          • glibc 2.24下 IO_FILE 的利用
          • 伪造vtable劫持程序流程
          • FSOP
          • FILE结构
        • mitigation
          • Canary
        • race-condition
          • introduction
          • 题目
        • summary
          • 获取地址
          • shell 获取小结
          • 控制程序执行流
        • Type Confusion
        • Uninitialized Memory
        • heap
          • mallocng
          • ptmalloc2
            • Chunk Extend and Overlapping
            • Fastbin Attack
            • 堆概述
            • 堆相关数据结构
            • 堆溢出
            • House Of Einherjar
            • House Of Force
            • House of Lore
            • House of Orange
            • House of Pig
            • House of Rabbit
            • House of Roman
            • 堆利用
            • Large Bin Attack
            • 通过堆进行信息泄漏
            • 堆中的 Off-By-One
            • 堆中的检查
            • tcache makes heap exploitation easy again
            • Unlink
            • Unsorted Bin Attack
            • Use After Free
            • implementation
              • 基础操作
              • 释放内存块
              • 堆初始化
              • malloc_state 相关函数
              • 申请内存块
              • 测试支持
              • 深入理解堆的实现
              • tcache
        • stackoverflow
          • arm
            • 环境搭建
            • Arm ROP
          • mips
            • mips - ROP
          • RISC-V
          • x86
            • 基本 ROP
            • 花式栈溢出技巧
            • 中级ROP
            • 栈介绍
            • 栈溢出原理
            • advanced-rop
              • 高级 ROP
              • ret2dlresolve
              • ret2VDSO
              • SROP
    • sandbox
      • Chroot
      • Docker
      • Namespace
      • python
        • Python 沙盒
      • seccomp
        • C 沙盒逃逸
      • Shell Sandbox
    • virtualization
      • basic-knowledge
        • 虚拟化技术简介
        • CPU 虚拟化
        • IO 虚拟化
        • 内存虚拟化
      • parallels
        • Parallels
      • VirtualBox
      • VMWare
      • qemu
        • basic-knowledge
          • QEMU 设备模拟
          • QEMU 内存管理
        • environment
          • 编写 QEMU 模拟设备
          • QEMU 下载与编译
        • exploitation
          • QEMU 逃逸入门
          • 越界读写
  • Android 安全
    • basic_develop
      • Android 开发基础
    • Android 应用运行机制简述
      • Android 中 Java 层的运行机制
        • dex
          • DEX文件
          • ODEX文件
        • smali
          • Smali
      • native_layer
        • so 介绍
    • basic_reverse
      • Android 关键代码定位
      • Android 逆向基本介绍
      • dynamic
        • Android 动态调试
        • IDA 动态调试原生层程序
        • IDA 动态调试 smali 代码
      • static
        • 静态分析综合题目
        • 静态分析 java 层例子
        • 静态分析原生层程序
  • blockchain
    • Blockchain Security Challenges
    • Blockchain Security Overview
    • ethereum
      • Ethereum Basics
      • Ethereum Overview
      • Ethereum Opcodes
      • 学习资源
      • Smart Contract Reverse
      • Function Selector and Argument Encoding
      • Ethereum Storage
      • attacks
        • Airdrop Hunting
        • Arbitrary Writing
        • CREATE2
        • Delegatecall
        • Introduction
        • Jump Oriented Programming
        • Integer Overflow and Underflow
        • Randomness
        • Re-Entrancy
        • Short Address Attack
        • Uninitialized Storage Pointer
    • publicblockchain
      • Public Blockchain Security Overview
      • Blockchain Weaknesses
  • assembly
    • ARM
    • MIPS
    • x86_x64
  • executable
    • elf
      • 程序加载
      • 程序执行流程
      • linking
        • 程序链接
        • Symbol Reslove
      • structure
        • ELF 文件
        • Code Section
        • Data Related Sections
        • Dynamic Sections
        • Misc Sections
        • Sections
        • String Sections
        • .symtab: Symbol Table
    • pe
      • PE 文件格式
      • 导出表
      • 导入表
      • 基址重定位表
  • ics
    • ICS_CTF 竞赛
    • ICS_CTF 发现
    • ICS_CTF 利用
    • ICS_CTF 学习资源
  • contribute
    • 贡献之前
    • 基本贡献方式
    • 贡献文档要求
    • 翻译
  • write up
    • 浙江工业大学CTF赛事
      • 2023第四届“安恒杯”CTF新生赛题解
Powered by GitBook
On this page
  • 暴力分解 N
  • 攻击条件
  • JarvisOJ - Easy RSA
  • p & q 不当分解 N
  • 攻击条件
  • |p-q| 很大
  • |p-q| 较小
  • p - 1 光滑
  • p + 1 光滑
  • 2017 SECCON very smooth
  • 扩展
  • 模不互素
  • 攻击原理
  • SCTF RSA2
  • 共模攻击
  • 攻击条件
  • 攻击原理
  • XMan 一期夏令营课堂练习
  • 题目
  1. crypto
  2. asymmetric
  3. rsa

模数相关攻击

暴力分解 N

攻击条件

在 N 的比特位数小于 512 的时候,可以采用大整数分解的策略获取 p 和 q。

JarvisOJ - Easy RSA

这里我们以 "JarvisOJ - Easy RSA" 为例进行介绍,题目如下

还记得 veryeasy RSA 吗?是不是不难?那继续来看看这题吧,这题也不难。 已知一段 RSA 加密的信息为:0xdc2eeeb2782c 且已知加密所用的公钥: N=322831561921859 e = 23 请解密出明文,提交时请将数字转化为 ascii 码提交 比如你解出的明文是 0x6162,那么请提交字符串 ab 提交格式:PCTF{明文字符串}

可以看出,我们的 N 比较小,这里我们直接使用 factordb 进行分解,可以得到

322831561921859=13574881×23781539322831561921859 = 13574881 \times 23781539322831561921859=13574881×23781539

进而我们简单编写程序如下

import gmpy2
p = 13574881
q = 23781539
n = p * q
e = 23
c = 0xdc2eeeb2782c
phin = (p - 1) * (q - 1)
d = gmpy2.invert(e, phin)
p = gmpy2.powmod(c, d, n)
tmp = hex(p)
print tmp, tmp[2:].decode('hex')

结果如下

➜  Jarvis OJ-Basic-easyRSA git:(master) ✗ python exp.py
0x33613559 3a5Y

p & q 不当分解 N

攻击条件

当 RSA 中 p 和 q 选取不当时,我们也可以进行攻击。

|p-q| 很大

当 p-q 很大时,一定存在某一个参数较小,这里我们假设为 p,那么我们可以通过穷举的方法对模数进行试除,从而分解模数,得到保密参数与明文信息。基本来说,不怎么可行。

|p-q| 较小

首先

(p+q)24−n=(p+q)24−pq=(p−q)24\frac{(p+q)^2}{4}-n=\frac{(p+q)^2}{4}-pq=\frac{(p-q)^2}{4}4(p+q)2​−n=4(p+q)2​−pq=4(p−q)2​

既然 |p-q| 较小,那么 $\frac{(p-q)^2}{4}$ 自然也比较小,进而 $\frac{(p+q)^2}{4}$ 只是比 N 稍微大一点,所以 $\frac{p+q}{2}$ 与 $\sqrt{n}$ 相近。那么我们可以按照如下方法来分解

  • 顺序检查 $\sqrt{n}$ 的每一个整数 x,直到找到一个 x 使得 $x^2-n$ 是平方数,记为 $y^2$

  • 那么 $x^2-n=y^2$,进而根据平方差公式即可分解 N

p - 1 光滑

  • 光滑数(Smooth number):指可以分解为小素数乘积的正整数

  • 当$p$是$N$的因数,并且$p-1$是光滑数,可以考虑使用Pollard's p-1算法来分解$N$

  • 根据费马小定理有

    若p∤a, 则ap−1≡1(modp)若p\nmid a,\ 则a^{p-1}\equiv 1\pmod{p}若p∤a, 则ap−1≡1(modp)

    则有

    at(p−1)≡1t≡1(modp)a^{t(p-1)}\equiv 1^t \equiv 1\pmod{p}at(p−1)≡1t≡1(modp)

    即

    at(p−1)−1=k∗pa^{t(p-1)} - 1 = k*pat(p−1)−1=k∗p

  • 根据Pollard's p-1算法:

    如果$p$是一个$B-smooth\ number$,那么则存在

    M=∏q≤Bq⌊log⁡qB⌋M = \prod_{q\le{B}}{q^{\lfloor\log_q{B}\rfloor}}M=∏q≤B​q⌊logq​B⌋

    使得

    (p−1)∣M(p-1)\mid M(p−1)∣M

    成立,则有

    gcd⁡(aM−1,N)\gcd{(a^{M}-1, N)}gcd(aM−1,N)

    如果结果不为$1$或$N$,那么就已成功分解$N$。

    因为我们只关心最后的gcd结果,同时N只包含两个素因子,则我们不需要计算$M$,考虑$n=2,3,\dots$,令$M = n!$即可覆盖正确的$M$同时方便计算。

  • 在具体计算中,可以代入降幂进行计算

    a^{n!}\bmod{N}=\begin{cases} (a\bmod{N})^2\mod{N}&n=2\\ (a^{(n-1)!}\bmod{N})^n\mod{N}&n\ge{3} \end{cases}$$
  • Python代码实现

    from gmpy2 import *
    a = 2
    n = 2
    while True:
        a = powmod(a, n, N)
        res = gcd(a-1, N)
        if res != 1 and res != N:
            q = N // res
            d = invert(e, (res-1)*(q-1))
            m = powmod(c, d, N)
            print(m)
            break
        n += 1

p + 1 光滑

  • 当$p$是$N$的因数,并且$p+1$是光滑数,可以考虑使用Williams's p+1算法来分解$N$

  • 已知$N$的因数$p$,且$p+1$是一个光滑数

    p=(∏i=1kqiαi)+1p = \left(\prod_{i=1}^k{q_i^{\alpha_i}}\right)+1p=(i=1∏k​qiαi​​)+1

    $q_i$即第$i$个素因数且有$q_i^{\alpha_i}\le B_1$, 找到$\beta_i$使得让$q_i^{\beta_i}\le B_1$且$q_i^{\beta_i+1}> B_1$,然后令

    R=∏i=1kqiβiR = \prod_{i=1}^k{q_i^{\beta_i}}R=i=1∏k​qiβi​​

    显然有$p-1\mid R$且当$(N, a) = 1$时有$a^{p-1}\equiv 1 \pmod{p}$,所以有$a^R\equiv 1\pmod{p}$,即

    p∣(N,aR−1)p\mid(N, a^R-1)p∣(N,aR−1)
  • 令$P,Q$为整数,$\alpha,\beta$为方程$x^2-Px+Q=0$的根,定义如下类卢卡斯序列

    Un(P,Q)=(αn−βn)/(α−β)Vn(P,Q)=αn+βn\begin{aligned} U_n(P, Q) &= (\alpha^n -\beta^n)/(\alpha - \beta)\\ V_n(P, Q) &= \alpha^n + \beta^n \end{aligned}Un​(P,Q)Vn​(P,Q)​=(αn−βn)/(α−β)=αn+βn​

    同样有$\Delta = (\alpha - \beta)^2 = P^2-4Q$,则有

    {Un+1=PUn−QUn−1Vn+1=PVn−QVn−1(2.2)\begin{cases} U_{n+1} &= PU_n - QU_{n-1}\\ V_{n+1} &= PV_n - QV_{n-1} \end{cases}\tag{2.2}{Un+1​Vn+1​​=PUn​−QUn−1​=PVn​−QVn−1​​(2.2)
    {U2n=VnUnV2n=Vn2−2Qn(2.3)\begin{cases} U_{2n} &= V_nU_n\\ V_{2n} &= V_n^2 - 2Q^n \end{cases}\tag{2.3}{U2n​V2n​​=Vn​Un​=Vn2​−2Qn​(2.3)
    {U2n−1=Un2−QUn−12V2n−1=VnVn−1−PQn−1(2.4)\begin{cases} U_{2n-1} &= U_n^2 - QU_{n-1}^2\\ V_{2n-1} &= V_nV_{n-1} - PQ^{n-1} \end{cases}\tag{2.4}{U2n−1​V2n−1​​=Un2​−QUn−12​=Vn​Vn−1​−PQn−1​(2.4)
    {ΔUn=PVn−2QVn−1Vn=PUn−2QUn−1(2.5)\begin{cases} \Delta U_{n} &= PV_n - 2QV_{n-1}\\ V_{n} &= PU_n - 2QU_{n-1} \end{cases}\tag{2.5}{ΔUn​Vn​​=PVn​−2QVn−1​=PUn​−2QUn−1​​(2.5)
    {Um+n=UmUn+1−QUm−1UnΔUm+n=VmVn+1−QVm−1Vn(2.6)\begin{cases} U_{m+n} &= U_mU_{n+1} - QU_{m-1}U_n\\ \Delta U_{m+n} &= V_mV_{n+1} - QV_{m-1}V_n \end{cases}\tag{2.6}{Um+n​ΔUm+n​​=Um​Un+1​−QUm−1​Un​=Vm​Vn+1​−QVm−1​Vn​​(2.6)
    {Un(Vk(P,Q),Qk)=Unk(P,Q)/Uk(P,Q)Vn(Vk(P,Q),Qk)=Vn(P,Q)(2.7)\begin{cases} U_{n}(V_k(P, Q), Q^k) &= U_{nk}(P, Q)/U_k(P, Q)\\ V_{n}(V_k(P, Q), Q^k) &= V_n(P, Q) \end{cases}\tag{2.7}{Un​(Vk​(P,Q),Qk)Vn​(Vk​(P,Q),Qk)​=Unk​(P,Q)/Uk​(P,Q)=Vn​(P,Q)​(2.7)

    同时我们有如果$(N, Q) = 1$且$P^{'}Q\equiv P^2-2Q\pmod{N}$,则有$P^{'}\equiv \alpha/\beta + \beta/\alpha$以及$Q^{'}\equiv \alpha/\beta + \beta/\alpha = 1$,即

    U2m(P,Q)≡PQm−1Um(P′,1)(modN)(2.8)U_{2m}(P, Q)\equiv PQ^{m-1}U_m(P^{'}, 1)\pmod{N}\tag{2.8}U2m​(P,Q)≡PQm−1Um​(P′,1)(modN)(2.8)

    根据扩展卢卡斯定理

    如果p是奇素数,$p\nmid Q$且勒让德符号$(\Delta/p) = \epsilon$,则

    U(p−ϵ)m(P,Q)≡0(modp)V(p−ϵ)m(P,Q)≡2Qm(1−ϵ)/2(modp)\begin{aligned} U_{(p-\epsilon)m}(P, Q) &\equiv 0\pmod{p}\\ V_{(p-\epsilon)m}(P, Q) &\equiv 2Q^{m(1-\epsilon)/2}\pmod{p} \end{aligned}U(p−ϵ)m​(P,Q)V(p−ϵ)m​(P,Q)​≡0(modp)≡2Qm(1−ϵ)/2(modp)​
  • 第一种情况:已知N的因数p,且p+1是一个光滑数

    p=(∏i=1kqiαi)−1p = \left(\prod_{i=1}^k{q_i^{\alpha_i}}\right)-1p=(i=1∏k​qiαi​​)−1

    有$p+1\mid R$,当$(Q, N)=1$且$(\Delta/p) = -1$时有$p\mid U_R(P, Q)$,即$p\mid (U_R(P, Q), N)$

    为了找到$U_R(P, Q)$,Guy和Conway提出可以使用如下公式

    U2n−1=Un2−QUn2−1U2n=Un(PUn−2QUn−1)U2n+1=PU2n−QU2n−1\begin{aligned} U_{2n-1} &= U_n^2 - QU_n^2 - 1\\ U_{2n} &= U_n(PU_n - 2QU_{n-1})\\ U_{2n+1} &= PU_{2n} - QU_{2n-1} \end{aligned}U2n−1​U2n​U2n+1​​=Un2​−QUn2​−1=Un​(PUn​−2QUn−1​)=PU2n​−QU2n−1​​

    但是上述公式值太大了,不便运算,我们可以考虑如下方法

    如果$p \mid U_R(P, 1)$,根据公式2.3有$p\mid U_{2R}(P, Q)$,所以根据公式2.8有$p \mid U_R(P^{'}, 1)$,设$Q=1$,则有

    V(p−ϵ)m(P,1)≡2(modp)V_{(p-\epsilon)m}(P, 1) \equiv 2\pmod{p}V(p−ϵ)m​(P,1)≡2(modp)

    即,如果$p\mid U_R(P, 1)$,则$p\mid(V_R(P, 1) -2)$.

    第一种情况可以归纳为:

    让$R = r_1r_2r_3\cdots r_m$,同时找到$P_0$使得$(P_0^2-4, N) = 1$,定义$V_n(P) = V_n(P, 1), U_n(P) = U_n(P, 1)$且

    Pj≡Vrj(Pj−1)(modN)(j=1,2,3,…,m)P_j \equiv V_{r_j}(P_{j-1})\pmod{N}(j = 1,2,3,\dots,m)Pj​≡Vrj​​(Pj−1​)(modN)(j=1,2,3,…,m)

    根据公式2.7,有

    Pm≡VR(P0)(modN)(3.1)P_m \equiv V_R(P_0)\pmod{N}\tag{3.1}Pm​≡VR​(P0​)(modN)(3.1)

    要计算$V_r = V_r(P)$可以用如下公式

    根据公式2.2,公式2.3,公式2.4有

    {V2f−1≡VfVf−1−PV2f≡Vf2−2V2f+1≡PVf2−VfVf−1−P(mod()N)\begin{cases} V_{2f-1}&\equiv V_fV_{f-1}-P\\ V_{2f}&\equiv V_f^2 - 2\\ V_{2f+1}&\equiv PV_f^2-V_fV_{f-1}-P\pmod(N) \end{cases}⎩⎨⎧​V2f−1​V2f​V2f+1​​≡Vf​Vf−1​−P≡Vf2​−2≡PVf2​−Vf​Vf−1​−P(mod()N)​

    令

    r=∑i=0tbt2t−i    (bi=0,1)r = \sum_{i=0}^t{b_t2^{t-i}}\ \ \ \ (b_i=0,1)r=i=0∑t​bt​2t−i    (bi​=0,1)

    $f_0=1, f_{k+1}=2f_k+b_{k+1}$,则$f_t=r$,同样$V_0(P) = 2, V_1(P) = P$,则最终公式为

    (Vfk+1,Vfk+1−1)={(V2fk,V2fk−1)    if bk+1=0(V2fk+1,V2fk)    if bk+1=1(V_{f_{k+1}}, V_{f_{k+1}-1}) = \begin{cases} (V_{2f_k}, V_{2f_k-1})\ \ \ \ if\ b_{k+1}=0\\ (V_{2f_k+1}, V_{2f_k})\ \ \ \ if\ b_{k+1}=1 \end{cases}(Vfk+1​​,Vfk+1​−1​)={(V2fk​​,V2fk​−1​)    if bk+1​=0(V2fk​+1​,V2fk​​)    if bk+1​=1​
  • 第二种情况:已知p+1是一个光滑数

    p=s(∏i=1kqiαi)−1p = s\left(\prod_{i=1}^k{q_i^{\alpha_i}}\right)-1p=s(i=1∏k​qiαi​​)−1

    当$s$是素数,且$B_1<s\le B_2$,有$p\mid(a_m^s-1, N),$定义$s_j$和$2d_j$

    2dj=sj+1−sj2d_j = s_j+1-s_j2dj​=sj​+1−sj​

    如果$(\Delta/p) = -1$且$p\nmid P_m-2$,则根据公式2.7和公式3.1有$p\mid(U_s(P_m), N)$。

    令$U[n] \equiv U_n(P_m), V[n]\equiv V_n(P_m)\pmod{N}$,计算$U[2d_j-1], U[2d_j], U[2d_j+1]$通过

    U[0]=0,U[1]=1,U[n+1]=PmU[n]−U[n−1]U[0] = 0, U[1] = 1, U[n+1] = P_mU[n] - U[n-1]U[0]=0,U[1]=1,U[n+1]=Pm​U[n]−U[n−1]

    计算

    T[si]≡ΔUsi(Pm)=ΔUsiR(P0)/UR(P0)(modN)T[s_i] \equiv \Delta U_{s_i}(P_m) = \Delta U_{s_iR}(P_0)/U_R(P_0)\pmod{N}T[si​]≡ΔUsi​​(Pm​)=ΔUsi​R​(P0​)/UR​(P0​)(modN)

    通过公式2.6,公式2.7和公式3.1有

    {T[s1]≡PmV[s1]−2V[s1−1]T[s1−1]≡2V[s1]−PmV[s1−1](modN)\begin{cases} T[s_1]&\equiv P_mV[s_1]-2V[s_1-1]\\ T[s_1-1]&\equiv 2V[s_1]-P_mV[s_1-1]\pmod{N} \end{cases}{T[s1​]T[s1​−1]​≡Pm​V[s1​]−2V[s1​−1]≡2V[s1​]−Pm​V[s1​−1](modN)​

    即

    {T[si+1]≡T[si]U[2di+1]−T[si−1]U[2di]T[si+1−1]≡T[si]U[2di]−T[si−1]U[2di−1](modN)\begin{cases} T[s_{i+1}]&\equiv T[s_i]U[2d_i+1]-T[s_i-1]U[2d_i]\\ T[s_{i+1}-1]&\equiv T[s_i]U[2d_i]-T[s_i-1]U[2d_i-1]\pmod{N} \end{cases}{T[si+1​]T[si+1​−1]​≡T[si​]U[2di​+1]−T[si​−1]U[2di​]≡T[si​]U[2di​]−T[si​−1]U[2di​−1](modN)​

    计算$T[s_i], i=1,2,3\dots$,然后计算

    Ht=(∏i=0cT[si+t],N)H_t = (\prod_{i=0}^c{T[s_{i+t}], N})Ht​=(i=0∏c​T[si+t​],N)

    其中$t = 1, c+1, 2c+1, \dots, c[B_2/c]+1$,我们有$p\mid H_i$当$(\Delta/p)=-1$

  • python代码实现

    def mlucas(v, a, n):
        """ Helper function for williams_pp1().  Multiplies along a Lucas sequence modulo n. """
        v1, v2 = v, (v**2 - 2) % n
        for bit in bin(a)[3:]: v1, v2 = ((v1**2 - 2) % n, (v1*v2 - v) % n) if bit == "0" else ((v1*v2 - v) % n, (v2**2 - 2) % n)
        return v1
    
    for v in count(1):
        for p in primegen():
            e = ilog(isqrt(n), p)
            if e == 0: break
            for _ in xrange(e): v = mlucas(v, p, n)
            g = gcd(v-2, n)
            if 1 < g < n: return g # g|n
            if g == n: break

2017 SECCON very smooth

该程序给了一个 HTTPS 加密的流量包,首先从其中拿到证书

➜  2017_SECCON_verysmooth git:(master) binwalk -e s.pcap      

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
2292          0x8F4           Certificate in DER format (x509 v3), header length: 4, sequence length: 467
4038          0xFC6           Certificate in DER format (x509 v3), header length: 4, sequence length: 467
5541          0x15A5          Certificate in DER format (x509 v3), header length: 4, sequence length: 467

➜  2017_SECCON_verysmooth git:(master) ls
s.pcap  _s.pcap.extracted  very_smooth.zip

这里分别查看三个证书,三个模数都一样,这里只给一个例子

➜  _s.pcap.extracted git:(master) openssl x509 -inform DER -in FC6.crt  -pubkey -text -modulus -noout 
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVRqqCXPYd6Xdl9GT7/kiJrYvy
8lohddAsi28qwMXCe2cDWuwZKzdB3R9NEnUxsHqwEuuGJBwJwIFJnmnvWurHjcYj
DUddp+4X8C9jtvCaLTgd+baSjo2eB0f+uiSL/9/4nN+vR3FliRm2mByeFCjppTQl
yioxCqbXYIMxGO4NcQIDAQAB
-----END PUBLIC KEY-----
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number: 11640506567126718943 (0xa18b630c7b3099df)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=JP, ST=Kawasaki, O=SRL
        Validity
            Not Before: Oct  8 02:47:17 2017 GMT
            Not After : Oct  8 02:47:17 2018 GMT
        Subject: C=JP, ST=Kawasaki, O=SRL
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (1024 bit)
                Modulus:
                    00:d5:46:aa:82:5c:f6:1d:e9:77:65:f4:64:fb:fe:
                    48:89:ad:8b:f2:f2:5a:21:75:d0:2c:8b:6f:2a:c0:
                    c5:c2:7b:67:03:5a:ec:19:2b:37:41:dd:1f:4d:12:
                    75:31:b0:7a:b0:12:eb:86:24:1c:09:c0:81:49:9e:
                    69:ef:5a:ea:c7:8d:c6:23:0d:47:5d:a7:ee:17:f0:
                    2f:63:b6:f0:9a:2d:38:1d:f9:b6:92:8e:8d:9e:07:
                    47:fe:ba:24:8b:ff:df:f8:9c:df:af:47:71:65:89:
                    19:b6:98:1c:9e:14:28:e9:a5:34:25:ca:2a:31:0a:
                    a6:d7:60:83:31:18:ee:0d:71
                Exponent: 65537 (0x10001)
    Signature Algorithm: sha256WithRSAEncryption
         78:92:11:fb:6c:e1:7a:f7:2a:33:b8:8b:08:a7:f7:5b:de:cf:
         62:0b:a0:ed:be:d0:69:88:38:93:94:9d:05:41:73:bd:7e:b3:
         32:ec:8e:10:bc:3a:62:b0:56:c7:c1:3f:60:66:a7:be:b9:46:
         f7:46:22:6a:f3:5a:25:d5:66:94:57:0e:fc:b5:16:33:05:1c:
         6f:f5:85:74:57:a4:a0:c6:ce:4f:fd:64:53:94:a9:83:b8:96:
         bf:5b:a7:ee:8b:1e:48:a7:d2:43:06:0e:4f:5a:86:62:69:05:
         e2:c0:bd:4e:89:c9:af:04:4a:77:a2:34:86:6a:b8:d2:3b:32:
         b7:39
Modulus=D546AA825CF61DE97765F464FBFE4889AD8BF2F25A2175D02C8B6F2AC0C5C27B67035AEC192B3741DD1F4D127531B07AB012EB86241C09C081499E69EF5AEAC78DC6230D475DA7EE17F02F63B6F09A2D381DF9B6928E8D9E0747FEBA248BFFDFF89CDFAF4771658919B6981C9E1428E9A53425CA2A310AA6D760833118EE0D71

可以看出模数只有 1024 比特。而且,根据题目名 very smooth,应该是其中一个因子比较 smooth,这里我们利用 primefac 分别尝试 Pollard's p − 1 与 Williams's p + 1 算法,如下

➜  _s.pcap.extracted git:(master) python -m primefac -vs -m=p+1  149767527975084886970446073530848114556615616489502613024958495602726912268566044330103850191720149622479290535294679429142532379851252608925587476670908668848275349192719279981470382501117310509432417895412013324758865071052169170753552224766744798369054498758364258656141800253652826603727552918575175830897

149767527975084886970446073530848114556615616489502613024958495602726912268566044330103850191720149622479290535294679429142532379851252608925587476670908668848275349192719279981470382501117310509432417895412013324758865071052169170753552224766744798369054498758364258656141800253652826603727552918575175830897: p+1 11807485231629132025602991324007150366908229752508016230400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 12684117323636134264468162714319298445454220244413621344524758865071052169170753552224766744798369054498758364258656141800253652826603727552918575175830897
Z309  =  P155 x P155  =  11807485231629132025602991324007150366908229752508016230400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 x 12684117323636134264468162714319298445454220244413621344524758865071052169170753552224766744798369054498758364258656141800253652826603727552918575175830897

可以发现当使用 Williams's p + 1 算法时,就直接分解出来了。按道理这个因子是 p-1 似乎更光滑,但是却并不能使用 Pollard's p − 1 算法分解,这里进行进一步的测试

➜  _s.pcap.extracted git:(master) python -m primefac -vs 1180748523162913202560299132400715036690822975250801623040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002

1180748523162913202560299132400715036690822975250801623040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002: 2 7 43 503 761429 5121103123294685745276806480148867612214394022184063853387799606010231770631857868979139305712805242051823263337587909550709296150544706624823
Z154  =  P1 x P1 x P2 x P3 x P6 x P142  =  2 x 7 x 43 x 503 x 761429 x 5121103123294685745276806480148867612214394022184063853387799606010231770631857868979139305712805242051823263337587909550709296150544706624823

➜  _s.pcap.extracted git:(master) python -m primefac -vs 1180748523162913202560299132400715036690822975250801623040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 

1180748523162913202560299132400715036690822975250801623040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000: 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
Z154  =  P1^185 x P1^62 x P1^97  =  2^185 x 3^62 x 5^97

可以看出,对于 p-1 确实有很多小因子,但是个数太多,这就会使得进行枚举的时候出现指数爆炸的情况,因此没有分解出来。

进而根据分解出来的数构造私钥

from Crypto.PublicKey import RSA
import gmpy2


def main():
    n = 149767527975084886970446073530848114556615616489502613024958495602726912268566044330103850191720149622479290535294679429142532379851252608925587476670908668848275349192719279981470382501117310509432417895412013324758865071052169170753552224766744798369054498758364258656141800253652826603727552918575175830897L
    p = 11807485231629132025602991324007150366908229752508016230400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001L
    q = 12684117323636134264468162714319298445454220244413621344524758865071052169170753552224766744798369054498758364258656141800253652826603727552918575175830897L
    e = 65537L
    priv = RSA.construct((n, e, long(gmpy2.invert(e, (p - 1) * (q - 1)))))
    open('private.pem', 'w').write(priv.exportKey('PEM'))


main()

最后,将私钥导入到 wireshark 中即可得到明文(Edit -> Preferences -> Protocols -> SSL -> RSA Key List)。

<html>
<head><title>Very smooth</title></head>
<body>
<h1>
Answer: One of these primes is very smooth.
</h1>
</body>
</html>

扩展

关于更多的一些分解模数 N 的方法可以参考 https://en.wikipedia.org/wiki/Integer_factorization。

模不互素

攻击原理

当存在两个公钥的 N 不互素时,我们显然可以直接对这两个数求最大公因数,然后直接获得 p,q,进而获得相应的私钥。

SCTF RSA2

这里我们以 SCTF rsa2 为例进行介绍。直接打开 pcap 包,发现有一堆的消息,包含 N 和 e,然后试了试不同的 N 是否互素,我试了前两个

import gmpy2
n1 = 20823369114556260762913588844471869725762985812215987993867783630051420241057912385055482788016327978468318067078233844052599750813155644341123314882762057524098732961382833215291266591824632392867716174967906544356144072051132659339140155889569810885013851467056048003672165059640408394953573072431523556848077958005971533618912219793914524077919058591586451716113637770245067687598931071827344740936982776112986104051191922613616045102859044234789636058568396611030966639561922036712001911238552391625658741659644888069244729729297927279384318252191421446283531524990762609975988147922688946591302181753813360518031
n2 = 19083821613736429958432024980074405375408953269276839696319265596855426189256865650651460460079819368923576109723079906759410116999053050999183058013281152153221170931725172009360565530214701693693990313074253430870625982998637645030077199119183041314493288940590060575521928665131467548955951797198132001987298869492894105525970519287000775477095816742582753228905458466705932162641076343490086247969277673809512472546919489077884464190676638450684714880196854445469562733561723325588433285405495368807600668761929378526978417102735864613562148766250350460118131749533517869691858933617013731291337496943174343464943
print gmpy2.gcd(n1, n2)

结果发现竟然不互素。

➜  scaf-rsa2 git:(master) ✗ python exp.py
122281872221091773923842091258531471948886120336284482555605167683829690073110898673260712865021244633908982705290201598907538975692920305239961645109897081011524485706755794882283892011824006117276162119331970728229108731696164377808170099285659797066904706924125871571157672409051718751812724929680249712137

那么我们就可以直接来解密了,这里我们利用第一对公钥密码。代码如下

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5, PKCS1_OAEP
import gmpy2
from base64 import b64decode
n1 = 20823369114556260762913588844471869725762985812215987993867783630051420241057912385055482788016327978468318067078233844052599750813155644341123314882762057524098732961382833215291266591824632392867716174967906544356144072051132659339140155889569810885013851467056048003672165059640408394953573072431523556848077958005971533618912219793914524077919058591586451716113637770245067687598931071827344740936982776112986104051191922613616045102859044234789636058568396611030966639561922036712001911238552391625658741659644888069244729729297927279384318252191421446283531524990762609975988147922688946591302181753813360518031
n2 = 19083821613736429958432024980074405375408953269276839696319265596855426189256865650651460460079819368923576109723079906759410116999053050999183058013281152153221170931725172009360565530214701693693990313074253430870625982998637645030077199119183041314493288940590060575521928665131467548955951797198132001987298869492894105525970519287000775477095816742582753228905458466705932162641076343490086247969277673809512472546919489077884464190676638450684714880196854445469562733561723325588433285405495368807600668761929378526978417102735864613562148766250350460118131749533517869691858933617013731291337496943174343464943
p1 = gmpy2.gcd(n1, n2)
q1 = n1 / p1
e = 65537
phin = (p1 - 1) * (q1 - 1)
d = gmpy2.invert(e, phin)
cipher = 0x68d5702b70d18238f9d4a3ac355b2a8934328250efd4efda39a4d750d80818e6fe228ba3af471b27cc529a4b0bef70a2598b80dd251b15952e6a6849d366633ed7bb716ed63c6febd4cd0621b0c4ebfe5235de03d4ee016448de1afbbe61144845b580eed8be8127a8d92b37f9ef670b3cdd5af613c76f58ca1a9f6f03f1bc11addba30b61bb191efe0015e971b8f78375faa257a60b355050f6435d94b49eab07075f40cb20bb8723d02f5998d5538e8dafc80cc58643c91f6c0868a7a7bf3bf6a9b4b6e79e0a80e89d430f0c049e1db4883c50db066a709b89d74038c34764aac286c36907b392bc299ab8288f9d7e372868954a92cdbf634678f7294096c7
plain = gmpy2.powmod(cipher, d, n1)
plain = hex(plain)[2:]
if len(plain) % 2 != 0:
    plain = '0' + plain
print plain.decode('hex')

最后解密如下

➜  scaf-rsa2 git:(master) ✗ python exp.py       
sH1R3_PRlME_1N_rsA_iS_4ulnEra5le

解压压缩包即可。

共模攻击

攻击条件

当两个用户使用相同的模数 N、不同的私钥时,加密同一明文消息时即存在共模攻击。

攻击原理

设两个用户的公钥分别为 $e_1$ 和 $e_2$,且两者互质。明文消息为 $m$,密文分别为:

c1=me1 mod Nc2=me2 mod Nc_1 = m^{e_1}\bmod N \\ c_2 = m^{e_2}\bmod Nc1​=me1​modNc2​=me2​modN

当攻击者截获 $c_1$ 和 $c_2$ 后,就可以恢复出明文。用扩展欧几里得算法求出 $re_1+se_2=1\bmod n$ 的两个整数 $r$ 和 $s$,由此可得:

c1rc2s≡mre1mse2 mod n≡m(re1+se2) mod n≡m mod n\begin{align*} c_{1}^{r}c_{2}^{s} &\equiv m^{re_1}m^{se_2}\bmod n\\ &\equiv m^{(re_1+se_2)} \bmod n\\ &\equiv m\bmod n \end{align*}c1r​c2s​​≡mre1​mse2​modn≡m(re1​+se2​)modn≡mmodn​

XMan 一期夏令营课堂练习

题目描述:

{6266565720726907265997241358331585417095726146341989755538017122981360742813498401533594757088796536341941659691259323065631249,773}

{6266565720726907265997241358331585417095726146341989755538017122981360742813498401533594757088796536341941659691259323065631249,839}

message1=3453520592723443935451151545245025864232388871721682326408915024349804062041976702364728660682912396903968193981131553111537349

message2=5672818026816293344070119332536629619457163570036305296869053532293105379690793386019065754465292867769521736414170803238309535

题目来源:XMan 一期夏令营课堂练习

可以看出两个公钥的 N 是一样的,并且两者的 e 互素。写一个脚本跑一下:

import gmpy2
n = 6266565720726907265997241358331585417095726146341989755538017122981360742813498401533594757088796536341941659691259323065631249
e1 = 773

e2 = 839

message1 = 3453520592723443935451151545245025864232388871721682326408915024349804062041976702364728660682912396903968193981131553111537349

message2 = 5672818026816293344070119332536629619457163570036305296869053532293105379690793386019065754465292867769521736414170803238309535
# s & t
gcd, s, t = gmpy2.gcdext(e1, e2)
if s < 0:
    s = -s
    message1 = gmpy2.invert(message1, n)
if t < 0:
    t = -t
    message2 = gmpy2.invert(message2, n)
plain = gmpy2.powmod(message1, s, n) * gmpy2.powmod(message2, t, n) % n
print plain

得到

➜  Xman-1-class-exercise git:(master) ✗ python exp.py
1021089710312311910410111011910111610410511010710511610511511211111511510598108101125

这时候需要考虑当时明文是如何转化为这个数字了,一般来说是 16 进制转换,ASCII 字符转换,或者 Base64 解密。这个应该是 ASCII 字符转换,进而我们使用如下代码得到 flag

i = 0
flag = ""
plain = str(plain)
while i < len(plain):
    if plain[i] == '1':
        flag += chr(int(plain[i:i + 3]))
        i += 3
    else:
        flag += chr(int(plain[i:i + 2]))
        i += 2
print flag

这里之所以使用 1 来判断是否为三位长度,是因为 flag 一般都是明文字符,而 1 开头的长度为 1 或者 2 的数字,一般都是不可见字符。

flag

➜  Xman-1-class-exercise git:(master) ✗ python exp.py
flag{whenwethinkitispossible}

题目

  • Jarvis OJ very hard RSA

Previous公钥指数相关攻击NextBleichenbacher's attack

Last updated 1 year ago