尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
checksec全面解析:PWN题第一步,读懂ELF安全防护与利用策略
做PWN题拿到一个二进制文件第一步你会做什么很多人习惯直接丢进IDA按F5看伪代码但我的习惯是先跑一遍checksec。这个工具两三秒钟输出的一堆字段直接决定了这道题是开胃菜还是硬骨头。checksec是检查ELF可执行文件安全特性的脚本在CTF和二进制安全研究里几乎是标配。今天这篇文章我就把最新版checksec的安装、常用姿势以及我平时怎么根据它的输出决定解题思路一次性讲清楚。适合刚入门PWN的选手也适合那些一直抱着旧脚本没升级的朋友。1. 认识checksecPWN入门必须搞懂的第一道门槛1.1 checksec到底在查什么checksec的名字由check和security组成干的活就是检查一个Linux可执行文件开启了哪些安全缓解机制。现代Linux编译器和内核默认会开启不少防护比如栈保护、地址随机化、只读重定位表等。这些机制本意是提高系统安全性但在CTF的约定规则下题目二进制会刻意关闭或保留某些防护用来控制题目难度逼迫选手掌握对应的绕过技巧。所以我常说checksec不是用来“看”的而是用来“定策略”的。它告诉你的不是“这个文件能不能打”而是“这道题应该往哪个方向想”。比如栈上有没有Canary决定了你是直接溢出还是需要先泄露随机值PIE开没开决定了你的ROP链里的地址能不能写死RELRO是不是Full决定了GOT表能不能被改写。这些信息在PWN解题前就必须明确而不是等你把exp写卡壳才回头查。对刚入门的朋友来说checksec的另一个价值在于帮你建立“防护意识”。当你看到NX开启时就会下意识想到栈不可执行shellcode不能直接放在栈上跑看到Canary存在时就会提醒自己注意信息泄露的利用点。久而久之你对编译选项和二进制内部结构的理解会越来越深而不只是会背“有canary就绕过”这句话。1.2 看懂输出字段RELRO、Canary、NX、PIE与FORTIFY一个典型的checksec输出长这样我以Ubuntu 22.04上自带的/bin/ls为例$ checksec --file/bin/ls RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE Full RELRO Canary found NX enabled PIE enabled No RPATH No RUNPATH 75) Symbols Yes 5 17 /bin/ls这一行看似密集其实每一项都有明确指向。RELRO全称Relocation Read-Only控制程序的重定位表是否只读。Partial RELRO意味着GOT表前半部分只读但GOT.plt仍可写这是比较常见的情况可以利用GOT覆写来劫持控制流。Full RELRO则把整个GOT都设为只读代价是程序启动时会做一次完整重定位性能略降但攻击面小很多。做PWN题遇到Full RELRO就要尽早放弃改GOT的想法把注意力转向堆管理、钩子函数或者FSOP这类路径。STACK CANARY即栈保护值。程序在函数的栈帧中放入一个随机值函数返回前检查它是否被改写。Canary found意味着栈溢出后直接覆盖返回地址的做法会被立刻发现。绕过思路通常是先通过格式化字符串、越界读等漏洞把Canary值泄出来然后在溢出payload里原样填回。NXNo-eXecute把栈和堆标记为不可执行。NX enabled时栈上的shellcode无法直接执行必须转为ROP、ret2libc、SROP等基于代码复用的思路。如果NX disabled同时题目又给了可写可执行的内存段那直接布置shellcode往往是最快的路径很多新手入门的栈题就是这种配置。PIEPosition Independent Executable地址随机化。PIE enabled表示程序每次加载的基址都不同代码段、数据段里所有固定的绝对地址都不能在exp里写死。没有PIE时函数地址、GOT地址都是固定的ROP链构造起来会轻松太多。现代Ubuntu默认全开PIE所以CTF里不少老题反而成了“练习固定地址利用”的经典素材。RPATH/RUNPATH动态库搜索路径。正常发行版的二进制基本都是No RPATH、No RUNPATH如果出现RPATH说明程序会优先从某个固定路径加载动态库这种场景在CTF里偶尔会结合“伪造同目录libc”来考。Symbols符号信息数量。保留符号意味着IDA里能看到函数名调试起来非常舒服。strip过的程序符号很少需要靠字符串交叉引用和函数签名去猜。FORTIFYFORTIFY_SOURCE编译加固。开启后编译器会对strcpy、sprintf这类危险函数插入边界检查代码部分溢出利用会失效。这项在CTF里不算最常见的考点但输出里有Fortified和Fortifiable两组数字时值得留意哪些函数被加固了。字段本身不难记难的是拿到结果后能快速形成判断。我的建议是不要死记硬背而是每做一道题都先跑checksec再打开IDA对照着看。看多了这些字段自然就长在脑子里了。2. 装对版本源码安装最新checksec的全流程2.1 为什么不用apt里的旧版很多人在Kali或者Ubuntu上直接apt install checksec装完也能跑但这里有个坑Linux发行版仓库里的checksec通常停留在很老的版本有的还停留在2015年前后的状态。老版本缺少对FORTIFY_SOURCE的检测不支持JSON输出对新版内核的安全特性也识别不全甚至在遇到部分新版编译器生成的ELF时会出现解析错误。更麻烦的是有些发行版会把checksec作为pwntools的依赖一起装进来但那个版本同样可能偏老。如果你刚接触PWN照着老博客的命令操作大概率不会报错但输出的内容和新版有细微差异等你把脚本写进自动化工具链时差异就会被放大。所以我一直建议要么直接用最新源码编译要么至少定期从项目仓库拉一次最新脚本。checksec本质上只是一个脚本更新成本极低没必要在工具版本上拖后腿。2.2 环境准备与依赖checksec.sh本身是bash脚本运行时依赖readelf、objdump、file、grep等命令。readelf和objdump属于binutilsfile是独立的file命令。绝大多数Linux发行版默认都带但精简容器里可能没有建议提前确认一下。# Debian/Ubuntu系 sudo apt update sudo apt install -y binutils file # CentOS/RHEL系 sudo yum install -y binutils file另外checksec需要bash 4及以上版本。macOS自带的bash一般都在3.2左右直接用脚本容易报语法不支持所以如果你是mac用户建议装完bash再指定/usr/local/bin/bash checksec.sh来执行或者直接在Linux容器里跑。这个细节很多教程都没提但实际使用时一旦碰上排查起来很浪费时间。如果你打算用--fortify-file之类的功能最好还装上对应架构的交叉编译工具链。毕竟CTF里经常出现arm、mips架构的题目本地没有对应binutils时checksec会报找不到readelf。2.3 从源码拉取并安装最新版checksec维护在GitHub仓库slimm609/checksec.sh中。安装方式很简单把checksec.sh这个单文件下载下来放到PATH目录即可。# 方式一完整克隆仓库 git clone https://github.com/slimm609/checksec.sh.git cd checksec.sh sudo cp checksec.sh /usr/local/bin/checksec sudo chmod x /usr/local/bin/checksec # 方式二直接下载单文件 wget https://raw.githubusercontent.com/slimm609/checksec.sh/main/checksec.sh sudo install -m 755 checksec.sh /usr/local/bin/checksec这里我把脚本改名为checksec去掉了.sh后缀。这样在命令行里敲起来更顺手而且新版脚本对执行路径没有特殊依赖整个文件可以直接拷贝。安装完成后验证版本checksec --help正常会输出一长串使用说明包含--file、--dir、--proc、--kernel、--output等参数。如果你看到的是很早以前的短帮助说明装的还是旧版。顺便说一句直接checksec --version在新版里也能看到版本号和构建信息可以用来快速确认。在Docker容器里做PWN题的朋友也注意基础镜像如果用了python:3.x-slim这类精简镜像读ELF可能缺file命令拉完脚本记得顺手apt install file。这是我在动态容器题目环境里踩过的真实问题后面专门展开讲。3. 实战用法命令行与Python调用的两套玩法3.1 命令行高频参数速览checksec的命令行参数不少但日常PWN解题真正高频的并不多。我按使用频率列一下参数作用实际场景--file路径检查单个ELF文件拿到题目文件后第一件事-f 路径同上短参数写法同上--dir目录批量检查目录下所有ELF分析固件、批量扫附件--procPID检查指定进程调试中确认运行态防护--proc-all检查所有进程系统排查、验收环境--kernel检查内核防护题目涉及内核或模块时--outputjsonJSON格式输出写自动化脚本时集成--fortify-file路径检查FORTIFY加固细节确认哪些函数被加固单个ELF最常用checksec --file./pwn批量检查一个目录里的所有文件checksec --dir./attachments/在调试器中确认当前进程的防护状态避免本地和远程环境不一致checksec --proc$(pidof pwn)写自动化批量测试脚本时JSON输出比纯文本好解析得多checksec --file./pwn --outputjson输出大概是这样的结构{ file: { relro: full, canary: true, nx: true, pie: true, rpath: false, runpath: false, symbols: true, fortify_source: false, fortified: 0, fortifiable: 5 } }拿到JSON后你就可以在exp构建脚本里根据防护字段自动选择利用模板。比如检测到canary为true就自动附加一个“先泄露canary”的流程注释或者检测到PIE开启时自动想办法从某个输出点读取地址。这些自动化虽然不能替代人工分析但在批量复现多个题目场景时很省事。3.2 在pwntools里调用checksec做PWN题绕不开pwntoolspwntools自身也封装了checksec功能有两种常见用法。第一种是直接查看已加载ELF的防护信息from pwn import * elf ELF(./pwn) print(elf.checksec())这种方式返回一个有序字典形式类似Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled第二种是读取checksec的原始文本输出from pwn import * print(checksec(./pwn))这两种写法的区别在于elf.checksec()解析的是pwntools内部通过readelf解析的结果而checksec()函数会实际调用系统命令。我平时更推荐前者因为它不依赖外部脚本在隔绝环境下也能稳定运行。但如果你已经把checksec.sh更新到最新版checksec()函数会直接调用新版脚本能拿到比pwntools内置解析更完整的FORTIFY字段。一个很实用的组合是在exp开头先打印防护状态验证自己拿到的文件和出题人预期一致。很多动态容器题目每次连接分配的实例可能不同先确认再打能省掉很多“为什么本地能通远程不行”的排查时间。from pwn import * context.arch amd64 elf ELF(./pwn) # 开局确认防护 sec elf.checksec() log.info(fRELRO: {sec[RELRO]}) log.info(fCanary: {sec[canary]}) log.info(fNX: {sec[nx]}) log.info(fPIE: {sec[pie]}) # 后续利用流程 ...3.3 动态容器题目的使用习惯现在很多CTF平台提供动态容器题目给你一个ip:port背后是出题人用Docker部署的靶机实例。和本地文件不同远程实例的防护状态和libc版本不一定和附件里完全一致。这时候checksec反而要“反着用”。我第一次打动态容器题时天真地以为远程环境就是本地附件编译生的。结果exp本地全通远程一打就崩。后来才明白很多动态容器都是套了一个标准模板libc版本、ASLR开关甚至编译选项都可能不同。所以拿到远程地址后我养成了一个习惯先连上去通过程序的输出判断远程环境和本地附件的差异同时用checksec确认本地基础版本再决定要不要更换libc或者调整地址。举一个具体场景题目给了libc-2.31.so本地系统是glibc 2.35。你用本地系统跑expputsgot指向的偏移和2.31完全不同。这时必须先checksec --file./pwn确认防护再用pwninit或patchelf把题目程序的解释器和libc替换成本地可复现的版本。替换完再次checksec --file./pwn确认替换后RELRO、NX、PIE这些关键属性没变才开始调试。这个流程虽简单却能规避掉动态容器环境里最让人头大的“环境不一致”问题。另外动态容器的远程端口一般只对特定题型开放连接后可能有时间限制。建议所有需要人工确认的信息都在本地确认完远程只做最终验证。checksec这种耗时极短的命令放本地跑别浪费远程连接时间。4. 看懂结果才能上手checksec输出与PWN利用策略4.1 常见防护组合对应的利用节奏checksec输出是一张“体检报告”真正的价值在于指导解题方向。我整理了CTF里最常见的几种组合和对应的思考路径供参考。组合一Canary found NX enabled PIE enabled Full RELRO这是现代Linux默认配置也是中等以上栈题的常见环境。这个组合下直接栈溢出覆盖返回地址的行不通因为Canary会拦ROP的地址没法写死因为PIE开启程序基址随机GOT不能改因为Full RELRO。所以这类题的核心突破口几乎都在“泄露”上先通过漏洞读出Canary再通过格式化字符串或栈迁移读出程序基址最后用one_gadget或ROP完成利用。整体节奏是“泄露-计算-构造-发送”一步都不能跳。组合二No canary NX enabled No PIE Partial RELRO这是入门栈溢出的经典设置。没有Canary栈溢出可以直接覆盖返回地址没有PIE函数地址固定可以直接构造ROP链Partial RELRO下GOT可写还能退回到GOT覆写或者ret2dlresolve。如果你刚入门遇到这种题目应该感到幸运它是练习ret2text、ret2syscall、ret2libc的最好素材。组合三Canary found NX disabled No PIENX关闭意味着栈可执行如果同时能拿到Canary或者题目有现成的信息泄露就可以在栈上布置shellcode。这个组合比较少见但出现时往往意味着出题人想考“栈迁移shellcode”的思路。组合四Static No PIE No canary完全静态编译的题目近期在各类CTF里出现频率不低。没有动态库可以泄露但也不需要泄露因为系统调用号固定syscall地址固定常用gadget都在程序里。checksec输出里如果看到No PIE、No canary同时文件大小又很大大概率是静态链接可以直接用ROPgadget搜gadget构造execve(/bin/sh, 0, 0)。组合五FORTIFY开启时的陷阱遇到FORTIFY为Yes时strcpy、sprintf这类函数会变成带边界检查的版本。如果你还在用老套的strcpy溢出会发现payload发出去程序直接abort。这时候要么找不受FORTIFY影响的函数比如read、memcpy要么考虑堆漏洞路径。checksec能提前暴露这个问题避免你在调试器里怀疑人生。4.2 从ctfshow pwn 074这类题目看实战我以ctfshow平台里比较有代表性的栈溢出题型来举例比如pwn 074这一类偏入门到进阶过渡的题目。这类题通常给出一个编译好的可执行文件保护设置有一定迷惑性不是全开也不全关需要选手自己判断。假设你拿到题目第一步file pwn checksec --file./pwnfile告诉你架构和链接方式checksec告诉你防护。假设输出是RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE Partial RELRO Canary found NX enabled No PIE No RPATH No RUNPATH 83) Symbols No 0 3 ./pwn这个组合下PIE没开函数地址是固定的GOT可写但Canary和NX都开着。这意味着你不能直接栈溢出打ret地址必须先想办法泄露Canary。通常题目会在某个地方提供一个漏洞函数可能是格式化字符串也可能是一次越界读。拿到Canary之后因为No PIE你可以放心地构造ROP链调用putsplt泄露libc地址再回到main进行第二轮控制最后执行system(/bin/sh)。整个流程用checksec串起来就是Canary提示你要先做信息泄露No PIE提示你可以放心使用固定地址的ROPPartial RELRO提示如果中途卡住还能考虑GOT覆写作为备选方案。一个工具的输出直接串起了整道题的解题链。再说动态容器场景。这类题目在远程跑起来后你连上靶机发送payload程序返回结果。远程系统的libc版本可能和本地不一致所以泄露libc地址后建议直接用LibcSearcher或one_gadget适配远程环境。同时检查远程返回的地址是否低于0x7fffffffffff判断ASLR是否生效。如果远程关闭了ASLR很多地址可以直接爆破那就根本不用走泄露流程直接构造ROP。4.3 多文件与libc判断PWN题除了单个可执行文件经常还会附赠一个libc.so。这时候checksec的价值体现在两个地方。一是确认目标程序使用哪个解释器。通过file可以看到动态链接器路径file ./pwn如果显示interpreter /lib64/ld-linux-x86-64.so.2而附件里有专门给的libc你就需要用patchelf --set-interpreter和patchelf --set-rpath把本地复现环境切到目标libc。二是确认libc自身的安全属性不过更准确地说libc的RELRO、NX等通常跟着系统走你在调试时更需要注意的是libc的版本和符号偏移。checksec在这里更像一个辅助确认工具。我自己的习惯是打完libc地址后优先用LibcSearcher或者libc-database匹配偏移然后回头用checksec输出里的RUNPATH字段确认程序是不是真的会加载附件里的libc。这个细节很多人忽略。如果程序全局RUNPATH指定了某个目录动态链接器会优先从那里加载libc而不是系统默认路径。这时你泄露出来的libc地址可能属于附件libc而你在本地复现用的却是系统libc地址当然对不上。先看checksec的输出能少走很多弯路。5. 踩坑记录与常见问题速查5.1 安装与执行报错问题一command not found脚本明明下载了执行checksec --file./pwn却说找不到命令。大概率是PATH里没有/usr/local/bin或者文件没有可执行权限。先确认ls -l /usr/local/bin/checksec which checksec如果没有执行权限补上chmod x即可。问题二bash版本过低在新版脚本里用到了关联数组和部分新特性bash 3.x会报错。Linux发行版一般没问题macOS用户尤其容易踩这个坑。最简单的办法是在Linux容器里运行或者安装新版bash后调整shebang行。问题三readelf not found精简镜像或最小化安装的系统里没有binutils。装一下就好sudo apt install binutils问题四Python环境里调用checksec()抛异常pwntools的checksec()函数依赖外部脚本如果你更新了checksec.sh但没放对路径或者新旧版本输出格式不兼容就会报解析错误。建议更新后先手动跑一遍checksec --file/bin/ls确认输出正常再用pwntools调用。5.2 识别失败与误报问题一非本机架构的文件识别失败本地是x86_64但题目是arm或mips的ELFchecksec会尝试调用对应架构的readelf如果没有安装交叉工具链就会报错或用错误的方式解析。解决办法是安装对应架构的binutils。Debian系sudo apt install binutils-arm-linux-gnueabihf binutils-mips-linux-gnu问题二静态编译的CANARY误报有些静态编译的二进制会包含Canary相关的符号和代码checksec可能认为开启了Canary但实际栈保护逻辑并没有生效或者只影响部分函数。看到输出后要结合逆向分析确认不能全信工具。问题三strip后的符号信息不准确Symbols字段显示的数字只能说明符号表的多少不代表程序复杂度。完全strip的二进制符号数可能为0但功能依然很复杂。不要因为Symbols少就轻视题目难度。5.3 新旧版本差异与确认旧版checksec无法显示FORTIFY信息JSON输出也没那么丰富。如果你在自动化脚本里依赖--outputjson先确认脚本版本支持。新版还增加了对Linux内核配置的检测checksec --kernel在分析内核题目时很有用。另外pwntools内置的checksec()和独立最新脚本在字段命名上略有出入。比如独立脚本输出Canary found而pwntools的字典键是canary布尔值为True。写脚本时要注意键名差异别照抄一个就用在另一个环境里。我在实际使用中还有一个体会checksec不只是在解题开头有用在打完exp做验证时也很有价值。比如你构造了一个ROP链但远程始终打不通回头用checksec --file./pwn确认一下题目有没有改动、远程是不是换成了更严格的防护往往能快速定位问题。工具虽小却贯穿了PWN题从分析、调试到验证的全流程。建议所有做PWN的朋友都把这个习惯刻进日常流程里。
RELATED

