// 红队渗透 · 2024-12-25

从非交互式 Shell 到全交互式 tty:反弹 Shell 终端升级全攻略

一、背景介绍

在渗透测试实战中,我们经常通过漏洞利用(如远程命令注入、反弹 Shell 等)拿到目标系统的初始权限。然而,通过 Netcat、命令重定向或 Web Shell 获取的 Shell,往往是功能十分受限的“非交互式 Shell”。这样的 Shell 通常存在以下局限:

  • 无法进行实时交互操作,只能执行单条命令,输入后无法回显或中途修改命令内容;
  • 命令补全和历史记录不可用,例如无法使用 Tab 自动补全或方向键翻阅历史;
  • 无法运行需要完整终端支持的工具(如 vim、top、less、passwd 等),因为这些工具依赖于 TTY;
  • 控制信号(如 Ctrl+C、Ctrl+Z 等)无效,无法中断或挂起当前进程;
  • sudo 和 su 等命令可能无法正常输入密码,因非终端环境而失败。

这些限制直接影响渗透测试效率。例如提权测试时需要运行交互式脚本、数据收集需要运行复杂命令、横向移动过程中需要使用终端工具等,都可能因 Shell 限制受阻。为此,我们需要逐步将 Shell 升级为功能更完善的“半交互式 Shell”或“全交互式 Shell”。


二、Shell 类型详解与对比

下面以表格形式对三类 Shell 类型的特性进行比较:

Shell 类型 是否绑定 TTY/PTY 快捷键支持 颜色 & 高亮 运行复杂命令 使用场景示例
非交互式 Shell 否 否 否 高失败率 netcat 反弹 Shell、 wget pipe 等
半交互式 Shell 有(部分模拟) 部分可用(方向键等) 无(或有限) 基本可用,但缺 readline python spawn、script 包装后的 Shell
全交互式 Shell 是(完整 PTY) 完全支持(Ctrl+/Tab) 有(取决配置) 完全支持 完整模拟 SSH 登录环境

非交互式 Shell(Non‑interactive Shell)

非交互式 Shell 是指不绑定终端设备(TTY/PTY)的 Shell,会话通过 stdin/stdout 重定向或管道接入。其特点包括:

  • 无法接收控制字符(如 Ctrl+C);
  • 无历史命令记录能力;
  • 无命令自动补全、无色彩高亮;
  • 无法运行依赖终端支持的命令或工具;
  • 在命令输入时无法中途停止或编辑。

这种 Shell 非常适合一次性命令执行,例如文件下载、脚本执行,但如果用于后续渗透或提权,就显得十分笨拙。

半交互式 Shell

半交互式 Shell 是通过模拟或挂载伪终端(PTY)后得到的一种中间状态。虽然尚不完善,但大幅改善了体验:

  • 支持基本的方向键历史浏览、Tab补全等;
  • 支持部分快捷键,但 Ctrl+C 或 Ctrl+Z 的信号可能没有完整支持;
  • 可以运行大部分简单工具,但仍无法顺畅运行 vim、top 等依赖完整 TTY 的程序;
  • 在稳定性和可操作性上较非交互式 Shell 显著提升。

半交互式 Shell 是多数渗透测试人员在拿到初始 Shell 后的首选升级方式,常用方法如使用 python pty.spawn、script 工具等。

全交互式 Shell(Fully interactive)

这是完全模拟本地终端环境的 Shell 类型,与 SSH 登录极为相似。特点包括:

  • 完整绑定 PTY,支持控制信号和原始终端行为;
  • 支持命令历史、自动补全、颜色显示等高级功能;
  • 能运行所有依赖 TTY 的命令和程序;
  • 用户界面接近本地终端操作体验,执行效率高,操作舒适。

全交互式 Shell 是进行复杂命令执行、持续操作、脚本运行、提权和数据交互时的理想环境。


三、概念澄清:为什么 bash -i 并不等价于交互式终端

