使用ida查看程序,首先保存esp和_exit地址,随后将输出的字符串压栈:
| 1 | push esp | 
随后执行输入函数:
| 1 | xor ebx, ebx ; fd | 
由于ecx在之前已经被赋值为esp,所以put函数仍是对同一个变量(输出的字符串)进行输入。使用gdb-peda的checksec查看,虽然显示NX: enable,但是通过vmmap执行,发现栈是可执行的。使用pattern create和pattern offset获取偏移量为20。因此构造的payload结构如下:
| 1 | 'a' * 20 + [ret addr] + getshell | 
因为要获取栈的地址来达到ret2shellcode的目的,所以需要通过write泄漏栈地址。在程序运行的开始,执行了:
| 1 | push esp | 
在put函数后,执行:
| 1 | add esp, 14h | 
使得字符串参数、_exit被移出栈、pop,栈顶从而变为之前储存的esp。因此在第一个put函数执行时,输入:
| 1 | 'a' * 20 + 0x8048087 | 
便可以打印出esp的地址。获取esp的地址后,将会继续再次执行put函数(此时ecx仍为字符串参数的地址),此时输入:
| 1 | 'a' * 20 + [ret addr] + getshell | 
即可。需要注意shellcode长度以满足输入的条件(3Ch)。