RSA:基于小加密指数的攻击方式与思维技巧
目录
目录
目录
零、前言
一、小加密指数爆破
[FSCTF]RSA签到
思路:
二、基于小加密指数的有限域开根
[NCTF 2019]easyRSA
思路:
三、基于小加密指数的CRT
[0CTF 2016] rsa
思路:
零、前言
最近,发现自己做题思路比较混乱。总的来说,就是在各种方法之间很难适配到对应的题目。所以,写下这篇博客来记录这些区别。特别说明的是,这篇文章更偏向于解题,而不是讲解原理。考虑到两个点,在写下这篇博客时本人其实也才学习了近1个月的密码学,数学知识严重匮乏,不敢乱教与解析原理。其次,备战省赛在即没有充分多的时间让我去了解学习深层次的原理。所以这里只能够给出使用条件,也就是应用层面上的区分。
此外特别声明,该篇博客更多的偏向于个人学习使用,其次是帮助大家应用。再者也欢迎各位指出错误,与提出问题。本人会在能力范围内尽可能作答。
一、小加密指数爆破
小加密指数爆破是最为简单的求解方式。几乎遇到小加密指数都可以尝试一下。因为它使用条件最为简单:加密指数小。需要注意的是,又是时候我需要分析数据特征。例如分析出flag比较短,即密文c很小时。我们可以优先直接开e次方。这一技巧出现于FSCTF中,这能帮助我们剔除混淆视听的提示--干扰信息。
[FSCTF]RSA签到
from Crypto.Util.number import *
from secret import flag
m = bytes_to_long(flag)
assert m.bit_length()<150
p = getPrime(512)
q = getPrime(512)
n = p*q
e = 3
c = pow(m, e, n)
kbits = 103
m = (m >> kbits) << kbits
Mod = getPrime(2048)
hint1 = (2019-2023*m) % Mod
hint2 = pow(2, 2023, Mod)
print('n =',n)
print('c =',c)
print('hint1 =',hint1)
print('hint2 =',hint2)
'''
n = 113369575322962228640839640796005129142256499725384495463316595604047079557930666699058024217561098997292782305151595366764483672240871690818579470888054811186902762990032505953330034837625667158114251720321766235335996441613828302393569643827293040591156144187232255906107532680524431761932215860898533224303
c = 42336544435252811021843650684098817755849747192874682997240960601474927692351510022965782272751339319782351146077580929125
hint1 = 23620186624579054670890922956929031966199853422018331906359817627553015939570302421768667351617160816651880338639432052134891008193969801696035505565684982786461527274477933881508678074157199742425764746919878452990468268098540220237611917321213668069666526658025737487539455262610713002399515462380573732082344497124344090365729168706760425585735014513373401622860196569544933971210142724734536588173957576667830667503151362930889494877201597267000737408071228466811160470759093928003064486766171850080985758351203536462206720715743059101285822169971058423075796415932349942113371706910521251120400151508125606778268
hint2 = 963121833542317369601573845406471251262548645428284526828835768327851746644612875378048462019053502788803516653832734212104068969204751285764221918179043624419894139984279754512017898273159626328827668380262481220865017731267802600915375183179264380651165421367773563947903391466768557089792263481734108493385146063258300495764165365295546337808852673629710735621386935094923561594142327134318905856137785813985574356271679918694447015294481691849341917432346559501502683303082591585074576786963085039546446281095048723669230856548339087909922753762884060607659880382812905450025751549153093939827557015748608
'''
思路:
通过肉眼观察,我们也能发现 密文(c) << 模数(n)。
import gmpy2
from Crypto.Util.number import *n = 113369575322962228640839640796005129142256499725384495463316595604047079557930666699058024217561098997292782305151595366764483672240871690818579470888054811186902762990032505953330034837625667158114251720321766235335996441613828302393569643827293040591156144187232255906107532680524431761932215860898533224303
c = 42336544435252811021843650684098817755849747192874682997240960601474927692351510022965782272751339319782351146077580929125
'''
print(n.bit_length())
print(c.bit_length())
n.bit_length() = 1024
c.bit_length() = 405
'''if (gmpy2.iroot(m, 3)[1]):print(gmpy2.iroot(m, 3)[0]) # m = 34852863801144743432974618956978703253885m = 34852863801144743432974618956978703253885
print(long_to_bytes(m)) # flag{sign_1n_RSA}
二、基于小加密指数的有限域开根
实际上,有限域上的开根并不需要有小加密指数的限制。指数当指数较低的时候运算速度会快一点。
有限域上的开根条件为:e | phi,且 e | 任意因子的欧拉函数。
[NCTF 2019]easyRSA
from flag import flage = 0x1337
p = 199138677823743837339927520157607820029746574557746549094921488292877226509198315016018919385259781238148402833316033634968163276198999279327827901879426429664674358844084491830543271625147280950273934405879341438429171453002453838897458102128836690385604150324972907981960626767679153125735677417397078196059
q = 112213695905472142415221444515326532320352429478341683352811183503269676555434601229013679319423878238944956830244386653674413411658696751173844443394608246716053086226910581400528167848306119179879115809778793093611381764939789057524575349501163689452810148280625226541609383166347879832134495444706697124741
n = p * qassert(flag.startswith('NCTF'))
m = int.from_bytes(flag.encode(), 'big')
assert(m.bit_length() > 1337)c = pow(m, e, n)
print(c)
# 10562302690541901187975815594605242014385201583329309191736952454310803387032252007244962585846519762051885640856082157060593829013572592812958261432327975138581784360302599265408134332094134880789013207382277849503344042487389850373487656200657856862096900860792273206447552132458430989534820256156021128891296387414689693952047302604774923411425863612316726417214819110981605912408620996068520823370069362751149060142640529571400977787330956486849449005402750224992048562898004309319577192693315658275912449198365737965570035264841782399978307388920681068646219895287752359564029778568376881425070363592696751183359
思路:
首先我们能够看到 e = 0x1337 < 0x10001,算是比较小的一个加密指数。因此我们考虑一些基于小加密指数的攻击。但是因为这里 e = 0x1337 虽然算小,但是对于开方运算来说还是比较大的。因此我们不打算尝试小加密指数爆破。
因此我们似乎只能分析其他攻击路径。那么我开始尝试有限域开根(可以思考一下,为什么后续攻击也可以不在考虑范围内,这样更真实的还原了做题的情形)。
所以我们先分析是否满足我们的使用条件。如果直接满足就是脚本题了。否则就需要一些处理操作。
e = 0x1337
p = 199138677823743837339927520157607820029746574557746549094921488292877226509198315016018919385259781238148402833316033634968163276198999279327827901879426429664674358844084491830543271625147280950273934405879341438429171453002453838897458102128836690385604150324972907981960626767679153125735677417397078196059
q = 112213695905472142415221444515326532320352429478341683352811183503269676555434601229013679319423878238944956830244386653674413411658696751173844443394608246716053086226910581400528167848306119179879115809778793093611381764939789057524575349501163689452810148280625226541609383166347879832134495444706697124741
n = p * qprint((p - 1)*(q - 1) % e) # 0
print((p - 1) % e) # 0
print((q - 1) % e) # 0
通过测试程序,我们可以确定可以使用有限域开根。因此有以下脚本。
from gmpy2 import *
from Crypto.Util.number import *
import random
import mathdef onemod(e, q):p = random.randint(1, q-1)while(powmod(p, (q-1)//e, q) == 1): # (r,s)=1p = random.randint(1, q)return pdef AMM_rth(o, r, q): # r|(q-1assert((q-1) % r == 0)p = onemod(r, q)t = 0s = q-1while(s % r == 0):s = s//rt += 1k = 1while((s*k+1) % r != 0):k += 1alp = (s*k+1)//ra = powmod(p, r**(t-1)*s, q)b = powmod(o, r*a-1, q)c = powmod(p, s, q)h = 1for i in range(1, t-1):d = powmod(int(b), r**(t-1-i), q)if d == 1:j = 0else:j = (-math.log(d, a)) % rb = (b*(c**(r*j))) % qh = (h*c**j) % qc = (c*r) % qresult = (powmod(o, alp, q)*h)return resultdef ALL_Solution(m, q, rt, cq, e):mp = []for pr in rt:r = (pr*m) % q# assert(pow(r, e, q) == cq)mp.append(r)return mpdef calc(mp, mq, e, p, q):i = 1j = 1t1 = invert(q, p)t2 = invert(p, q)for mp1 in mp:for mq1 in mq:j += 1if j % 1000000 == 0:print(j)ans = (mp1*t1*q+mq1*t2*p) % (p*q)if check(ans):returnreturndef check(m):try:a = long_to_bytes(m).decode('utf-8')if 'NCTF' in a:print(a)return Trueelse:return Falseexcept:return Falsedef ALL_ROOT2(r, q): # use function set() and .add() ensure that the generated elements are not repeatedli = set()while(len(li) < r):p = powmod(random.randint(1, q-1), (q-1)//r, q)li.add(p)return liif __name__ == '__main__':c = 10562302690541901187975815594605242014385201583329309191736952454310803387032252007244962585846519762051885640856082157060593829013572592812958261432327975138581784360302599265408134332094134880789013207382277849503344042487389850373487656200657856862096900860792273206447552132458430989534820256156021128891296387414689693952047302604774923411425863612316726417214819110981605912408620996068520823370069362751149060142640529571400977787330956486849449005402750224992048562898004309319577192693315658275912449198365737965570035264841782399978307388920681068646219895287752359564029778568376881425070363592696751183359p = 199138677823743837339927520157607820029746574557746549094921488292877226509198315016018919385259781238148402833316033634968163276198999279327827901879426429664674358844084491830543271625147280950273934405879341438429171453002453838897458102128836690385604150324972907981960626767679153125735677417397078196059q = 112213695905472142415221444515326532320352429478341683352811183503269676555434601229013679319423878238944956830244386653674413411658696751173844443394608246716053086226910581400528167848306119179879115809778793093611381764939789057524575349501163689452810148280625226541609383166347879832134495444706697124741e = 0x1337cp = c % pcq = c % qmp = AMM_rth(cp, e, p)mq = AMM_rth(cq, e, q)rt1 = ALL_ROOT2(e, p)rt2 = ALL_ROOT2(e, q)amp = ALL_Solution(mp, p, rt1, cp, e)amq = ALL_Solution(mq, q, rt2, cq, e)calc(amp, amq, e, p, q)
三、基于小加密指数的CRT
基于小加密指数的CRT,基本有以下特征。e的大小就是方程组的数目。
[0CTF 2016] rsa

思路:
下载附件,我们可以获取得到两个文件。其中pem可以使用openssl指令获取里面的内容。当然也可以使用其他方式例如:
from Crypto.PublicKey import RSA
f = open("public.pem")
data = f.read()
s = RSA.importKey(data)
print(s.n)
print(s.e)n = 23292710978670380403641273270002884747060006568046290011918413375473934024039715180540887338067
e = 3
f.close()f = open("D:/Desktop/enter/flag.enc", 'rb')
data = f.read()
print(bytes_to_long(data))
c = 2485360255306619684345131431867350432205477625621366642887752720125176463993839766742234027524
读取完文件后,我们已知的消息有(n, e, c), 其中我们需要求解m,那么我需要知道因子才能获取得到d,进而获取得到m。
print(n.bit_length())
#314
看到n的位数很小,因此我们可以分解n。

p = 26440615366395242196516853423447
q = 27038194053540661979045656526063
r = 32581479300404876772405716877547
接下来分析数据特征
print((p - 1) * (q - 1) * (r - 1) % e)
print((p - 1) % e)
print((q - 1) % e)
print((r - 1) % e)

在关注到e的大小为因子的数目,从模数运算角度出发,拆分是一种极其重要的思维。所以我们可以通过拆分n得到足够的方程数。所以,我们需要将CRT纳入考虑范围。除此之外,我们还应该考虑到,有且仅有(q - 1)不是e的倍数,因此还要考虑有限域开根或者说是解方程。获取得到c的e根次。
p = 26440615366395242196516853423447
q = 27038194053540661979045656526063
r = 32581479300404876772405716877547
ct = 2485360255306619684345131431867350432205477625621366642887752720125176463993839766742234027524PR.<x> = PolynomialRing(Zmod(p))
f = x^3-ct
res1 = f.roots()
PR.<x> = PolynomialRing(Zmod(q))
f = x^3-ct
res2 = f.roots()
PR.<x> = PolynomialRing(Zmod(r))
f = x^3-ct
res3 = f.roots()for x in res1:for y in res2:for z in res3:m = crt([int(x[0]),int(y[0]),int(z[0])],[int(p),int(q),int(r)])if b'0ctf'in long_to_bytes(m):print(long_to_bytes(m))
相关文章:
RSA:基于小加密指数的攻击方式与思维技巧
目录 目录 目录 零、前言 一、小加密指数爆破 [FSCTF]RSA签到 思路: 二、基于小加密指数的有限域开根 [NCTF 2019]easyRSA 思路: 三、基于小加密指数的CRT [0CTF 2016] rsa 思路: 零、前言 最近,发现自己做题思路比较…...
Vuex 和 Redux 的区别?
Vuex和Redux是两个流行的JavaScript状态管理库,它们有一些相似之处,但也有一些区别。 区别: 语言:Vuex是为Vue.js框架设计的,而Redux是一个独立的库,可用于多种JavaScript框架或库。生态系统:…...
软考高级系统架构师冲关预测
[ – 2023年10月27日 – ] 去年11月通过了软考高级系统架构师的考试,原本想立即分享下过关的总结回顾,但是随着软考新版大纲及教程的发布,也意味着题目及内容的复盘总结经验便不那么适用。在即将迎来今年的软考高架的时候,想着透…...
华为实验基础(1):交换机基础
一、交换机的分类 1、 根据交换方式划分: 存储转发式交换 (Store and Forward) 直通式交换 (Cut-through) 碎片过滤式交换 (Fragment Free) 2、 根据交换的协议层划分: 第二层交换:根据 MAC 地址进行交换 第三层交换&…...
bitlocker 加密锁定的固态硬盘,更换到别的电脑上,怎么把原密钥写进新电脑TPM芯片内,开启无需手动填密钥
环境: Win11 专业版 联想E14笔记本 512G ssd 问题描述: 一台笔记本因充电故障,需要拿去维修,不想重装系统,将bitlocker 加密锁定的固态硬盘拆下更换到别的笔记本电脑上,现在开机要手动填密钥,怎么把原密钥写进新电脑TPM芯片内,开启无需手动填密钥和之前那台电脑一…...
C语言之错误处理
在C语言中,错误处理是一种重要的编程技术,用于处理程序运行过程中可能出现的错误情况。C语言提供了几种处理错误的机制,包括返回错误码、使用全局变量、异常处理等。 1、返回错误码: 在函数执行过程中,如果发生错误&a…...
IO流框架,缓冲流
一.缓冲流有什么优点 Java中的缓冲流(Buffered Stream)具有以下优势: 提高效率:缓冲流通过在内存中缓存一部分数据,减少了直接从内存到磁盘或从磁盘到内存的频繁IO操作,从而提高了读写效率。缓冲区大小调整…...
数字音频工作站软件 Ableton Live 11 mac中文软件特点与功能
Ableton Live 11 mac是一款数字音频工作站软件,用于音乐制作、录音、混音和现场演出。它由Ableton公司开发,是一款极其流行的音乐制作软件之一。 Ableton Live 11 mac软件特点和功能 Comping功能:Live 11增加了Comping功能,允许用…...
【PyQt】调整子控件的层级以调整绘制的先后顺序
简述 qt中貌似没有直接设置z序的函数,但对应的有其他调整z序的方法: QWidget.raise_():置顶 QWidget.lower():置底 QWidget.stackUnder(wid):置于指定控件之下 其中关键函数是QWidget.stackUnder(wid),利…...
js中数组的相关方法
引言: 数组(Array)是有序的元素序列。 [1]若将有限个类型相同的变量的集合命名,那么这个名称为数组名。组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量 方法: push()…...
深入浅出排序算法之直接插入排序(拓展:折半插入排序)
目录 1. 图示解析 2. 原理解析 3. 代码实现 4. 性能分析 5. 折半插入排序(拓展) 直接插入排序和选择排序的第一趟就是第一个关键字 ! 1. 图示解析 2. 原理解析 整个区间被分为:① 有序区间;② 无序区间 每次选…...
皮卡丘RCE靶场通关攻略
皮卡丘RCE靶场通关攻略 文章目录 皮卡丘RCE靶场通关攻略RCE(remote command/code execute)概述远程系统命令执行启动环境漏洞练习第一关exec "ping"第二关 exec "eval" RCE(remote command/code execute)概述 RCE漏洞,可以让攻击者直接向后台服…...
Mysql binlog日志功能使用,简单易懂
一、简单了解binlog MySQL的二进制日志binlog可以说是MySQL最重要的日志,它记录了所有的DDL和DML语句(除了数据查询语句select)。因此binlog日志文件我们用cat等查看文件的命令是打不开的,但是mysql提供了专门看binlog文件的命令…...
计算机视觉-光源的目的和作用
光源的目的 机器视觉系统的核心是图像采集和图像处理,而光源则是影响图像水平的重要因素,通过适当的光源照明,使图像中的目标信息与背景信息得到更好的分离,可大大降低图像识别难度,提高系统的精度和可靠性。 对于机器…...
源码角度分析Java 循环中删除数据为什么会报异常
一、源码角度分析Java 循环中删除数据为什么会报异常 相信大家在之前或多或少都知道 Java 中在增强 for中删除数据会抛出:java.util.ConcurrentModificationException 异常,例如:如下所示程序: public class RmTest {public sta…...
leetCode 229. 多数元素 II + 摩尔投票法 + 进阶 + 优化空间
229. 多数元素 II - 力扣(LeetCode) 给定一个大小为 n 的整数数组,找出其中所有出现超过 ⌊ n/3 ⌋ 次的元素。 进阶:尝试设计时间复杂度为 O(n)、空间复杂度为 O(1)的算法解决此问题。 (1)哈希表 class …...
5 个编写高效 Makefile 文件的最佳实践
在软件开发过程中,Makefile是一个非常重要的工具,它可以帮助我们自动化构建、编译、测试和部署。然而,编写高效的Makefile文件并不是一件容易的事情。在本文中,我们将讨论如何编写高效的Makefile文件,以提高我们的开发…...
20231028刷题记录
P3381 【模板】最小费用最大流 Portal. sol. 注意 SPFA 找最小费用增广路时不要到终点就返回,因为到终点的路径可能有多条不能确定哪条是费用最小的。 P2740 [USACO4.2] 草地排水Drainage Ditches Portal. 最大流模板。 注意区分 N , M N,M N,M。 CF609D G…...
39 深度学习(三):tensorflow.data模块的使用(基础,可跳)
文章目录 data模块的使用基础api的介绍csv文件tfrecord data模块的使用 在训练的过程中,当数据量一大的时候,我们纯读取一个文件,然后每次训练都调用相同的文件,然后进行处理是很不科学的,或者说,当我们需…...
css四种导入方式
1 行内样式 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body> <h1 style"color: blue">我是标题</h1> </body> </htm…...
使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...
Razor编程中@Html的方法使用大全
文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...
Canal环境搭建并实现和ES数据同步
作者:田超凡 日期:2025年6月7日 Canal安装,启动端口11111、8082: 安装canal-deployer服务端: https://github.com/alibaba/canal/releases/1.1.7/canal.deployer-1.1.7.tar.gz cd /opt/homebrew/etc mkdir canal…...