经常有人尝试直接使用 bash -i(带 -i 参数的 bash,即交互模式)来升级 Shell,却发现依然不能使用 Tab 补全或方向键。这背后的原因是:

  • bash -i 可以让 Shell 进入“交互模式”,但若其背后没有绑定 PTY,仍然只是通过 stdin/stdout 与网络连接或重定向通信。
  • bash -i 并不会创建伪终端设备,也不会加载终端属性(如 raw 模式、多字节支持等)。
  • 在这种环境下,尽管屏幕看似可输入命令,但仍然没有真正的终端功能支持(诸如 job control、信号处理中断等)。

简而言之,bash -i 只是将 Shell 切换到交互模式,但如果没有分配 PTY,实际效果仍与非交互式 Shell 相似。


四、创建半交互式 Shell:分配伪终端(PTY)

方法一:使用 Python 的 pty 模块

这是最常用且兼容广的方式。命令如下:

python3 -c 'import pty; pty.spawn("/bin/bash")'

在 Python 中,pty.spawn() 会自动创建一对虚拟终端设备(master 和 slave),并在 slave 一侧启动新的 /bin/bash 进程。用户对 master 端发送输入,bash 从 slave 端读取输入并输出,最终在 master 端显示交互界面。这个过程模拟了标准终端的行为,从而提供基础交互能力。

注意事项:

  • 若目标环境仅安装 Python 2,可改为 python2 -c 'import pty; pty.spawn("/bin/bash")';
  • 在某些系统中可能需要使用 /usr/bin/python、/usr/bin/python3 等完整路径;
  • 有时还需先执行 export SHELL=/bin/bash 再运行 pty.spawn,以确保环境变量正确;
  • 尽管这种方式能够支持命令输入和输出,但在历史记录和补全体验方面可能仍有限。

方法二:使用 script 命令

script -qc /bin/bash /dev/null

script 本身主要用于记录终端会话,但是提供如下便利:

  • -q 参数表示静默模式,避免输出 session 开始/结束提示;
  • -c /bin/bash 表示执行 bash;
  • /dev/null 用来丢弃自动创建的记录文件。

执行后,会话将被绑定到一个伪终端。效果与 Python 方法类似,但兼容性更强,对于老旧 Linux 发行版或没有 Python 的环境尤为有效。

方法三:使用 socat 工具(高级用法)

socat PTY,link=/tmp/pty0,raw,echo=0 EXEC:"/bin/bash"

分析如下:

  • PTY,link=/tmp/pty0:在客户端创建一个伪终端设备 /tmp/pty0;
  • raw,echo=0:设置原始模式、关闭回显,优化输入体验;
  • EXEC:"/bin/bash":启动 bash 并将其关联至伪终端 slave 端。

此方法适用于需要将终端设备挂载至特定路径,或构建复杂中转机制的场景。socat 本身功能强大,还能绑定 TCP、UNIX socket、串口等多种通道。


五、升级为全交互式 Shell:终端属性设置与环境优化

获取半交互式 Shell 后,还需一系列后续步骤,使终端行为尽可能接近用户本地终端。这些步骤包括挂起当前 shell、修改 stty 设置、恢复终端控制、重置环境变量等。

具体操作流程如下:

1. 获取半交互式 Shell

使用上述 Python、script 或 socat 方法之一获取基础交互环境。

2. 挂起当前 Shell

在客户端本地按 Ctrl + Z,暂时挂起当前 Shell,释放终端控制权。

3. 修改本地终端设置并恢复 Shell

执行:

stty raw -echo; fg

作用:

  • stty raw:将终端设置为原始模式,输入字符直接发送,不进行本地处理;
  • stty -echo:关闭输入回显,避免输入字符重复出现;
  • fg:将挂起的 shell 恢复到前台,并重新绑定到优化后的终端控制环境。

4. 重置终端并配置环境

reset
export TERM=xterm-256color
export SHELL=/bin/bash
source /etc/skel/.bashrc  # 如果目标用户存在默认 bashrc 文件

解释:

  • reset:清理终端缓存、修复终端显示异常或乱码问题;
  • TERM 环境变量指定终端类型,使 shell 和程序支持颜色、高亮、光标控制等;
  • SHELL 明确指定默认 shell;
  • source .bashrc 加载默认配置,包括别名、颜色方案、命令补全等。

