thesp0nge OSCP guy. I break code and rebuild it with security in mind, taekwon-do, husband, dad. Chaotic good drow ranger. I blog @codiceinsicuro and @the_armoredcode.

Backflip into the stack

Backflip into the stack

During my OSCE journey I came across an interesting technique to jump backwards into the very beginning of the buffer injected on the vulnerable process.

The more reliable technique to jump back is to use an egghunter. You split your shellcode into stages: in the first stage you write an egghunter shellcode that searches into the memory for the second stage payload, that it is the code you want to executed prepended by your egg.

However, under some circumstances, you may want to execute a jump back into your shellcode.

This old but gold phrack article describes some very handy assembly code snippets when writing shellcode for Microsoft Windows.

Here you can find the idea about using FPU state saving instructions to have the EIP value to be written on the stack.

fnstenv [esp-12]
pop ecx
add cl, 10

FLDZ instruction pushes a 0 on the FPU register stack and the FNSTENV stores the FPU environment to the address given as parameter,

Executing a “fnstenv [esp]” instruction, the result on the stack is the following.

gdb-peda$ x/30x $esp
0xffffd600:	0x7f	0x03	0xff	0xff	0x00	0x38	0xff	0xff
0xffffd608:	0xff	0x7f	0xff	0xff	0x82	0x80	0x04	0x08
0xffffd610:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffd618:	0x00	0x00	0xff	0xff	0xe9	0xd7

If we want to align the information about the EIP (0x08048082 in my case) to be found at the very beginning of the stack, we kindly ask FNSTENV to start writing 12 bytes before the $ESP value, that’s the reason of “fnstenv [esp-12]”.

We than pop the stack word into ECX storing the value the EIP register has when fnstenv it was called. Then, I choose to add 9 bytes to move ECX value to the instruction right after the NOP.

In order to execute a jump, we decrement CH register (the most significant 8 bits of the CX register, the 16 bits representation of ECX. This will subtract 256 on the whole ECX value, that means this technique allow us to jump backwards in steps of 256 bytes.

fnstenv [esp-12]
pop ecx
add cl, 10
dec ch
dec ch
jmp ecx

See the code in action on gdb.

Today I added those two shellcodes in shellerate project.

def get_where_am_i_in_ecx():
    # fldz
    # fnstenv [esp-12]
    # pop ecx
    # add cl, 9
    return "\xd9\xee\xd9\x74\x24\xf4\x59\x80\xc1\x09"

# jumps is how many 256 bytes backword jump you want to take
def jmp_backwards_ecx(jumps=1):
    return get_where_am_i_in_ecx() + "\xfe\xcd" * jumps + "\xff\xe1"

Please note again that using egghunter is more reliable but it can take some time in order to loop into victim memory searching for the payload. Anyway, this technique can be used if you’re pretty sure about the fixed amount of space you can backward skip, e.g. it can be safetly used in a SEH overwrite exploitation.

Enjoy it!

(Updated: )

comments powered by Disqus