1. 从解题到入门:为什么你需要一份密码学总结
如果你在CTF赛场上看到一段乱码或者一个奇怪的方程就头疼,或者你刚入门网络安全,觉得密码学深不可测,那这篇文章就是为你准备的。我打CTF有年头了,从最早看Base64都发懵,到现在能快速识别和破解一些中低难度的密码学题目,中间踩过的坑、浪费的时间,足够写好几篇总结了。网上资料很多,但要么太散,要么一上来就讲复杂的数学原理,对新手极不友好。所以我想做的,就是把我这些年实战中最高频遇到、最核心的密码学知识点,用最“人话”的方式串起来,让你能快速建立一套可用的解题框架。
密码学在CTF中,尤其是入门和中级比赛中,出场率极高。它不像Web渗透那样有那么多“骚操作”,也不像逆向工程那样需要深厚的底层功底。密码学的题目,很多时候考的是“见识”和“工具使用”。你知道这是什么编码、什么加密,手边有合适的工具,往往就能秒解;如果不知道,可能对着题目干瞪眼一晚上。这份总结的目的,就是帮你扩充“见识库”,并告诉你这些“见识”该怎么用。我们会从最基础的编码开始,讲到古典密码、现代对称/非对称加密,以及一些常见的攻击思路和技巧。我不会深入讲解RSA背后那复杂的数论证明,但我会告诉你,当你拿到一道RSA题时,应该按什么步骤去分析、去尝试,以及哪些工具能帮你省时省力。
2. 密码学解题核心思路拆解
面对一道密码学题目,老手和新手的最大区别不在于懂得多少算法,而在于有一套系统性的分析思路。新手容易陷入盲目尝试,而老手则像医生问诊一样,一步步缩小范围。
2.1 第一步:观察与信息收集(CTF版“望闻问切”)
任何密码题都不会是孤零零给一串密文。你需要像侦探一样,收集所有可能的信息。
- 题目描述与标题:这是最直接的提示。题目名可能就叫“凯撒的秘密”、“RSA签到”、“Base64?没那么简单”。描述里可能包含“移位”、“密钥”、“flag格式”等关键词。
- 附件内容:如果提供了文件(如
.txt,.py,.pem),一定要仔细查看。一个.pem文件可能直接包含了RSA的公钥或私钥;一个.py脚本可能泄露了加密的逻辑或参数。 - 密文特征:这是判断编码或加密类型最直观的依据。
- 仅由数字组成:可能是十进制ASCII、坐标、或其他数字编码。
- 仅由
A-Z、a-z、0-9、+、/和=组成:这几乎是Base64的“身份证”。注意,=是填充字符,可能出现在末尾。 - 仅由
A-F、a-f、0-9组成:典型的十六进制(Hex)编码。 - 由
%后跟两个十六进制数组成(如%41):这是URL编码。 - 字符分布均匀,无明显规律:可能是AES、DES等现代分组加密的结果,或者是经过多次编码/加密的套娃题。
- 字符频率有规律(英文文本):可能是古典密码(如凯撒、维吉尼亚、替换密码)。可以用在线工具分析词频。
- 包含花括号
{}、flag字样:有时出题人不会完全加密flag格式,这可以作为已知明文攻击的突破口。
- 上下文信息:在Web题或杂项题中,密码可能藏在HTTP响应头、图片注释、源代码注释、网络流量包中。
注意:第一步切忌直接上手就解密。花两三分钟做好信息收集,能为你节省后面几十分钟甚至几小时的无效尝试。
2.2 第二步:分类与尝试(从简单到复杂)
根据收集到的信息,按照“编码 -> 古典密码 -> 现代密码”的优先级进行尝试。这个顺序是基于解题效率的:解码通常最快,古典密码次之,现代密码需要更多分析。
- 编码识别与解码:这通常是第一道关卡。很多题目会把flag用Base64、Hex、URL、ASCII等编码进行多次转换(即“套娃”)。你需要一层层剥开。
- 工具:浏览器开发者工具(Console)、Python的
base64、binascii库、CyberChef(全能在线工具)是必备的。 - 技巧:写一个简单的Python脚本进行循环解码直到出现可读文本,是非常高效的方法。
- 工具:浏览器开发者工具(Console)、Python的
- 古典密码分析:如果解码后得到的是像英文但读不懂的文本,考虑古典密码。
- 凯撒密码:最简单,暴力移位(0-25)即可。
- 单表替换密码:字符频率分析是王道。英文中
e、t、a出现频率最高。使用quipqiup这类在线词频分析工具能极大提高效率。 - 维吉尼亚密码:首先需要确定密钥长度(常用Kasiski测试法或重合指数法),然后对每个分组进行频率分析猜解密钥。
Vigenère Solver等自动化工具可以辅助。 - 栅栏密码:尝试不同的栏数。
- 现代密码分析:这需要更多密码学知识。
- 对称加密(AES, DES):题目通常会给出加密脚本或提示加密模式。关键点在于密钥。密钥可能弱(如短密码、常见单词),可能被隐藏在别处,或者加密模式不安全(如ECB模式可能导致信息泄露)。
- 非对称加密(RSA):这是CTF密码学的重头戏。解题关键在于利用给出的条件(如
n,e,c,p,q,dp,dq等)和已知的攻击方法(如模数分解、共模攻击、低加密指数攻击、维纳攻击等)。 - 哈希与摘要(MD5, SHA1):通常不是让你破解哈希(那是彩虹表的活),而是考察哈希长度扩展攻击、哈希碰撞,或是让你识别出已知的哈希值(去在线网站反查)。
2.3 第三步:工具化与脚本化
不要重复造轮子,也不要纯手工操作。成熟的CTF选手一定是“工具人”。
- 离线工具:
Python+pwntools/Crypto库是你的瑞士军刀。openssl命令行工具用于处理证书和加解密。RSACTFTool、RsaCtfTool等专门针对RSA攻击。 - 在线工具:
CyberChef(编码/加密/解码/解密全能厨房)、quipqiup(词频分析)、factordb(分解大整数)、dcode.fr(多种密码工具集合)。 - 脚本思想:对于需要暴力破解、遍历、或者复杂计算的问题,第一时间想到写脚本。比如暴力破解4位数字PIN码、遍历所有可能的栅栏数、尝试用不同的IV解密CBC模式。
3. 核心密码类型详解与实战要点
这一部分,我们将深入几种CTF中最常见的密码类型,不仅讲是什么,更讲怎么考、怎么解。
3.1 编码:信息表示的“七十二变”
编码不是加密,它只是信息的不同表示形式,通常没有密钥,过程可逆。
1. Base64:出场率之王
- 原理:将每3个字节(24位)的数据,重新划分为4组,每组6位。这6位二进制数(范围0-63)对应一个字符,映射表是
A-Z、a-z、0-9、+、/。末尾用=填充。 - CTF考点:
- 单纯解码:给一段Base64,解码即可。
CyberChef里丢进去就行。 - 换表Base64:出题人自定义一张64个字符的映射表。你需要从题目附件(通常是加密脚本)中找到这张表,然后用它来解码。解题关键就是找到并替换标准Base64表。
- Base64隐写:这是一个经典考点。Base64编码时,末尾的
=(填充位)所对应的二进制数据有时会被忽略,但一些工具会把这些“无效”位也存储起来。利用这些位可以隐藏信息。需要使用专门的工具(如b64stegano)或脚本来提取。
- 单纯解码:给一段Base64,解码即可。
- 实操命令:
# Linux命令行解码 echo “SGVsbG8gV29ybGQ=” | base64 -d # Python解码 import base64 base64.b64decode(“SGVsbG8gV29ybGQ=”)
2. 十六进制(Hex)与URL编码
- Hex编码:每个字节用两个
0-9、a-f的字符表示。CyberChef中的From Hex操作即可。 - URL编码:为了在URL中安全传输特殊字符,将字符转换为
%后跟其ASCII码的十六进制形式。例如,空格是%20。在Web题中极为常见。 - 考点:通常作为一层简单的包装,或者与其他编码/加密结合。注意区分大小写。
3. 套娃编码这是新手最容易卡住的地方。题目可能将flag先进行Base64编码,结果再进行Hex编码,然后再进行URL编码……如此循环多次。
- 解法:手动一层层剥固然可以,但更高效的是用CyberChef的魔法(Magic)功能。它能够自动检测并尝试多种编码组合。或者写一个Python脚本,用
try-except循环尝试常见的解码操作,直到输出中包含flag或{等特征字符串。
3.2 古典密码:智慧与频率的博弈
古典密码的安全性基于算法的保密性,而非密钥。在现代计算机面前,它们大多很脆弱。
1. 凯撒密码(移位密码)
- 原理:将明文中的所有字母在字母表上向后(或向前)按照一个固定数目进行偏移。
- CTF考点:纯凯撒题已经很少,但常作为一部分出现。比如,先凯撒移位,再进行其他操作。
- 工具:任何古典密码工具都支持凯撒暴力破解。
dcode.fr上的凯撒密码工具可以瞬间展示所有25种可能的结果。
2. 单表替换密码
- 原理:建立一个明文字母到密文字母的一一映射表。比如所有
a都替换成Q,所有b替换成W。 - 攻击方法——频率分析:这是核心。英文中字母
e的出现频率最高(约12.7%),其次是t,a,o,i,n等。双字母组合(th,he,in,er等)、三字母组合(the,and,ing)也有明显统计特征。 - 实操心得:
- 不要试图完全手动分析。将密文粘贴到
quipqiup.com,它会自动进行频率分析并给出最可能的明文。你只需要根据上下文微调几个字母即可。 - 如果密文较短,频率特征不明显,可以尝试结合题目描述或flag格式(如
flag{)进行已知明文攻击,推测出部分映射关系。
- 不要试图完全手动分析。将密文粘贴到
3. 维吉尼亚密码
- 原理:使用一个关键词作为密钥,对明文进行循环的凯撒移位加密。安全性比单表替换高很多。
- 解题步骤:
- 确定密钥长度:使用Kasiski测试(寻找重复的密文片段,计算其间距的公约数)或计算重合指数(Index of Coincidence, IC)。在线工具可以自动完成这一步。
- 分割密文:根据密钥长度
n,将密文分成n组,每组由被密钥中同一个字母加密的密文组成。 - 频率分析每组:此时,每一组都是一个单表替换(实际上是凯撒密码)。对每一组进行频率分析,猜解出密钥的对应字母。
- 拼接密钥并解密。
- 工具:
Vigenère Cipher Solver(如guballa.de的版本)可以一站式完成上述所有步骤,是解决维吉尼亚题的利器。
3.3 现代密码学核心:RSA的常见攻击套路
RSA题目千变万化,但攻击方式相对固定。你需要像背公式一样熟悉以下几种场景。
前置知识回顾:
n = p * q:大模数。e:加密指数,通常为65537。c:密文,c = m^e mod n。φ(n) = (p-1)*(q-1):欧拉函数。d:私钥,满足e*d ≡ 1 mod φ(n)。m:明文,m = c^d mod n。
攻击场景与工具:
场景一:直接分解n
- 条件:
n较小(通常小于512位)或p和q很接近。 - 工具:
- 在线网站:
factordb.com。这是你的第一选择,它有一个庞大的已分解数数据库。 - 本地工具:
yafu(强大的整数分解工具)。命令如yafu “factor(n)”。 - Python库:
sympy的factorint函数,适用于小整数。
- 在线网站:
- 实操:拿到
n,先扔factordb查一下。如果查不到,且n不大,再用yafu尝试分解。
场景二:共模攻击
- 条件:相同的
n,不同的e,加密了同一明文m。 - 原理:如果
gcd(e1, e2)=1,根据扩展欧几里得算法,可以找到r和s使得e1*r + e2*s = 1。那么,m = (c1^r * c2^s) mod n。 - 工具:
RsaCtfTool(--attack common_modulus)或自己写Python脚本实现扩展欧几里得算法。
场景三:低加密指数攻击(如e=3)
- 条件:
e很小(如3),且明文m满足m^e < n。 - 原理:此时
c = m^e(没有模运算),直接对c开e次方即可得到m。 - 扩展——广播攻击:如果相同的低
e加密了同一个明文m,但发送给了k(k>=e)个不同的接收者(即有不同的n_i),可以利用中国剩余定理(CRT)恢复m。 - 工具:
RsaCtfTool(--attack hastad)或使用sage/Python的gmpy2库进行CRT计算。
场景四:维纳攻击
- 条件:私钥
d相对n来说过小(具体条件与e和n的位数有关)。 - 原理:利用连分数逼近来从
e和n中恢复出d。 - 工具:
RsaCtfTool(--attack wiener)是首选。当e很大(接近n)时,可以优先尝试此攻击。
场景五:已知dp, dq泄露
- 条件:给出了
p,q,dp(d mod (p-1)),dq(d mod (q-1)),但没有直接给d或φ(n)。 - 原理:利用中国剩余定理可以高效计算
m = c^d mod n。这是RSA-CRT的实现方式,泄露这些参数同样危险。 - 工具:写脚本。公式是:
import gmpy2 # 假设已定义 p, q, dp, dq, c InvQ = gmpy2.invert(q, p) # 计算q对p的模逆 m1 = pow(c, dp, p) m2 = pow(c, dq, q) h = (InvQ * (m1 - m2)) % p m = m2 + h * q print(bytes.fromhex(hex(m)[2:]))
场景六:p和q相近(Fermat分解)
- 条件:
p和q非常接近,即|p-q|很小。 - 原理:令
a = (p+q)/2,b = (p-q)/2,则n = a^2 - b^2。由于b很小,可以从a = sqrt(n)开始尝试,检查a^2 - n是否为完全平方数。 - 工具:
RsaCtfTool(--attack fermat)或自己实现上述算法。
重要心得:拿到一道RSA题,首先把所有给出的参数(
n, e, c, p, q, dp, dq, ...)整理出来。然后对照上述场景,看符合哪个条件。优先尝试factordb分解n,如果不行,再根据e的大小、参数组合来判断可能适用的攻击方法。RsaCtfTool是一个集大成的工具,支持--attack指定多种攻击模式,通常能解决大部分常规题。
4. 实战流程与工具链配置
理论说再多,不如实际走一遍。这里我以一个虚构的、但融合了常见考点的“套娃题”为例,展示完整的解题流程。
4.1 题目假设与初始分析
我们收到一个文件challenge.txt,内容如下:
题目:找到真正的flag。 密文:U2FsdGVkX1%2B9L%2F7%2F8J%2BqKjJd%2FkzWp%2FmN%2FZ%2F%2Bv%2F7f3t%2Fe397f3 提示1:不止一层。 提示2:与“salted”有关。第一步:观察与信息收集
- 密文包含大量
%符号,这是明显的URL编码特征。 - 提示“不止一层”说明是多重编码/加密。
- 提示“与‘salted’有关”。在密码学中,“Salted”经常出现在OpenSSL加密的标识中。
U2FsdGVkX1是OpenSSL使用Salted__作为魔数并进行Base64编码后的固定开头。
第二步:分类与尝试
- 第一层:URL解码。使用CyberChef,添加
URL Decode模块。解码后得到:U2FsdGVkX1+9L/7/8J+qKjJd/kzWp/mN/Z/+v/7f3t/e397f3可以看到,%2B解码成了+,%2F解码成了/。现在字符串由B64字符集和+、/组成。 - 第二层:Base64解码。在CyberChef中接着添加
From Base64模块。注意,这里的+和/是标准Base64字符。解码后得到一串看起来像乱码的二进制数据。CyberChef可能会将其显示为Hex。 - 分析结果:解码后的数据,其开头部分在Hex视图下可能是
Salted__的ASCII码(53616c7465645f5f)。这验证了提示2。这表明数据是经过OpenSSL加密的,格式通常是Salted__(8字节) + 盐值(8字节) + 密文。 - 第三层:OpenSSL解密。现在我们需要知道加密算法和密码。题目没有直接给。常见的考察点是AES-256-CBC或DES。密码(口令)可能是弱密码,如
password、123456、flag,或者藏在题目其他地方(如图片、注释)。这里我们假设密码是弱密码password。- 工具选择:可以使用OpenSSL命令行,但CyberChef更方便。
- CyberChef操作:添加
Decrypt模块,选择AES Decrypt。模式选CBC。输入密码password。因为数据包含盐值,所以IV参数通常留空(工具会自动从输入数据头部提取盐值并推导IV)。点击执行。 - 尝试:如果AES-256-CBC不行,尝试AES-128-CBC、DES等。如果密码不对,需要结合其他线索或进行简单的字典爆破(可以用
John the Ripper或hashcat,但本题假设密码已知)。
假设我们使用AES-256-CBC和密码password解密成功,输出是一段可读文本:flag_is_here{Base64_Url_And_Openssl_AES}
4.2 工具链配置建议
一个高效的环境能让你事半功倍。
- 浏览器书签:
- CyberChef:
https://gchq.github.io/CyberChef/ - quipqiup(词频分析):
https://www.quipqiup.com/ - dCode(多种密码工具):
https://www.dcode.fr/en - FactoDB(因数分解):
http://factordb.com/
- CyberChef:
- 本地Python环境:
- 安装
pwntools:CTF全能库,处理网络交互、数据打包解包非常方便。 - 安装
pycryptodome或cryptography:提供标准的加密算法实现。 - 安装
gmpy2:用于大整数运算,解RSA题必备。 - 安装
sympy:用于数学计算和分解小整数。
- 安装
- 专用工具:
RsaCtfTool(GitHub): 集成了绝大多数RSA攻击脚本,命令行调用,非常强大。John the Ripper&hashcat:密码破解神器,对于弱密钥、哈希碰撞等题目有用。Wireshark&NetworkMiner:分析流量包中的密码数据。
- 脚本模板:准备一些常用的Python脚本模板,比如Base64/Hex循环解码、简单凯撒/栅栏暴力、RSA共模/低指数攻击脚本。比赛时直接修改参数就能用。
5. 常见问题与排查技巧实录
即使知道了方法,实战中还是会遇到各种奇怪的问题。这里记录一些我踩过的坑和解决技巧。
问题1:Base64解码报错“Incorrect padding”。
- 原因:Base64字符串的长度必须是4的倍数,且填充符
=的位置和数量可能被破坏或移除。 - 解决:
- 首先,检查字符串长度。如果不是4的倍数,尝试在末尾补上1或2个
=。 - 有时出题人会去掉
=。你可以手动补上,或者使用Python的base64.b64decode(cipher + ‘=’)并捕获异常,尝试补一个或两个=。 - 使用
base64.urlsafe_b64decode,它处理-和_替换+和/的情况。 - 终极方法:使用
base64.b64decode(cipher, validate=False),但这不是标准做法,可能解码出错误数据。
- 首先,检查字符串长度。如果不是4的倍数,尝试在末尾补上1或2个
问题2:古典密码词频分析工具给了结果,但看起来还是不对。
- 原因:
- 密文太短,统计特征不明显。
- 明文不是标准英文,可能是技术术语、flag格式或其他语言。
- 工具猜错了几个关键字母。
- 解决:
- 利用已知明文:CTF的flag通常有固定格式,如
flag{、ctf{、SECCON{。将密文中对应位置的字母强制替换为已知明文,然后让工具基于此重新分析。 - 手动微调:工具给出的结果通常接近80%正确。仔细阅读输出,根据英文单词的构成(如
th、ing、tion常见)手动修正几个字母,可能就全通了。 - 尝试其他工具:不同的词频分析工具可能使用不同的字典或算法,换一个试试(如
dcode.fr的替换密码求解器)。
- 利用已知明文:CTF的flag通常有固定格式,如
问题3:RSA题目给了n和e,用factordb分解不了,yafu也跑不出来。
- 排查思路:
- 检查n的长度:如果n超过1024位,常规分解在比赛时间内可能不现实,需要考虑其他攻击路径。
- 检查e的大小:如果e非常大(接近n),思考维纳攻击。如果e非常小(如3, 17),思考低加密指数攻击或广播攻击。
- 检查是否有多组n、e、c:如果有两组以上的数据,考虑共模攻击或广播攻击。
- 检查是否给了其他参数:仔细阅读题目,看是否附件中隐藏了
p、q、dp、dq、hint等文件。dp、dq泄露是常见考点。 - 检查n是否有特殊性质:用
python检查gcd(n1, n2),看多个n之间是否有公因数。或者检查n是否是素数(gmpy2.is_prime),有些题会直接给p=n。 - 搜索已知的n:有时出题人会复用以前题目用过的n,或者使用一些著名的、已被分解的RSA数字(如RSA-768)。可以尝试用n的十进制或十六进制值去搜索引擎或CTF社区搜索。
问题4:使用工具解密AES/DES时,输出仍是乱码。
- 可能原因:
- 密码错误:这是最常见的原因。回顾题目所有描述、注释、文件名、其他附件,寻找可能的密码。尝试空密码、
password、123456、flag、key等弱密码。 - 加密算法或模式错误:AES还分ECB、CBC、CFB等模式。如果模式不对,解密会失败。题目脚本通常会写明,如
AES.MODE_CBC。如果没有,CBC是最常见的。 - IV(初始化向量)错误:CBC模式需要IV。如果加密时IV是随机的并放在密文前,解密时需要正确提取。如果IV是全零或与密钥相关,题目可能会暗示。
- 数据格式问题:确保你提供给解密函数的数据是原始的字节串(bytes),而不是经过Hex或Base64编码的字符串。在CyberChef中,要注意模块之间数据格式的衔接(是
Raw还是Hex)。
- 密码错误:这是最常见的原因。回顾题目所有描述、注释、文件名、其他附件,寻找可能的密码。尝试空密码、
问题5:题目说是“逗号隐写”或“零宽字符隐写”。
- 逗号隐写:通常指在文本中,利用中文全角逗号“,”和英文半角逗号“,”的差异,或者逗号数量的差异,来隐藏二进制信息(如摩斯电码)。你需要将不同的逗号映射为0和1。
- 零宽字符隐写:这是一种在网页或文本中插入不可见Unicode字符(如零宽空格、零宽连接符等)来隐藏信息的方法。
- 解决:
- 将文本复制到一个能显示所有字符的编辑器(如VS Code,并开启“渲染空白字符”功能)。
- 对于逗号隐写,写脚本统计并转换。对于零宽字符,可以使用在线解码工具(搜索“zero width character decoder”)或Python库
zlib配合特定算法提取。
最后,也是最重要的心得:保持耐心和条理。密码学题目有时就像解谜,信息可能分散在各处。把所有线索写在草稿纸上,一步步推导。当一种思路卡住超过15分钟时,果断跳出来,重新审题,或者换一种攻击假设。多打比赛,多复盘别人的Writeup,你的“武器库”和“条件反射”会越来越丰富。这套总结是一个起点,希望能帮你推开CTF密码学这扇门,后面的路,还需要你在实战中不断积累和探索。