执行完毕后,你将获得一个相当于本地 SSH 登录的终端环境,支持方向键历史、Tab 补全、颜色显示、 Ctrl+C 中断、 vim 编辑、top 查看等功能,可大大提升渗透测试效率和命令操作流畅度。


六、深入底层:终端升级流程原理解析

PTY 工作原理

伪终端(PTY)由 Master 和 Slave 两端组成:

  • Master 端通常由控制终端负责处理 I/O;
  • Slave 端作为真实 shell 的输入输出终端;
  • 操作系统将从 Master 端输入的数据转发到 Slave 端,shell 执行后返回数据再经 Master 端输出。
  • Control 线号(如 SIGINT、SIGTSTP)也会正确从 Master 端传递至 Slave 端 shell。

这种结构模拟真实终端行为,使 shell 与程序获得完整控制信号和输入输出路径。

Ctrl+Z 与 stty raw -echo 背后的机制

  • Ctrl+Z 向当前前台进程发送 SIGTSTP 信号,将 shell 挂起;

  • 恢复前台控制权给终端,然后通过 stty raw -echo 修改终端模式:

    • raw 模式禁用行缓冲和特殊字符解释;
    • -echo 禁止重复显示用户输入;
  • fg 恢复 shell 后,shell 的 I/O 接入的是已经修改过行为的终端,从而支持实用快捷键和控制信号。

终端类型与环境变量配置

  • TERM=xterm-256color 能使 shell 和常用工具(如 ls、vim、less)正确启用颜色、光标控制等;
  • 指定默认 SHELL=/bin/bash 是为了确保 shell 启动行为统一,避免某些系统使用 dash、sh 或 zsh 导致特性不一致;
  • 加载 .bashrc 或 /etc/skel/.bashrc,可以添加别名(如 ll)、补全规则、颜色方案等提升命令行体验。

提示与注意事项

  • 若目标系统中未安装 Python 3 或 Python 2,可尝试其他方式(如 script 或 socat);若也缺少这些工具,可能需借助外部 payload 或自制工具上传;
  • 若 shell 异常卡顿,可尝试先执行 export LANG=C、export LC_ALL=C,避免多字节字符干扰终端;
  • 若终端乱码或不可输入特殊字符,可尝试 reset 或 stty sane 恢复标准模式;
  • 若处于 Windows 平台目标,shell 类型不同,可使用 Windows 原生命令提示符无需升级为 PTY,或采用 rlwrap 进行轻量增强。

七、番外:在 Windows Shell 环境中的优化技巧

在 Windows 平台上,如果你反弹了 cmd.exe 或者 PowerShell,情况与 Linux 有所不同:

  • Windows 命令提示符本身不依赖终端设备(TTY),即使在非交互式会话中,也能工作的相当稳定;

  • PowerShell 默认支持某些补全与历史记录功能,在一定程度上不依赖 readline 库;

  • 故而我们可以使用 rlwrap 为 netcat 等工具添加简单增强,而不必考虑 Linux 环境中复杂的 PTY 稳定步骤

    rlwrap nc -lvnp 4444

    如上命令可以提供历史命令和输入补全功能,显著改善交互体验,无需分配 PTY。

但对于 Linux 命令行,单纯用 rlwrap 增强仍无法运行 vim、less、sudo 等依赖于终端控制信号的工具,因此在需要完整交互时仍需升级环境。


八、最佳实践与建议总结

  1. 拿到初始 shell 后,应尽快确认当前 shell 类型以及可用的终端环境;
  2. 若为非交互式 shell,立即尝试通过 Python、script、socat 分配 PTY;
  3. 获取半交互式 shell 后,运行挂起 + stty raw -echo + fg 等步骤升级为全交互式 shell;
  4. 配置环境变量如 TERM、SHELL,并加载 bash 配置文件,改善交互体验;
  5. 在 Windows shell 中,可使用 rlwrap 进行轻量增强,但限制较多;
  6. 妥善处理乱码、多字节、终端类型不兼容等问题;
  7. 升级后务必测试:方向键补全、Tab 补全、Ctrl+C 中断、vim/less/top 是否可正常运行。

原文 https://blog.csdn.net/2301_79518550/article/details/144730328