简体   繁体   中英

Why my shellcode does not work (in Linux)?

I wrote a small shellcode below:

#include <stdlib.h>

int main()
{
    __asm__("jmp calloffset\n"
        "poploffset: popl %%esi\n"
        "movl $1,%%eax\n"
        "movl $6,%%ebx\n"
        "int $0x80\n"
        "calloffset: call poploffset\n"
        ".string \"/bin/bash\"\n":::"esi");

    exit(1);
}

When the shellcode work, it will return 6. Actually, the code above works well, main function return 6 indeed.

And then I embed the code into a C program:

#include <stdlib.h>
#include <unistd.h>

char shellcode[]="\xeb\x0d\x5e\xb8\x01\x00\x00\x00\xbb\x06\x00\x00\x00\xcd\x80\xe8\xee\xff\xff\xff";

void func()
{
    int * ret;
    ret=(int *)&ret+0x08;
    *ret=(int *)shellcode;

}

int main()
{
    func();
    exit(0);
}

Under normal circumstances, the code should return 6. But it return 0 all the time.

I don't think my code is wrong. I will show you that.

First, I get the address of val ret from gdb:

(gdb) print &ret
$1 = (int **) 0xbffff2f4

And I get the address of the next instruction of call in main:

(gdb) disass main
Dump of assembler code for function main:
   0x08048ccb <+0>: push   %ebp
   0x08048ccc <+1>: mov    %esp,%ebp
   0x08048cce <+3>: and    $0xfffffff0,%esp
   0x08048cd1 <+6>: sub    $0x10,%esp
   0x08048cd4 <+9>: call   0x8048cb0 <func>
   0x08048cd9 <+14>:    movl   $0x0,(%esp)
   0x08048ce0 <+21>:    call   0x80495c0 <exit>
End of assembler dump.

Obviously, it is 0x08048cd9.

And then, I get the address which store the address above in the stack:

(gdb) x/16xw $esp
0xbffff2e8: 0xbffff3bc  0x00000001  0x00000000  0x08049460
0xbffff2f8: 0xbffff318  0x08048cd9  0x0804972f  0x080d6044
0xbffff308: 0x08049797  0x00000000  0x08049460  0x080493c0
0xbffff318: 0x00000000  0x08048e91  0x00000001  0xbffff3b4

Obviously, the address is 0xbffff2f8+0x04=0xbffff2fc. And the address of val ret is 0xbffff2f4.

So, ret=(int *)&ret+0x08 should get the right address. And *ret=(int *)shellcode should insert the address of the shellcode into the stack. And then the program runs into the shellcode, and finally I get 6 when the program return.

Am I wrong?

I seem to find the wrong place:

(gdb) disass func
Dump of assembler code for function func:
   0x08048cb0 <+0>: push   %ebp
   0x08048cb1 <+1>: mov    %esp,%ebp
   0x08048cb3 <+3>: sub    $0x28,%esp
   0x08048cb6 <+6>: lea    -0xc(%ebp),%eax
   0x08048cb9 <+9>: add    $0x20,%eax
   0x08048cbc <+12>:    mov    %eax,-0xc(%ebp)
   0x08048cbf <+15>:    mov    -0xc(%ebp),%eax
   0x08048cc2 <+18>:    mov    $0x80d6028,%edx
   0x08048cc7 <+23>:    mov    %edx,(%eax)
   0x08048cc9 <+25>:    movl   $0x1,(%esp)
   0x08048cd0 <+32>:    call   0x8053380 <sleep>
   0x08048cd5 <+37>:    leave  
   0x08048cd6 <+38>:    ret    
End of assembler dump.

The instruction add $0x20,%eax is strange. How can this happen?

The compiler is free to put the "ret" variable anywhere in the stack frame of func() that it wants. Presumably (I'm too lazy to work out the math from the disassembly) your offset of 8 is simply wrong. Note that there is a 40 byte frame being set up.

The instruction add $0x20,%eax is strange. How can this happen?

int * ret;
ret=(int *)&ret+0x08;

That's how C pointer math works - this addition changes ret by 0x08 * sizeof(int) bytes. That's where 0x20 comes from. But Andy Ross's observation is correct, the compiler is free to arrange the stack frame how it wants, so any recompilation, especially with different compiler settings, can modify the frame layout.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM