ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

CTF竞赛中密码学与二进制安全的实战关联与解题框架

CTF竞赛中密码学与二进制安全的实战关联与解题框架 1. 从CTF公开赛题看密码学与二进制安全的实战关联最近在复盘NewStarCTF 2023公开赛道第三周的题目特别是Crypto密码学和Pwn二进制漏洞利用这两个方向的题目感触颇深。很多人会把这两个方向割裂开来看觉得一个是数学和算法的艺术另一个是底层内存和指令的魔术。但真正上手做一遍这些题目你会发现它们的内核是相通的——都是对“信息”和“控制流”的极致理解与操纵。这周的题目设置就很有意思没有给具体的题目描述只留下了“week3 crypto/pwn”这个标签这反而给了我们一个更广阔的视角去探讨这两个领域在CTF竞赛中的典型套路、解题心法以及背后的知识体系。对于刚入门安全竞赛的朋友来说Crypto和Pwn常常是两座大山。Crypto题可能给你一段看不懂的数学符号和算法描述让你去破解一个加密系统Pwn题则是给你一个可执行程序让你找到它的漏洞并利用它来获取权限通常是拿到一个shell。表面上看风马牛不相及但它们的解题流程都遵循一个相似的逻辑逆向分析理解系统- 寻找弱点发现异常- 构造利用达成目标。这周的题目虽然没有具体内容但我们可以基于常见的出题模式深入拆解在这两个方向上一个合格的赛手需要掌握的核心技能树、工具链以及那些在官方Writeup里不会写的“踩坑”经验。2. Crypto题目不止于套公式关键在于理解“信息”的形态密码学题目在CTF中往往不是考察你对AES、RSA算法本身的实现而是考察你对算法在特定场景下应用时其“信息”暴露出的弱点。常见的题型包括古典密码、现代对称/非对称密码的误用、基于数论难题的挑战以及交互题。2.1 古典密码与编码识别与爆破的艺术很多入门级的Crypto题会从古典密码或编码开始。这看起来简单但关键在于快速识别和选择工具。常见类型凯撒密码、仿射密码、维吉尼亚密码、栅栏密码以及Base64、Base32、十六进制、莫尔斯电码等各种编码。核心思路观察密文的字符集分布、频率或者题目给出的任何提示如flag格式为flag{...}。对于凯撒密码可以尝试遍历所有偏移量0-25对于维吉尼亚密码需要先推测密钥长度通常使用Kasiski测试或重合指数法再对每一组进行频率分析。实战工具与技巧CyberChef一个在线的“密码学厨房”集成了绝大多数古典密码和编码的操作。它的优势是可视化、可组合操作Magic功能有时有奇效非常适合快速试错。Python脚本对于需要批量尝试或复杂逻辑的题目自己写Python脚本是必备技能。例如处理只包含数字和括号的“Brainfuck”或“Ook!”编码用脚本转换比手动快得多。一个容易忽略的坑题目给的密文可能是多种编码嵌套的结果。比如先Base64再十六进制最后还做了字符替换。这时候需要耐心一步步逆向尝试。一个经验法则是先尝试最常见的Base64解码如果输出是乱码但包含%或\x可能是URL编码或字节串如果输出很像ASCII但不可读可能是异或XOR了某个固定值。2.2 现代密码RSA的无数种“死法”RSA是CTF Crypto的绝对主角围绕它能衍生出无数考点。解题的关键在于理解RSA的数学原理c m^e mod n 解密是m c^d mod n 其中d是私钥满足e*d ≡ 1 mod φ(n)φ(n) (p-1)*(q-1)。常见攻击场景与工具直接分解n当n较小时如小于512位可以使用网站如factordb.com或工具yafu进行分解。如果n是平滑数即它的质因数都很小也可以用Pollards p-1算法。共模攻击同一明文m用相同的n但不同的e1, e2加密得到c1, c2。如果gcd(e1, e2)1则可以通过扩展欧几里得算法找到一组r,s使得r*e1 s*e2 1 那么m (c1^r * c2^s) mod n。用Python的gmpy2库可以轻松实现。低加密指数攻击当e很小如3且m^e n时加密过程实际上没有取模直接对c开e次方即可得到m。维纳攻击当私钥d很小时可以通过连分数展开来逼近d。使用RsaCtfTool或owiener脚本可以自动化完成。p和q相近此时p ≈ q ≈ sqrt(n) 可以从sqrt(n)附近开始爆破。泄露部分信息题目可能给出p或q的高位或低位、dpd mod (p-1)等需要利用Coppersmith定理在有限域内求解小根。这是难点通常使用SageMath来构造和求解方程。必备工具链Python gmpy2库处理大数运算的黄金组合。SageMath解决涉及数论、多项式环、格Lattice攻击的利器尤其是Coppersmith方法。RsaCtfTool一个集成了多种RSA攻击方法的自动化工具在已知部分信息或遇到常见攻击模式时可以首先尝试用它。个人踩坑记录有一次遇到一个题给了n, e, c还有hint (pq) % (2**512)。这其实是泄露了pq的低512位。我一开始试图直接用这个值去解方程浪费了很多时间。正确的思路是设s pq 已知s_low s mod 2^512 那么s s_low k * 2^512。 又因为n p*q 且φ(n) n - s 1。 我们可以枚举一个较小的k对于每个k计算一个s进而计算一个φ(n)然后检查d invert(e, φ(n))用这个d去解密c看解密出的明文是否包含flag字样。这就是一个典型的“部分信息泄露爆破”的组合拳。2.3 交互题与侧信道思想有些Crypto题是以网络交互的形式出现你需要连接到一个服务器它会给你加密 oracle 或解密 oracle允许你提交数据并返回加密/解密结果但对flag相关操作有限制。这类题考察的是如何通过精心构造的输入从oracle的反馈中提取信息。Padding Oracle Attack针对CBC模式下的分组密码如果服务器会返回解密后的填充是否正确攻击者就可以利用这个信息逐字节破解出密文对应的明文。padbuster或自己编写脚本可以实现。选择密文攻击例如在RSA中如果有一个解密oracle但不能解密flag本身你可以提交c c * r^e mod n 其中r是你选的随机数。服务器会返回m (c)^d mod n m * r mod n。 你再用m * inv(r) mod n就能得到原始的m。这考察了对RSA乘法同态性的理解。实战心得做交互题一定要本地先模拟逻辑把交互流程用Python的socket或pwntools库写清楚。最重要的是处理网络数据的编码bytes/string和解析往往需要正则匹配一个字符的错误就可能导致整个流程失败。建议在脚本里加入详细的print日志便于调试。3. Pwn题目从程序逻辑到控制流劫持的完整链条Pwn题目的核心目标是获取目标程序的shell或读取flag文件。这个过程通常分为几步分析程序保护机制、逆向分析找到漏洞点、构造利用载荷Exploit、最终完成利用。3.1 前期分析知己知彼百战不殆拿到一个二进制文件通常是ELF格式不要急着运行先用一套工具链把它“看透”。file命令查看文件类型和架构。ELF 64-bit LSB executable, x86-64这是最常见的信息。checksec命令这是pwntools里的工具用于检查程序开启了哪些安全保护。RELRO部分Partial或完全Full影响全局偏移表GOT是否可写。Stack Canary栈溢出保护防止覆盖返回地址。NX数据执行保护栈和堆上的代码不可执行。PIE地址空间布局随机化使代码段的基地址每次运行都变化。这些信息直接决定了你能使用哪种利用技术。strings命令提取文件中的字符串有时能直接发现/bin/sh、flag文件名或关键的提示信息。IDA Pro / Ghidra / Binary Ninja进行静态反汇编和反编译。这是最耗时的步骤目的是理解程序的主要逻辑、函数调用关系以及寻找潜在的漏洞函数如gets,scanf,strcpy,read等。3.2 漏洞挖掘与利用栈溢出入门与进阶栈溢出是最经典也最基础的漏洞类型。其原理是向栈上的缓冲区写入超过其分配大小的数据覆盖了相邻的返回地址rip从而控制程序执行流。基本利用步骤确定偏移量需要精确知道从缓冲区开始到返回地址之间的字节数。可以用pwntools的cyclic功能生成一串唯一模式字符串造成崩溃后查看rip寄存器的值再用cyclic_find计算偏移。寻找后门或构造ROP如果程序本身有system(“/bin/sh”)这样的后门函数直接跳转到其地址即可。如果没有且开启了NX保护就需要使用ROPReturn-Oriented Programming技术。ROP是在现有代码片段gadget中寻找以ret结尾的小指令序列将它们串联起来达到调用system等函数的目的。泄露地址如果开启了PIE和ASLR代码和库的基地址是随机的。通常需要先利用一次漏洞如格式化字符串漏洞或能泄露内存的栈溢出来泄露某个已知函数的地址如puts在GOT表中的地址然后计算出libc的基地址进而得到system和字符串/bin/sh的真实地址。构造Payload最终的payload结构通常是[填充垃圾数据] [目标地址] [函数参数]。对于64位系统参数传递优先使用寄存器rdi, rsi, rdx...所以payload中可能需要包含设置寄存器的gadget。工具与技巧pwntoolsPwner的瑞士军刀。它集成了本地/远程交互、汇编/反汇编、ELF文件解析、ROP链构建、调试器集成等功能。写exp脚本几乎离不开它。ROPgadget / ropper用于在二进制文件中搜索可用的gadget。one_gadget在libc中寻找直接调用execve(“/bin/sh”, NULL, NULL)的单一gadget地址有时能简化利用。GDB pwndbg/gef插件动态调试神器。可以下断点、单步执行、查看内存和寄存器状态、修改内存等。heap命令对于堆题尤其重要。一个典型的栈溢出利用脚本框架from pwn import * context(os‘linux’, arch‘amd64’, log_level‘debug’) # 本地或远程连接 # p process(‘./pwn’) p remote(‘node4.buuoj.cn’, 12345) elf ELF(‘./pwn’) # 1. 计算偏移 offset 0x70 8 # 假设通过cyclic计算得出 # 2. 构造ROP链 (假设没有PIE有libc地址) pop_rdi 0x400913 # gadget: pop rdi; ret ret 0x4005ae # gadget: ret; (用于栈对齐) binsh next(elf.search(b’/bin/sh’)) system_plt elf.plt[‘system’] payload b’A’ * offset payload p64(pop_rdi) p64(binsh) payload p64(ret) # 某些系统下需要栈对齐 payload p64(system_plt) # 3. 发送payload p.sendline(payload) # 4. 交互 p.interactive()3.3 格式化字符串漏洞内存的“读与写”格式化字符串漏洞源于使用了用户可控的字符串作为printf、sprintf等函数的格式化参数。例如printf(user_input) 如果user_input是%p就会泄露栈上的数据如果是%n则可以向指定地址写入数据。利用方式泄露信息使用%p、%s等格式化符可以泄露出栈上的返回地址、libc地址、canary值等为后续利用做准备。任意地址写使用%n格式化符将目前已输出的字符数写入参数指向的地址或%hn写入2字节、%hhn写入1字节可以精确地向任意地址写入数据。通常用来覆盖GOT表项将某个函数的地址改为system的地址。实战技巧在构造格式化字符串payload时需要精确控制其在栈上的位置。通常使用类似%{offset}$p的方式来直接定位第几个参数。pwntools的fmtstr_payload函数可以自动化生成用于任意写的payload非常方便。3.4 堆漏洞复杂但强大的利用方式堆漏洞Use-After-Free, Double Free, Heap Overflow等是Pwn题中的难点也是区分选手水平的关键。它涉及对堆管理器如glibc的ptmalloc2内部结构的深刻理解。核心知识chunk结构了解malloc chunk的prev_size,size,fdforward pointer,bkbackward pointer字段。bins了解fastbin, smallbin, largebin, unsortedbin等不同链表的特性和操作。利用思路堆漏洞利用的目标往往是实现“任意地址写”或“控制流劫持”。常见技术包括Fastbin Attack通过Double Free或UAF构造一个指向目标地址如malloc_hook的fastbin chunk然后申请下来并写入数据从而修改关键函数指针。Unlink Attack利用堆溢出伪造一个chunk触发unlink操作时会执行FD-bk BK和BK-fd FD 从而实现任意地址写。Tcache Poisoning在较新版本的glibc中tcache机制使得利用更容易可以直接通过UAF修改tcache entry的next指针指向任意地址然后分配出来。学习建议堆利用的学习曲线很陡。建议从how2heapGitHub上的一个经典教程开始在关闭ASLR和特定保护的环境下逐个实验里面的例子并用gdb跟踪每一步堆块状态的变化。理解每一个操作对内存的实际影响比死记硬背利用链更重要。4. 环境搭建与调试磨刀不误砍柴工一个稳定、高效的调试环境能极大提升解题效率尤其是在处理复杂的Pwn题时。本地环境推荐使用Ubuntu虚拟机或WSL2。安装pwntools,gdb,pwndbg/gef,ROPgadget,one_gadget,patchelf等工具。libc版本问题这是最大的坑之一。题目提供的libc版本可能和你的系统不一致。解决方法使用patchelf修改二进制文件使其指向你下载的题目同版本libcpatchelf --set-interpreter /path/to/ld.so --set-rpath /path/to/libc_dir ./pwn在运行或调试时使用LD_PRELOAD环境变量指定libcLD_PRELOAD./libc.so.6 ./pwn远程调试如果漏洞只能在特定环境下触发如需要特定libc可以在服务器上运行socat或gdbserver进行远程调试。pwntools的gdb.attach()功能可以很方便地附加到本地进程并打开gdb。一个小技巧在写exp时可以在关键步骤前后加入pause()这样脚本会停住方便你手动用gdb attach上去查看内存状态确认利用链是否按预期执行。5. 解题思维与比赛策略从单题到全局最后聊聊Beyond具体技术的解题思维。面对一道新题尤其是像NewStarCTF这种只给分类不给描述的题目应该如何入手信息收集对于Crypto先看文件是文本还是二进制尝试各种编码对于Pwn先用checksec和file再扔进IDA快速浏览main函数和字符串表。动态分析运行程序输入一些测试数据观察输出和反应。对于交互题用nc命令手动连一下感受交互流程。模式识别根据经验判断题型。Crypto里长长的数字n和e大概率是RSAPwn里有菜单1. add, 2. delete...的很可能是堆题。识别题型能帮你快速调用对应的知识模块。利用已知工具不要重复造轮子。遇到RSA先想能不能用RsaCtfTool遇到格式化字符串先试试fmtstr_payload遇到堆题先回顾how2heap里的类似案例。分步验证利用链往往很长不要试图一次性写对完整的exp。先写一段代码验证是否能泄露地址再写一段验证是否能控制某个指针最后再串联起来。每一步都用print或调试器确认结果。团队协作与信息利用在比赛中如果卡住了可以看看题目是否有动态分值解出人数越多分值越低这间接反映了题目难度。也可以关注平台的公告或提示虽然正规比赛通常没有。团队内分工有人专攻Crypto有人专攻Pwn遇到难题及时讨论。回过头看“week3 crypto/pwn”它更像是一个阶段的标志。掌握这些基础知识和解题框架后你就有能力去挑战更复杂的复合型题目比如那些将Crypto算法嵌入到Pwn程序逻辑中需要你先逆向算法再破解密钥的题目。安全研究的乐趣正是在于这种抽丝剥茧、最终掌控系统的过程。每一次cat flag成功的瞬间都是对之前所有分析、尝试和失败的最好奖赏。
返回列表