相关推荐

CCF推荐目录解读:计算机视觉与图像处理会议选择指南

CCF推荐目录解读:计算机视觉与图像处理会议选择指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/2 1:05:05
从显存爆炸到流畅重建:Voxel Hashing如何重构TSDF体素存储

从显存爆炸到流畅重建:Voxel Hashing如何重构TSDF体素存储

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/2 1:05:05
通用型直启盘光纤中继模块:远距离抗干扰控制方案详解

通用型直启盘光纤中继模块:远距离抗干扰控制方案详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/2 1:05:05
MORE NEWS

更多资讯

📰

从零配置IDE中的Git:环境准备、SSH认证与高频报错排查全指南

从命令行到图形界面,Git 在 IDE 里的配置其实没你想的那么玄乎。大部分开发者日常工作都离不开 IDE,而 Git 早就成了 IDE 的标配能力,无论是 IntelliJ IDEA、VS Code,还是 Eclipse、Android Studio,开箱就带 Git 集成。…

📰

Django在线考试系统:500并发+自动阅卷+防切屏实战部署指南

简介:这是一套基于Python Django框架开发的在线考试系统完整源码,面向高校教师、课程开发者及Web全栈学习者,专为《Python程序设计》等编程类课程提供可部署的自动化测评解决方案。系统采用Django后端Vue前端架构,覆盖用户注册登录…

📰

VMware虚拟机安装RHEL9并配置SSH远程连接实战指南

咱们今天聊的这件事,标题写着“简单练习1”,但真上手你会明白:从VMware里创建一台虚拟机,到把RHEL9装好,再让SSH连得通,中间能踩的坑一点不比上生产环境少。我自己带过不少新人,经常看他们卡在“…

📰

CH592低功耗BLE SoC选型与设计:从硬件集成到续航优化

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

PIM组播协议详解:从DM/SM模式到RPF检查与故障排查

1. 先搞清楚:PIM到底是干嘛的协议做网络的人应该都有这种经历:一套视频点播系统、一个交易所行情分发网络,或者某个证券报盘组播源,明明单播一切正常,换成组播就开始出现"部分终端收不到流""时断时续&q…

📰

Python机器学习实战:加密流量恶意行为检测平台

简介:本资源为基于Python机器学习的加密恶意流量分析与检测平台完整项目包,面向计算机、自动化等专业学生及安全方向从业者,可用于毕业设计、课程大作业或期末课程设计,帮助解决加密恶意流量识别与监测的实践问题。包内共134个文件…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