首先自己写了一个程序
就是两次read+put
read存在栈溢出,但是只够溢出到返回地址,所以使用栈溢出
此题开启了canary,首先要泄露canary和rbp上的栈上的地址
canary最低位地址上的值本来为0,但puts读到0就会停止,所以将canary最低位字节值不置为0,就能输出到rbp
此时已经使用了一次read和put
第二次read希望泄露libc的基址,但是溢出的位置不够用,所以进行栈迁移
通过gdb调试得到第二次read的位置,与得到的栈的地址得到偏移,得到第二次read的栈顶地址(为了找到后面leave的地址)
开始构造payload
payload就是将pop_rdi,puts的got,puts的plt填充,,main函数地址然后加上刚才泄露的canary和计算得到的栈顶地址,最后加上leave
所以程序执行到第二次read的时候,先将栈内填充我们构造好的payload,canary已经之前得到,rbp覆盖为计算的这次read的栈顶地址-8(后面说原因),返回地址修改为leave(leave地址使用ropper程序得到)
read完程序首先执行read中的leave,leave=mov rsp,rbp;pop rbp
此时rsp指向我们填充的leave,rbp由于是我们构造好的所以指向read栈顶-8
leave完ret,ret=pop rip,所以执行的是我们填充的leave,所以rsp指向read栈顶-8,再pop rbp,所以此时rsp正好指向read的栈顶
然后就执行之前填充的payload,即pop rdi ;call puts
这就得到了puts的地址
通过LibcSearcher就可以得到libc的基址
然后就可以得到system地址和/bin/sh的地址
第二次read的返回地址是main,所以程序从头再次执行
通过gdb调试得到read的栈顶地址,通过与泄露的地址计算偏移,构造payload即可(方法同上面的泄露puts,依然是栈迁移)
然后就得到了shell
总结:也没什么好说的,就是python3下的pwntools太难用了,发现自己不适合pwn,之后可能大部分精力放在深度学习上了