一、ROP中的gadget:
首先什么是gadget呢?gadget在英文中意为小配件,在构造ROP链时,主要是指一对pop|ret指令,其功能在于可以配置一个寄存器的值,并返回至指定地址。常常用来在64位pwn的寄存器传参中构造寄存器值,而ret可打到劫持目标函数的位置,也可以打到下一个gadget;
给出搜索gadget的pwntools命令:ROPgadget --binary ./pwnme --only "pop|ret"
二、代码复用:__libc_csu_init函数区
这个函数在尾部位置有一系列pop操作,并带有一个ret,倒数第二个标签区域中有一系列寄存器拷贝操作,源寄存器就是尾部pop寄存器,可以为更多的寄存器设置值,解决gadget不足情况,并带有一个可控的call,可以实现控制流劫持;我们不妨把尾部那块区域称为x区,倒数第二个标签域称为z区;
不要通过二次回归x区来实现劫持,因为call的目标未经设置会导致段错误!
那么二次回归x区后的ret的作用是什么呢?注意我们是通过z区的call劫持,call调用过程结束后会继续执行,最终会回归到x区,如果需要后续执行流,则可以利用这个ret;
注意,如果用z区中的call劫持控制流时,除了会先执行一个push外会有一个严重的问题,我们看汇编:
也就是说,目标addr值不是r12+rbx*8,而是存在r12+rbx*8处的值,如果要成功劫持,必须事先在对应地址处写进一个目标地址(例如用read函数写、或者能泄露可控栈地址和got表地址);
我们尝试给出对应通用exp的函数:
rdi = add ; rsi = len ;rdx = prot
edx ,rsi,edi
def rop_csu(dx,si,di,toZ,addr_got,addr,bx):
csuret=p64(bx)+p64(bx+1)+p64(addr_got-bx*8)+p64(dx)+p64(si)+p64(di)+p64(toZ)+'A'*56+p64(addr)
return csuret